aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorOliver Endriss <o.endriss@gmx.de>2007-04-27 11:31:21 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-04-27 14:43:45 -0400
commitee820a648fb333034aa455e8e1479b89798a1281 (patch)
tree2bb8611029075d0ff068394b6aaad9b5ea46f057 /drivers/media
parentdb4836791dc578f0f6e9573468cffeee00fa7ebc (diff)
V4L/DVB (5334): Dvb-ttpci: Infrared remote control refactoring
Infrared remote control support rewritten. Now each device provides its own event device, keymap, protocol, inversion and address setting. EVIOCGKEYCODE and EVIOCSKEYCODE ioctls are supported to read/modify a keymap. Keymaps may be loaded using - input tools (keyb etc.) - av7110_loadkeys (obsolete, for backward compatibility) New command line parameters: - ir_protocol: select infrared protocol: 0 RC5, 1 RCMM (default) - ir_inversion: signal inversion: 0 not inverted (default), 1 inverted - ir_device_mask: bitmask of infrared devices (default: accept all) Those parameters may be set anytime. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/dvb/ttpci/av7110.c13
-rw-r--r--drivers/media/dvb/ttpci/av7110.h28
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c358
3 files changed, 265 insertions, 134 deletions
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 29ed532ba966..3cd85231a0cd 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -219,7 +219,10 @@ static void recover_arm(struct av7110 *av7110)
219 av7110->recover(av7110); 219 av7110->recover(av7110);
220 220
221 restart_feeds(av7110); 221 restart_feeds(av7110);
222 av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); 222
223#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
224 av7110_check_ir_config(av7110, true);
225#endif
223} 226}
224 227
225static void av7110_arm_sync(struct av7110 *av7110) 228static void av7110_arm_sync(struct av7110 *av7110)
@@ -250,6 +253,10 @@ static int arm_thread(void *data)
250 if (!av7110->arm_ready) 253 if (!av7110->arm_ready)
251 continue; 254 continue;
252 255
256#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
257 av7110_check_ir_config(av7110, false);
258#endif
259
253 if (mutex_lock_interruptible(&av7110->dcomlock)) 260 if (mutex_lock_interruptible(&av7110->dcomlock))
254 break; 261 break;
255 newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); 262 newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
@@ -667,8 +674,8 @@ static void gpioirq(unsigned long data)
667 return; 674 return;
668 675
669 case DATA_IRCOMMAND: 676 case DATA_IRCOMMAND:
670 if (av7110->ir_handler) 677 if (av7110->ir.ir_handler)
671 av7110->ir_handler(av7110, 678 av7110->ir.ir_handler(av7110,
672 swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); 679 swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
673 iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); 680 iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
674 break; 681 break;
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index b98bd453cade..115002b0390c 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -5,6 +5,7 @@
5#include <linux/socket.h> 5#include <linux/socket.h>
6#include <linux/netdevice.h> 6#include <linux/netdevice.h>
7#include <linux/i2c.h> 7#include <linux/i2c.h>
8#include <linux/input.h>
8 9
9#include <linux/dvb/video.h> 10#include <linux/dvb/video.h>
10#include <linux/dvb/audio.h> 11#include <linux/dvb/audio.h>
@@ -66,6 +67,27 @@ struct dvb_video_events {
66}; 67};
67 68
68 69
70struct av7110;
71
72/* infrared remote control */
73struct infrared {
74 u16 key_map[256];
75 struct input_dev *input_dev;
76 char input_phys[32];
77 struct timer_list keyup_timer;
78 struct tasklet_struct ir_tasklet;
79 void (*ir_handler)(struct av7110 *av7110, u32 ircom);
80 u32 ir_command;
81 u32 ir_config;
82 u32 device_mask;
83 u8 protocol;
84 u8 inversion;
85 u16 last_key;
86 u16 last_toggle;
87 u8 delay_timer_finished;
88};
89
90
69/* place to store all the necessary device information */ 91/* place to store all the necessary device information */
70struct av7110 { 92struct av7110 {
71 93
@@ -227,10 +249,7 @@ struct av7110 {
227 u16 wssMode; 249 u16 wssMode;
228 u16 wssData; 250 u16 wssData;
229 251
230 u32 ir_config; 252 struct infrared ir;
231 u32 ir_command;
232 void (*ir_handler)(struct av7110 *av7110, u32 ircom);
233 struct tasklet_struct ir_tasklet;
234 253
235 /* firmware stuff */ 254 /* firmware stuff */
236 unsigned char *bin_fw; 255 unsigned char *bin_fw;
@@ -268,6 +287,7 @@ struct av7110 {
268extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, 287extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
269 u16 subpid, u16 pcrpid); 288 u16 subpid, u16 pcrpid);
270 289
290extern int av7110_check_ir_config(struct av7110 *av7110, int force);
271extern int av7110_ir_init(struct av7110 *av7110); 291extern int av7110_ir_init(struct av7110 *av7110);
272extern void av7110_ir_exit(struct av7110 *av7110); 292extern void av7110_ir_exit(struct av7110 *av7110);
273 293
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index f59465bb0af3..921ff199ed19 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)
46
47
48/* Note: enable ir debugging by or'ing debug with 16 */
49
50static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
51module_param_array(ir_protocol, int, NULL, 0644);
52MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
53
54static int ir_inversion[AV_CNT];
55module_param_array(ir_inversion, int, NULL, 0644);
56MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted");
57
58static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
59module_param_array(ir_device_mask, uint, NULL, 0644);
60MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)");
16 61
17static int av_cnt;
18static struct av7110 *av_list[4];
19static struct input_dev *input_dev;
20static char input_phys[32];
21 62
22static u8 delay_timer_finished; 63static int av_cnt;
64static struct av7110 *av_list[AV_CNT];
23 65
24static u16 key_map [256] = { 66static 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,187 @@ static u16 key_map [256] = {
45}; 87};
46 88
47 89
48static void av7110_emit_keyup(unsigned long data) 90/* key-up timer */
91static 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
58static struct timer_list keyup_timer = { .function = av7110_emit_keyup }; 103/* tasklet */
59
60
61static void av7110_emit_key(unsigned long parm) 104static 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 keycode = ir->key_map[data];
98 142
99 dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n", 143 dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
100 ircom, addr, data, keycode); 144 __FUNCTION__, ircom, addr, data, keycode);
101 145
102 /* check device address (if selected) */ 146 /* check device address */
103 if (ir_config & 0x4000) 147 if (!(ir->device_mask & (1 << addr)))
104 if (addr != ((ir_config >> 16) & 0xff)) 148 return;
105 return;
106 149
107 if (!keycode) { 150 if (!keycode) {
108 printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data); 151 printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
152 __FUNCTION__, ircom, addr, data);
109 return; 153 return;
110 } 154 }
111 155
112 if ((ir_config & 0x0003) == 1) 156 if (timer_pending(&ir->keyup_timer)) {
113 new_toggle = 0; /* RCMM */ 157 del_timer(&ir->keyup_timer);
114 else 158 if (ir->last_key != keycode || toggle != ir->last_toggle) {
115 new_toggle = (ircom & 0x800); /* RC5, extended RC5 */ 159 ir->delay_timer_finished = 0;
116 160 input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
117 if (timer_pending(&keyup_timer)) { 161 input_event(ir->input_dev, EV_KEY, keycode, 1);
118 del_timer(&keyup_timer); 162 input_sync(ir->input_dev);
119 if (keyup_timer.data != keycode || new_toggle != old_toggle) { 163 } else if (ir->delay_timer_finished) {
120 delay_timer_finished = 0; 164 input_event(ir->input_dev, EV_KEY, keycode, 2);
121 input_event(input_dev, EV_KEY, keyup_timer.data, 0); 165 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 } 166 }
128 } else { 167 } else {
129 delay_timer_finished = 0; 168 ir->delay_timer_finished = 0;
130 input_event(input_dev, EV_KEY, keycode, 1); 169 input_event(ir->input_dev, EV_KEY, keycode, 1);
131 input_sync(input_dev); 170 input_sync(ir->input_dev);
132 } 171 }
133 172
134 keyup_timer.expires = jiffies + UP_TIMEOUT; 173 ir->last_key = keycode;
135 keyup_timer.data = keycode; 174 ir->last_toggle = toggle;
136 175
137 add_timer(&keyup_timer); 176 ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
177 add_timer(&ir->keyup_timer);
138 178
139 old_toggle = new_toggle;
140} 179}
141 180
142static void input_register_keys(void) 181
182/* register with input layer */
183static void input_register_keys(struct infrared *ir)
143{ 184{
144 int i; 185 int i;
145 186
146 memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); 187 set_bit(EV_KEY, ir->input_dev->evbit);
188 set_bit(EV_REP, ir->input_dev->evbit);
147 189
148 for (i = 0; i < ARRAY_SIZE(key_map); i++) { 190 memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
149 if (key_map[i] > KEY_MAX) 191
150 key_map[i] = 0; 192 for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
151 else if (key_map[i] > KEY_RESERVED) 193 if (ir->key_map[i] > KEY_MAX)
152 set_bit(key_map[i], input_dev->keybit); 194 ir->key_map[i] = 0;
195 else if (ir->key_map[i] > KEY_RESERVED)
196 set_bit(ir->key_map[i], ir->input_dev->keybit);
153 } 197 }
198
199 ir->input_dev->keycode = ir->key_map;
200 ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
201 ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
154} 202}
155 203
156 204
157static void input_repeat_key(unsigned long data) 205/* called by the input driver after rep[REP_DELAY] ms */
206static void input_repeat_key(unsigned long parm)
158{ 207{
159 /* called by the input driver after rep[REP_DELAY] ms */ 208 struct infrared *ir = (struct infrared *) parm;
160 delay_timer_finished = 1; 209
210 ir->delay_timer_finished = 1;
161} 211}
162 212
163 213
164static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) 214/* check for configuration changes */
215int av7110_check_ir_config(struct av7110 *av7110, int force)
165{ 216{
166 int ret = 0; 217 int i;
218 int modified = force;
219 int ret = -ENODEV;
167 220
168 dprintk(4, "%p\n", av7110); 221 for (i = 0; i < av_cnt; i++)
169 if (av7110) { 222 if (av7110 == av_list[i])
170 ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); 223 break;
171 av7110->ir_config = ir_config; 224
225 if (i < av_cnt && av7110) {
226 if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
227 av7110->ir.inversion != ir_inversion[i])
228 modified = true;
229
230 if (modified) {
231 /* protocol */
232 if (ir_protocol[i]) {
233 ir_protocol[i] = 1;
234 av7110->ir.protocol = IR_RCMM;
235 av7110->ir.ir_config = 0x0001;
236 } else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
237 av7110->ir.protocol = IR_RC5_EXT;
238 av7110->ir.ir_config = 0x0002;
239 } else {
240 av7110->ir.protocol = IR_RC5;
241 av7110->ir.ir_config = 0x0000;
242 }
243 /* inversion */
244 if (ir_inversion[i]) {
245 ir_inversion[i] = 1;
246 av7110->ir.ir_config |= 0x8000;
247 }
248 av7110->ir.inversion = ir_inversion[i];
249 /* update ARM */
250 ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
251 av7110->ir.ir_config);
252 } else
253 ret = 0;
254
255 /* address */
256 if (av7110->ir.device_mask != ir_device_mask[i])
257 av7110->ir.device_mask = ir_device_mask[i];
172 } 258 }
259
173 return ret; 260 return ret;
174} 261}
175 262
176 263
264/* /proc/av7110_ir interface */
177static int av7110_ir_write_proc(struct file *file, const char __user *buffer, 265static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
178 unsigned long count, void *data) 266 unsigned long count, void *data)
179{ 267{
180 char *page; 268 char *page;
181 int size = 4 + 256 * sizeof(u16);
182 u32 ir_config; 269 u32 ir_config;
270 int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
183 int i; 271 int i;
184 272
185 if (count < size) 273 if (count < size)
@@ -194,71 +282,86 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
194 return -EFAULT; 282 return -EFAULT;
195 } 283 }
196 284
197 memcpy(&ir_config, page, 4); 285 memcpy(&ir_config, page, sizeof ir_config);
198 memcpy(&key_map, page + 4, 256 * sizeof(u16)); 286
287 for (i = 0; i < av_cnt; i++) {
288 /* keymap */
289 memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
290 sizeof(av_list[i]->ir.key_map));
291 /* protocol, inversion, address */
292 ir_protocol[i] = ir_config & 0x0001;
293 ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
294 if (ir_config & 0x4000)
295 ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
296 else
297 ir_device_mask[i] = IR_ALL;
298 /* update configuration */
299 av7110_check_ir_config(av_list[i], false);
300 input_register_keys(&av_list[i]->ir);
301 }
199 vfree(page); 302 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; 303 return count;
206} 304}
207 305
208 306
307/* interrupt handler */
209static void ir_handler(struct av7110 *av7110, u32 ircom) 308static void ir_handler(struct av7110 *av7110, u32 ircom)
210{ 309{
211 dprintk(4, "ircommand = %08x\n", ircom); 310 dprintk(4, "ir command = %08x\n", ircom);
212 av7110->ir_command = ircom; 311 av7110->ir.ir_command = ircom;
213 tasklet_schedule(&av7110->ir_tasklet); 312 tasklet_schedule(&av7110->ir.ir_tasklet);
214} 313}
215 314
216 315
217int __devinit av7110_ir_init(struct av7110 *av7110) 316int __devinit av7110_ir_init(struct av7110 *av7110)
218{ 317{
318 struct input_dev *input_dev;
219 static struct proc_dir_entry *e; 319 static struct proc_dir_entry *e;
220 int err; 320 int err;
221 321
222 if (av_cnt >= ARRAY_SIZE(av_list)) 322 if (av_cnt >= ARRAY_SIZE(av_list))
223 return -ENOSPC; 323 return -ENOSPC;
224 324
225 av7110_setup_irc_config(av7110, 0x0001); 325 av7110_check_ir_config(av7110, true);
226 av_list[av_cnt++] = av7110; 326 av_list[av_cnt++] = av7110;
227 327
228 if (av_cnt == 1) { 328 init_timer(&av7110->ir.keyup_timer);
229 init_timer(&keyup_timer); 329 av7110->ir.keyup_timer.function = av7110_emit_keyup;
230 keyup_timer.data = 0; 330 av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir;
231 331
232 input_dev = input_allocate_device(); 332 input_dev = input_allocate_device();
233 if (!input_dev) 333 if (!input_dev)
234 return -ENOMEM; 334 return -ENOMEM;
235 335
236 snprintf(input_phys, sizeof(input_phys), 336 av7110->ir.input_dev = input_dev;
237 "pci-%s/ir0", pci_name(av7110->dev->pci)); 337 snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
238 338 "pci-%s/ir0", pci_name(av7110->dev->pci));
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 339
340 input_dev->name = "DVB on-card IR receiver";
341
342 input_dev->phys = av7110->ir.input_phys;
343 input_dev->id.bustype = BUS_PCI;
344 input_dev->id.version = 2;
345 if (av7110->dev->pci->subsystem_vendor) {
346 input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
347 input_dev->id.product = av7110->dev->pci->subsystem_device;
348 } else {
349 input_dev->id.vendor = av7110->dev->pci->vendor;
350 input_dev->id.product = av7110->dev->pci->device;
351 }
352 input_dev->cdev.dev = &av7110->dev->pci->dev;
353 /* initial keymap */
354 memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
355 input_register_keys(&av7110->ir);
356 err = input_register_device(input_dev);
357 if (err) {
358 input_free_device(input_dev);
359 return err;
360 }
361 input_dev->timer.function = input_repeat_key;
362 input_dev->timer.data = (unsigned long) &av7110->ir;
363
364 if (av_cnt == 1) {
262 e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); 365 e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
263 if (e) { 366 if (e) {
264 e->write_proc = av7110_ir_write_proc; 367 e->write_proc = av7110_ir_write_proc;
@@ -266,8 +369,8 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
266 } 369 }
267 } 370 }
268 371
269 tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110); 372 tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
270 av7110->ir_handler = ir_handler; 373 av7110->ir.ir_handler = ir_handler;
271 374
272 return 0; 375 return 0;
273} 376}
@@ -280,8 +383,10 @@ void __devexit av7110_ir_exit(struct av7110 *av7110)
280 if (av_cnt == 0) 383 if (av_cnt == 0)
281 return; 384 return;
282 385
283 av7110->ir_handler = NULL; 386 del_timer_sync(&av7110->ir.keyup_timer);
284 tasklet_kill(&av7110->ir_tasklet); 387 av7110->ir.ir_handler = NULL;
388 tasklet_kill(&av7110->ir.ir_tasklet);
389
285 for (i = 0; i < av_cnt; i++) 390 for (i = 0; i < av_cnt; i++)
286 if (av_list[i] == av7110) { 391 if (av_list[i] == av7110) {
287 av_list[i] = av_list[av_cnt-1]; 392 av_list[i] = av_list[av_cnt-1];
@@ -289,14 +394,13 @@ void __devexit av7110_ir_exit(struct av7110 *av7110)
289 break; 394 break;
290 } 395 }
291 396
292 if (av_cnt == 1) { 397 if (av_cnt == 1)
293 del_timer_sync(&keyup_timer);
294 remove_proc_entry("av7110_ir", NULL); 398 remove_proc_entry("av7110_ir", NULL);
295 input_unregister_device(input_dev); 399
296 } 400 input_unregister_device(av7110->ir.input_dev);
297 401
298 av_cnt--; 402 av_cnt--;
299} 403}
300 404
301//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>"); 405//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
302//MODULE_LICENSE("GPL"); 406//MODULE_LICENSE("GPL");