diff options
Diffstat (limited to 'drivers/media/dvb/ttpci/av7110_ir.c')
-rw-r--r-- | drivers/media/dvb/ttpci/av7110_ir.c | 365 |
1 files changed, 238 insertions, 127 deletions
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index f59465bb0af3..a97f166bb523 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c | |||
@@ -1,8 +1,31 @@ | |||
1 | /* | ||
2 | * Driver for the remote control of SAA7146 based AV7110 cards | ||
3 | * | ||
4 | * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de> | ||
5 | * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2 | ||
10 | * of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
1 | #include <linux/types.h> | 25 | #include <linux/types.h> |
2 | #include <linux/init.h> | 26 | #include <linux/init.h> |
3 | #include <linux/module.h> | 27 | #include <linux/module.h> |
4 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
5 | #include <linux/input.h> | ||
6 | #include <linux/proc_fs.h> | 29 | #include <linux/proc_fs.h> |
7 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
8 | #include <asm/bitops.h> | 31 | #include <asm/bitops.h> |
@@ -10,18 +33,37 @@ | |||
10 | #include "av7110.h" | 33 | #include "av7110.h" |
11 | #include "av7110_hw.h" | 34 | #include "av7110_hw.h" |
12 | 35 | ||
13 | #define UP_TIMEOUT (HZ*7/25) | ||
14 | 36 | ||
15 | /* enable ir debugging by or'ing debug with 16 */ | 37 | #define AV_CNT 4 |
38 | |||
39 | #define IR_RC5 0 | ||
40 | #define IR_RCMM 1 | ||
41 | #define IR_RC5_EXT 2 /* internal only */ | ||
42 | |||
43 | #define IR_ALL 0xffffffff | ||
44 | |||
45 | #define UP_TIMEOUT (HZ*7/25) | ||
16 | 46 | ||
17 | static int av_cnt; | ||
18 | static struct av7110 *av_list[4]; | ||
19 | static struct input_dev *input_dev; | ||
20 | static char input_phys[32]; | ||
21 | 47 | ||
22 | static u8 delay_timer_finished; | 48 | /* Note: enable ir debugging by or'ing debug with 16 */ |
49 | |||
50 | static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; | ||
51 | module_param_array(ir_protocol, int, NULL, 0644); | ||
52 | MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); | ||
53 | |||
54 | static int ir_inversion[AV_CNT]; | ||
55 | module_param_array(ir_inversion, int, NULL, 0644); | ||
56 | MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); | ||
57 | |||
58 | static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; | ||
59 | module_param_array(ir_device_mask, uint, NULL, 0644); | ||
60 | MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); | ||
61 | |||
62 | |||
63 | static int av_cnt; | ||
64 | static struct av7110 *av_list[AV_CNT]; | ||
23 | 65 | ||
24 | static u16 key_map [256] = { | 66 | static u16 default_key_map [256] = { |
25 | KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, | 67 | KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, |
26 | KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, | 68 | KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, |
27 | KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 69 | KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
@@ -45,141 +87,194 @@ static u16 key_map [256] = { | |||
45 | }; | 87 | }; |
46 | 88 | ||
47 | 89 | ||
48 | static void av7110_emit_keyup(unsigned long data) | 90 | /* key-up timer */ |
91 | static void av7110_emit_keyup(unsigned long parm) | ||
49 | { | 92 | { |
50 | if (!data || !test_bit(data, input_dev->key)) | 93 | struct infrared *ir = (struct infrared *) parm; |
94 | |||
95 | if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) | ||
51 | return; | 96 | return; |
52 | 97 | ||
53 | input_report_key(input_dev, data, 0); | 98 | input_report_key(ir->input_dev, ir->last_key, 0); |
54 | input_sync(input_dev); | 99 | input_sync(ir->input_dev); |
55 | } | 100 | } |
56 | 101 | ||
57 | 102 | ||
58 | static struct timer_list keyup_timer = { .function = av7110_emit_keyup }; | 103 | /* tasklet */ |
59 | |||
60 | |||
61 | static void av7110_emit_key(unsigned long parm) | 104 | static void av7110_emit_key(unsigned long parm) |
62 | { | 105 | { |
63 | struct av7110 *av7110 = (struct av7110 *) parm; | 106 | struct infrared *ir = (struct infrared *) parm; |
64 | u32 ir_config = av7110->ir_config; | 107 | u32 ircom = ir->ir_command; |
65 | u32 ircom = av7110->ir_command; | ||
66 | u8 data; | 108 | u8 data; |
67 | u8 addr; | 109 | u8 addr; |
68 | static u16 old_toggle = 0; | 110 | u16 toggle; |
69 | u16 new_toggle; | ||
70 | u16 keycode; | 111 | u16 keycode; |
71 | 112 | ||
72 | /* extract device address and data */ | 113 | /* extract device address and data */ |
73 | switch (ir_config & 0x0003) { | 114 | switch (ir->protocol) { |
74 | case 0: /* RC5: 5 bits device address, 6 bits data */ | 115 | case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ |
75 | data = ircom & 0x3f; | 116 | data = ircom & 0x3f; |
76 | addr = (ircom >> 6) & 0x1f; | 117 | addr = (ircom >> 6) & 0x1f; |
118 | toggle = ircom & 0x0800; | ||
77 | break; | 119 | break; |
78 | 120 | ||
79 | case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */ | 121 | case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ |
80 | data = ircom & 0xff; | 122 | data = ircom & 0xff; |
81 | addr = (ircom >> 8) & 0xff; | 123 | addr = (ircom >> 8) & 0x1f; |
124 | toggle = ircom & 0x8000; | ||
82 | break; | 125 | break; |
83 | 126 | ||
84 | case 2: /* extended RC5: 5 bits device address, 7 bits data */ | 127 | case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ |
85 | data = ircom & 0x3f; | 128 | data = ircom & 0x3f; |
86 | addr = (ircom >> 6) & 0x1f; | 129 | addr = (ircom >> 6) & 0x1f; |
87 | /* invert 7th data bit for backward compatibility with RC5 keymaps */ | 130 | /* invert 7th data bit for backward compatibility with RC5 keymaps */ |
88 | if (!(ircom & 0x1000)) | 131 | if (!(ircom & 0x1000)) |
89 | data |= 0x40; | 132 | data |= 0x40; |
133 | toggle = ircom & 0x0800; | ||
90 | break; | 134 | break; |
91 | 135 | ||
92 | default: | 136 | default: |
93 | printk("invalid ir_config %x\n", ir_config); | 137 | printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol); |
94 | return; | 138 | return; |
95 | } | 139 | } |
96 | 140 | ||
97 | keycode = key_map[data]; | 141 | input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); |
142 | input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); | ||
98 | 143 | ||
99 | dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n", | 144 | keycode = ir->key_map[data]; |
100 | ircom, addr, data, keycode); | ||
101 | 145 | ||
102 | /* check device address (if selected) */ | 146 | dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", |
103 | if (ir_config & 0x4000) | 147 | __FUNCTION__, ircom, addr, data, keycode); |
104 | if (addr != ((ir_config >> 16) & 0xff)) | 148 | |
105 | return; | 149 | /* check device address */ |
150 | if (!(ir->device_mask & (1 << addr))) | ||
151 | return; | ||
106 | 152 | ||
107 | if (!keycode) { | 153 | if (!keycode) { |
108 | printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data); | 154 | printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", |
155 | __FUNCTION__, ircom, addr, data); | ||
109 | return; | 156 | return; |
110 | } | 157 | } |
111 | 158 | ||
112 | if ((ir_config & 0x0003) == 1) | 159 | if (timer_pending(&ir->keyup_timer)) { |
113 | new_toggle = 0; /* RCMM */ | 160 | del_timer(&ir->keyup_timer); |
114 | else | 161 | if (ir->last_key != keycode || toggle != ir->last_toggle) { |
115 | new_toggle = (ircom & 0x800); /* RC5, extended RC5 */ | 162 | ir->delay_timer_finished = 0; |
116 | 163 | input_event(ir->input_dev, EV_KEY, ir->last_key, 0); | |
117 | if (timer_pending(&keyup_timer)) { | 164 | input_event(ir->input_dev, EV_KEY, keycode, 1); |
118 | del_timer(&keyup_timer); | 165 | input_sync(ir->input_dev); |
119 | if (keyup_timer.data != keycode || new_toggle != old_toggle) { | 166 | } else if (ir->delay_timer_finished) { |
120 | delay_timer_finished = 0; | 167 | input_event(ir->input_dev, EV_KEY, keycode, 2); |
121 | input_event(input_dev, EV_KEY, keyup_timer.data, 0); | 168 | input_sync(ir->input_dev); |
122 | input_event(input_dev, EV_KEY, keycode, 1); | ||
123 | input_sync(input_dev); | ||
124 | } else if (delay_timer_finished) { | ||
125 | input_event(input_dev, EV_KEY, keycode, 2); | ||
126 | input_sync(input_dev); | ||
127 | } | 169 | } |
128 | } else { | 170 | } else { |
129 | delay_timer_finished = 0; | 171 | ir->delay_timer_finished = 0; |
130 | input_event(input_dev, EV_KEY, keycode, 1); | 172 | input_event(ir->input_dev, EV_KEY, keycode, 1); |
131 | input_sync(input_dev); | 173 | input_sync(ir->input_dev); |
132 | } | 174 | } |
133 | 175 | ||
134 | keyup_timer.expires = jiffies + UP_TIMEOUT; | 176 | ir->last_key = keycode; |
135 | keyup_timer.data = keycode; | 177 | ir->last_toggle = toggle; |
136 | 178 | ||
137 | add_timer(&keyup_timer); | 179 | ir->keyup_timer.expires = jiffies + UP_TIMEOUT; |
180 | add_timer(&ir->keyup_timer); | ||
138 | 181 | ||
139 | old_toggle = new_toggle; | ||
140 | } | 182 | } |
141 | 183 | ||
142 | static void input_register_keys(void) | 184 | |
185 | /* register with input layer */ | ||
186 | static void input_register_keys(struct infrared *ir) | ||
143 | { | 187 | { |
144 | int i; | 188 | int i; |
145 | 189 | ||
146 | memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); | 190 | set_bit(EV_KEY, ir->input_dev->evbit); |
191 | set_bit(EV_REP, ir->input_dev->evbit); | ||
192 | set_bit(EV_MSC, ir->input_dev->evbit); | ||
147 | 193 | ||
148 | for (i = 0; i < ARRAY_SIZE(key_map); i++) { | 194 | set_bit(MSC_RAW, ir->input_dev->mscbit); |
149 | if (key_map[i] > KEY_MAX) | 195 | set_bit(MSC_SCAN, ir->input_dev->mscbit); |
150 | key_map[i] = 0; | 196 | |
151 | else if (key_map[i] > KEY_RESERVED) | 197 | memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); |
152 | set_bit(key_map[i], input_dev->keybit); | 198 | |
199 | for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { | ||
200 | if (ir->key_map[i] > KEY_MAX) | ||
201 | ir->key_map[i] = 0; | ||
202 | else if (ir->key_map[i] > KEY_RESERVED) | ||
203 | set_bit(ir->key_map[i], ir->input_dev->keybit); | ||
153 | } | 204 | } |
205 | |||
206 | ir->input_dev->keycode = ir->key_map; | ||
207 | ir->input_dev->keycodesize = sizeof(ir->key_map[0]); | ||
208 | ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); | ||
154 | } | 209 | } |
155 | 210 | ||
156 | 211 | ||
157 | static void input_repeat_key(unsigned long data) | 212 | /* called by the input driver after rep[REP_DELAY] ms */ |
213 | static void input_repeat_key(unsigned long parm) | ||
158 | { | 214 | { |
159 | /* called by the input driver after rep[REP_DELAY] ms */ | 215 | struct infrared *ir = (struct infrared *) parm; |
160 | delay_timer_finished = 1; | 216 | |
217 | ir->delay_timer_finished = 1; | ||
161 | } | 218 | } |
162 | 219 | ||
163 | 220 | ||
164 | static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) | 221 | /* check for configuration changes */ |
222 | int av7110_check_ir_config(struct av7110 *av7110, int force) | ||
165 | { | 223 | { |
166 | int ret = 0; | 224 | int i; |
225 | int modified = force; | ||
226 | int ret = -ENODEV; | ||
167 | 227 | ||
168 | dprintk(4, "%p\n", av7110); | 228 | for (i = 0; i < av_cnt; i++) |
169 | if (av7110) { | 229 | if (av7110 == av_list[i]) |
170 | ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); | 230 | break; |
171 | av7110->ir_config = ir_config; | 231 | |
232 | if (i < av_cnt && av7110) { | ||
233 | if ((av7110->ir.protocol & 1) != ir_protocol[i] || | ||
234 | av7110->ir.inversion != ir_inversion[i]) | ||
235 | modified = true; | ||
236 | |||
237 | if (modified) { | ||
238 | /* protocol */ | ||
239 | if (ir_protocol[i]) { | ||
240 | ir_protocol[i] = 1; | ||
241 | av7110->ir.protocol = IR_RCMM; | ||
242 | av7110->ir.ir_config = 0x0001; | ||
243 | } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { | ||
244 | av7110->ir.protocol = IR_RC5_EXT; | ||
245 | av7110->ir.ir_config = 0x0002; | ||
246 | } else { | ||
247 | av7110->ir.protocol = IR_RC5; | ||
248 | av7110->ir.ir_config = 0x0000; | ||
249 | } | ||
250 | /* inversion */ | ||
251 | if (ir_inversion[i]) { | ||
252 | ir_inversion[i] = 1; | ||
253 | av7110->ir.ir_config |= 0x8000; | ||
254 | } | ||
255 | av7110->ir.inversion = ir_inversion[i]; | ||
256 | /* update ARM */ | ||
257 | ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, | ||
258 | av7110->ir.ir_config); | ||
259 | } else | ||
260 | ret = 0; | ||
261 | |||
262 | /* address */ | ||
263 | if (av7110->ir.device_mask != ir_device_mask[i]) | ||
264 | av7110->ir.device_mask = ir_device_mask[i]; | ||
172 | } | 265 | } |
266 | |||
173 | return ret; | 267 | return ret; |
174 | } | 268 | } |
175 | 269 | ||
176 | 270 | ||
271 | /* /proc/av7110_ir interface */ | ||
177 | static int av7110_ir_write_proc(struct file *file, const char __user *buffer, | 272 | static int av7110_ir_write_proc(struct file *file, const char __user *buffer, |
178 | unsigned long count, void *data) | 273 | unsigned long count, void *data) |
179 | { | 274 | { |
180 | char *page; | 275 | char *page; |
181 | int size = 4 + 256 * sizeof(u16); | ||
182 | u32 ir_config; | 276 | u32 ir_config; |
277 | int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; | ||
183 | int i; | 278 | int i; |
184 | 279 | ||
185 | if (count < size) | 280 | if (count < size) |
@@ -194,71 +289,86 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, | |||
194 | return -EFAULT; | 289 | return -EFAULT; |
195 | } | 290 | } |
196 | 291 | ||
197 | memcpy(&ir_config, page, 4); | 292 | memcpy(&ir_config, page, sizeof ir_config); |
198 | memcpy(&key_map, page + 4, 256 * sizeof(u16)); | 293 | |
294 | for (i = 0; i < av_cnt; i++) { | ||
295 | /* keymap */ | ||
296 | memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, | ||
297 | sizeof(av_list[i]->ir.key_map)); | ||
298 | /* protocol, inversion, address */ | ||
299 | ir_protocol[i] = ir_config & 0x0001; | ||
300 | ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; | ||
301 | if (ir_config & 0x4000) | ||
302 | ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); | ||
303 | else | ||
304 | ir_device_mask[i] = IR_ALL; | ||
305 | /* update configuration */ | ||
306 | av7110_check_ir_config(av_list[i], false); | ||
307 | input_register_keys(&av_list[i]->ir); | ||
308 | } | ||
199 | vfree(page); | 309 | vfree(page); |
200 | if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001)) | ||
201 | ir_config |= 0x0002; /* enable extended RC5 */ | ||
202 | for (i = 0; i < av_cnt; i++) | ||
203 | av7110_setup_irc_config(av_list[i], ir_config); | ||
204 | input_register_keys(); | ||
205 | return count; | 310 | return count; |
206 | } | 311 | } |
207 | 312 | ||
208 | 313 | ||
314 | /* interrupt handler */ | ||
209 | static void ir_handler(struct av7110 *av7110, u32 ircom) | 315 | static void ir_handler(struct av7110 *av7110, u32 ircom) |
210 | { | 316 | { |
211 | dprintk(4, "ircommand = %08x\n", ircom); | 317 | dprintk(4, "ir command = %08x\n", ircom); |
212 | av7110->ir_command = ircom; | 318 | av7110->ir.ir_command = ircom; |
213 | tasklet_schedule(&av7110->ir_tasklet); | 319 | tasklet_schedule(&av7110->ir.ir_tasklet); |
214 | } | 320 | } |
215 | 321 | ||
216 | 322 | ||
217 | int __devinit av7110_ir_init(struct av7110 *av7110) | 323 | int __devinit av7110_ir_init(struct av7110 *av7110) |
218 | { | 324 | { |
325 | struct input_dev *input_dev; | ||
219 | static struct proc_dir_entry *e; | 326 | static struct proc_dir_entry *e; |
220 | int err; | 327 | int err; |
221 | 328 | ||
222 | if (av_cnt >= ARRAY_SIZE(av_list)) | 329 | if (av_cnt >= ARRAY_SIZE(av_list)) |
223 | return -ENOSPC; | 330 | return -ENOSPC; |
224 | 331 | ||
225 | av7110_setup_irc_config(av7110, 0x0001); | ||
226 | av_list[av_cnt++] = av7110; | 332 | av_list[av_cnt++] = av7110; |
333 | av7110_check_ir_config(av7110, true); | ||
227 | 334 | ||
228 | if (av_cnt == 1) { | 335 | init_timer(&av7110->ir.keyup_timer); |
229 | init_timer(&keyup_timer); | 336 | av7110->ir.keyup_timer.function = av7110_emit_keyup; |
230 | keyup_timer.data = 0; | 337 | av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; |
231 | 338 | ||
232 | input_dev = input_allocate_device(); | 339 | input_dev = input_allocate_device(); |
233 | if (!input_dev) | 340 | if (!input_dev) |
234 | return -ENOMEM; | 341 | return -ENOMEM; |
235 | |||
236 | snprintf(input_phys, sizeof(input_phys), | ||
237 | "pci-%s/ir0", pci_name(av7110->dev->pci)); | ||
238 | |||
239 | input_dev->name = "DVB on-card IR receiver"; | ||
240 | |||
241 | input_dev->phys = input_phys; | ||
242 | input_dev->id.bustype = BUS_PCI; | ||
243 | input_dev->id.version = 1; | ||
244 | if (av7110->dev->pci->subsystem_vendor) { | ||
245 | input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; | ||
246 | input_dev->id.product = av7110->dev->pci->subsystem_device; | ||
247 | } else { | ||
248 | input_dev->id.vendor = av7110->dev->pci->vendor; | ||
249 | input_dev->id.product = av7110->dev->pci->device; | ||
250 | } | ||
251 | input_dev->cdev.dev = &av7110->dev->pci->dev; | ||
252 | set_bit(EV_KEY, input_dev->evbit); | ||
253 | set_bit(EV_REP, input_dev->evbit); | ||
254 | input_register_keys(); | ||
255 | err = input_register_device(input_dev); | ||
256 | if (err) { | ||
257 | input_free_device(input_dev); | ||
258 | return err; | ||
259 | } | ||
260 | input_dev->timer.function = input_repeat_key; | ||
261 | 342 | ||
343 | av7110->ir.input_dev = input_dev; | ||
344 | snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), | ||
345 | "pci-%s/ir0", pci_name(av7110->dev->pci)); | ||
346 | |||
347 | input_dev->name = "DVB on-card IR receiver"; | ||
348 | |||
349 | input_dev->phys = av7110->ir.input_phys; | ||
350 | input_dev->id.bustype = BUS_PCI; | ||
351 | input_dev->id.version = 2; | ||
352 | if (av7110->dev->pci->subsystem_vendor) { | ||
353 | input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; | ||
354 | input_dev->id.product = av7110->dev->pci->subsystem_device; | ||
355 | } else { | ||
356 | input_dev->id.vendor = av7110->dev->pci->vendor; | ||
357 | input_dev->id.product = av7110->dev->pci->device; | ||
358 | } | ||
359 | input_dev->cdev.dev = &av7110->dev->pci->dev; | ||
360 | /* initial keymap */ | ||
361 | memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); | ||
362 | input_register_keys(&av7110->ir); | ||
363 | err = input_register_device(input_dev); | ||
364 | if (err) { | ||
365 | input_free_device(input_dev); | ||
366 | return err; | ||
367 | } | ||
368 | input_dev->timer.function = input_repeat_key; | ||
369 | input_dev->timer.data = (unsigned long) &av7110->ir; | ||
370 | |||
371 | if (av_cnt == 1) { | ||
262 | e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); | 372 | e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); |
263 | if (e) { | 373 | if (e) { |
264 | e->write_proc = av7110_ir_write_proc; | 374 | e->write_proc = av7110_ir_write_proc; |
@@ -266,8 +376,8 @@ int __devinit av7110_ir_init(struct av7110 *av7110) | |||
266 | } | 376 | } |
267 | } | 377 | } |
268 | 378 | ||
269 | tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110); | 379 | tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); |
270 | av7110->ir_handler = ir_handler; | 380 | av7110->ir.ir_handler = ir_handler; |
271 | 381 | ||
272 | return 0; | 382 | return 0; |
273 | } | 383 | } |
@@ -280,8 +390,10 @@ void __devexit av7110_ir_exit(struct av7110 *av7110) | |||
280 | if (av_cnt == 0) | 390 | if (av_cnt == 0) |
281 | return; | 391 | return; |
282 | 392 | ||
283 | av7110->ir_handler = NULL; | 393 | del_timer_sync(&av7110->ir.keyup_timer); |
284 | tasklet_kill(&av7110->ir_tasklet); | 394 | av7110->ir.ir_handler = NULL; |
395 | tasklet_kill(&av7110->ir.ir_tasklet); | ||
396 | |||
285 | for (i = 0; i < av_cnt; i++) | 397 | for (i = 0; i < av_cnt; i++) |
286 | if (av_list[i] == av7110) { | 398 | if (av_list[i] == av7110) { |
287 | av_list[i] = av_list[av_cnt-1]; | 399 | av_list[i] = av_list[av_cnt-1]; |
@@ -289,14 +401,13 @@ void __devexit av7110_ir_exit(struct av7110 *av7110) | |||
289 | break; | 401 | break; |
290 | } | 402 | } |
291 | 403 | ||
292 | if (av_cnt == 1) { | 404 | if (av_cnt == 1) |
293 | del_timer_sync(&keyup_timer); | ||
294 | remove_proc_entry("av7110_ir", NULL); | 405 | remove_proc_entry("av7110_ir", NULL); |
295 | input_unregister_device(input_dev); | 406 | |
296 | } | 407 | input_unregister_device(av7110->ir.input_dev); |
297 | 408 | ||
298 | av_cnt--; | 409 | av_cnt--; |
299 | } | 410 | } |
300 | 411 | ||
301 | //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>"); | 412 | //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>"); |
302 | //MODULE_LICENSE("GPL"); | 413 | //MODULE_LICENSE("GPL"); |