diff options
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r-- | drivers/media/dvb/ttpci/av7110.c | 13 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/av7110.h | 28 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/av7110_ir.c | 358 |
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 | ||
225 | static void av7110_arm_sync(struct av7110 *av7110) | 228 | static 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 | ||
70 | struct av7110; | ||
71 | |||
72 | /* infrared remote control */ | ||
73 | struct 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 */ |
70 | struct av7110 { | 92 | struct 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 { | |||
268 | extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, | 287 | extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, |
269 | u16 subpid, u16 pcrpid); | 288 | u16 subpid, u16 pcrpid); |
270 | 289 | ||
290 | extern int av7110_check_ir_config(struct av7110 *av7110, int force); | ||
271 | extern int av7110_ir_init(struct av7110 *av7110); | 291 | extern int av7110_ir_init(struct av7110 *av7110); |
272 | extern void av7110_ir_exit(struct av7110 *av7110); | 292 | extern 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 | |||
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)"); | ||
16 | 61 | ||
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 | 62 | ||
22 | static u8 delay_timer_finished; | 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,187 @@ 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 | 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 | ||
142 | static void input_register_keys(void) | 181 | |
182 | /* register with input layer */ | ||
183 | static 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 | ||
157 | static void input_repeat_key(unsigned long data) | 205 | /* called by the input driver after rep[REP_DELAY] ms */ |
206 | static 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 | ||
164 | static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) | 214 | /* check for configuration changes */ |
215 | int 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 */ | ||
177 | static int av7110_ir_write_proc(struct file *file, const char __user *buffer, | 265 | static 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 */ | ||
209 | static void ir_handler(struct av7110 *av7110, u32 ircom) | 308 | static 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 | ||
217 | int __devinit av7110_ir_init(struct av7110 *av7110) | 316 | int __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"); |