diff options
author | Devin Heitmueller <devin.heitmueller@gmail.com> | 2008-11-13 01:15:55 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-29 14:53:33 -0500 |
commit | 4b92253acc723f365ad6b2f32e4118e38133b7b8 (patch) | |
tree | 509874e833c9330a29c85c554b01df1380ca6052 /drivers/media/video | |
parent | 0a6b8a851efae71b0a6f2cbf5d40880553dfabaa (diff) |
V4L/DVB (9628): em28xx: refactor IR support
Refactor the em28xx IR support based on the em2860/em2880 and em2874
datasheets.
Tested on the HVR-950 (em2883), Pinnacle 800e (em2883), Pinnacle 80e (em2874)
using the remote controls that came with those products.
Signed-off-by: Devin Heitmueller <devin.heitmueller@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-cards.c | 4 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-input.c | 202 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-reg.h | 8 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 4 |
4 files changed, 147 insertions, 71 deletions
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 1d38bfaa3e7c..3b585486f7fe 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -592,6 +592,7 @@ struct em28xx_board em28xx_boards[] = { | |||
592 | .mts_firmware = 1, | 592 | .mts_firmware = 1, |
593 | .has_12mhz_i2s = 1, | 593 | .has_12mhz_i2s = 1, |
594 | .has_dvb = 1, | 594 | .has_dvb = 1, |
595 | .ir_codes = ir_codes_hauppauge_new, | ||
595 | .decoder = EM28XX_TVP5150, | 596 | .decoder = EM28XX_TVP5150, |
596 | .input = { { | 597 | .input = { { |
597 | .type = EM28XX_VMUX_TELEVISION, | 598 | .type = EM28XX_VMUX_TELEVISION, |
@@ -615,6 +616,7 @@ struct em28xx_board em28xx_boards[] = { | |||
615 | .mts_firmware = 1, | 616 | .mts_firmware = 1, |
616 | .has_12mhz_i2s = 1, | 617 | .has_12mhz_i2s = 1, |
617 | .has_dvb = 1, | 618 | .has_dvb = 1, |
619 | .ir_codes = ir_codes_pinnacle_pctv_hd, | ||
618 | .decoder = EM28XX_TVP5150, | 620 | .decoder = EM28XX_TVP5150, |
619 | .input = { { | 621 | .input = { { |
620 | .type = EM28XX_VMUX_TELEVISION, | 622 | .type = EM28XX_VMUX_TELEVISION, |
@@ -1092,6 +1094,7 @@ struct em28xx_board em28xx_boards[] = { | |||
1092 | .vchannels = 0, | 1094 | .vchannels = 0, |
1093 | .tuner_type = TUNER_ABSENT, | 1095 | .tuner_type = TUNER_ABSENT, |
1094 | .has_dvb = 1, | 1096 | .has_dvb = 1, |
1097 | .ir_codes = ir_codes_pinnacle_pctv_hd, | ||
1095 | .decoder = EM28XX_NODECODER, | 1098 | .decoder = EM28XX_NODECODER, |
1096 | #ifdef DJH_DEBUG | 1099 | #ifdef DJH_DEBUG |
1097 | .input = { { | 1100 | .input = { { |
@@ -1329,6 +1332,7 @@ static void em28xx_set_model(struct em28xx *dev) | |||
1329 | dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; | 1332 | dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; |
1330 | dev->has_dvb = em28xx_boards[dev->model].has_dvb; | 1333 | dev->has_dvb = em28xx_boards[dev->model].has_dvb; |
1331 | dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; | 1334 | dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; |
1335 | dev->ir_codes = em28xx_boards[dev->model].ir_codes; | ||
1332 | dev->valid = em28xx_boards[dev->model].valid; | 1336 | dev->valid = em28xx_boards[dev->model].valid; |
1333 | } | 1337 | } |
1334 | 1338 | ||
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 159b5c307f25..07edd4067acc 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c | |||
@@ -52,6 +52,13 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); | |||
52 | Polling structure used by em28xx IR's | 52 | Polling structure used by em28xx IR's |
53 | **********************************************************/ | 53 | **********************************************************/ |
54 | 54 | ||
55 | struct em28xx_ir_poll_result { | ||
56 | unsigned int toggle_bit:1; | ||
57 | unsigned int read_count:7; | ||
58 | u8 rc_address; | ||
59 | u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */ | ||
60 | }; | ||
61 | |||
55 | struct em28xx_IR { | 62 | struct em28xx_IR { |
56 | struct em28xx *dev; | 63 | struct em28xx *dev; |
57 | struct input_dev *input; | 64 | struct input_dev *input; |
@@ -63,13 +70,11 @@ struct em28xx_IR { | |||
63 | int polling; | 70 | int polling; |
64 | struct work_struct work; | 71 | struct work_struct work; |
65 | struct timer_list timer; | 72 | struct timer_list timer; |
66 | u32 last_gpio; | 73 | unsigned int last_toggle:1; |
67 | u32 mask_keycode; | 74 | unsigned int last_readcount; |
68 | u32 mask_keydown; | 75 | unsigned int repeat_interval; |
69 | u32 mask_keyup; | ||
70 | u32 mask_repeat; | ||
71 | 76 | ||
72 | int (*get_key)(struct em28xx_IR *); | 77 | int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); |
73 | }; | 78 | }; |
74 | 79 | ||
75 | /********************************************************** | 80 | /********************************************************** |
@@ -162,11 +167,13 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, | |||
162 | Poll based get keycode functions | 167 | Poll based get keycode functions |
163 | **********************************************************/ | 168 | **********************************************************/ |
164 | 169 | ||
165 | static int default_polling_getkey(struct em28xx_IR *ir) | 170 | /* This is for the em2860/em2880 */ |
171 | static int default_polling_getkey(struct em28xx_IR *ir, | ||
172 | struct em28xx_ir_poll_result *poll_result) | ||
166 | { | 173 | { |
167 | struct em28xx *dev = ir->dev; | 174 | struct em28xx *dev = ir->dev; |
168 | int rc; | 175 | int rc; |
169 | u8 msg[4] = { 0, 0, 0, 0 }; | 176 | u8 msg[3] = { 0, 0, 0 }; |
170 | 177 | ||
171 | /* Read key toggle, brand, and key code | 178 | /* Read key toggle, brand, and key code |
172 | on registers 0x45, 0x46 and 0x47 | 179 | on registers 0x45, 0x46 and 0x47 |
@@ -176,7 +183,51 @@ static int default_polling_getkey(struct em28xx_IR *ir) | |||
176 | if (rc < 0) | 183 | if (rc < 0) |
177 | return rc; | 184 | return rc; |
178 | 185 | ||
179 | return (int)(le32_to_cpu(*(u32 *)msg)); | 186 | /* Infrared toggle (Reg 0x45[7]) */ |
187 | poll_result->toggle_bit = (msg[0] >> 7); | ||
188 | |||
189 | /* Infrared read count (Reg 0x45[6:0] */ | ||
190 | poll_result->read_count = (msg[0] & 0x7f); | ||
191 | |||
192 | /* Remote Control Address (Reg 0x46) */ | ||
193 | poll_result->rc_address = msg[1]; | ||
194 | |||
195 | /* Remote Control Data (Reg 0x47) */ | ||
196 | poll_result->rc_data[0] = msg[2]; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int em2874_polling_getkey(struct em28xx_IR *ir, | ||
202 | struct em28xx_ir_poll_result *poll_result) | ||
203 | { | ||
204 | struct em28xx *dev = ir->dev; | ||
205 | int rc; | ||
206 | u8 msg[5] = { 0, 0, 0, 0, 0 }; | ||
207 | |||
208 | /* Read key toggle, brand, and key code | ||
209 | on registers 0x51-55 | ||
210 | */ | ||
211 | rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, | ||
212 | msg, sizeof(msg)); | ||
213 | if (rc < 0) | ||
214 | return rc; | ||
215 | |||
216 | /* Infrared toggle (Reg 0x51[7]) */ | ||
217 | poll_result->toggle_bit = (msg[0] >> 7); | ||
218 | |||
219 | /* Infrared read count (Reg 0x51[6:0] */ | ||
220 | poll_result->read_count = (msg[0] & 0x7f); | ||
221 | |||
222 | /* Remote Control Address (Reg 0x52) */ | ||
223 | poll_result->rc_address = msg[1]; | ||
224 | |||
225 | /* Remote Control Data (Reg 0x53-55) */ | ||
226 | poll_result->rc_data[0] = msg[2]; | ||
227 | poll_result->rc_data[1] = msg[3]; | ||
228 | poll_result->rc_data[2] = msg[4]; | ||
229 | |||
230 | return 0; | ||
180 | } | 231 | } |
181 | 232 | ||
182 | /********************************************************** | 233 | /********************************************************** |
@@ -185,52 +236,60 @@ static int default_polling_getkey(struct em28xx_IR *ir) | |||
185 | 236 | ||
186 | static void em28xx_ir_handle_key(struct em28xx_IR *ir) | 237 | static void em28xx_ir_handle_key(struct em28xx_IR *ir) |
187 | { | 238 | { |
188 | int gpio; | 239 | int result; |
189 | u32 data; | 240 | int do_sendkey = 0; |
190 | 241 | struct em28xx_ir_poll_result poll_result; | |
191 | /* read gpio value */ | 242 | |
192 | gpio = ir->get_key(ir); | 243 | /* read the registers containing the IR status */ |
193 | if (gpio < 0) | 244 | result = ir->get_key(ir, &poll_result); |
245 | if (result < 0) { | ||
246 | dprintk("ir->get_key() failed %d\n", result); | ||
194 | return; | 247 | return; |
248 | } | ||
195 | 249 | ||
196 | if (gpio == ir->last_gpio) | 250 | dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n", |
197 | return; | 251 | poll_result.toggle_bit, poll_result.read_count, |
252 | ir->last_readcount, poll_result.rc_data[0]); | ||
253 | |||
254 | if (ir->dev->chip_id == CHIP_ID_EM2874) { | ||
255 | /* The em2874 clears the readcount field every time the | ||
256 | register is read. The em2860/2880 datasheet says that it | ||
257 | is supposed to clear the readcount, but it doesn't. So with | ||
258 | the em2874, we are looking for a non-zero read count as | ||
259 | opposed to a readcount that is incrementing */ | ||
260 | ir->last_readcount = 0; | ||
261 | } | ||
198 | 262 | ||
199 | ir->last_gpio = gpio; | 263 | if (poll_result.read_count == 0) { |
200 | 264 | /* The button has not been pressed since the last read */ | |
201 | /* extract data */ | 265 | } else if (ir->last_toggle != poll_result.toggle_bit) { |
202 | data = ir_extract_bits(gpio, ir->mask_keycode); | 266 | /* A button has been pressed */ |
203 | dprintk("irq gpio=0x%x code=%d | poll%s%s\n", | 267 | dprintk("button has been pressed\n"); |
204 | gpio, data, | 268 | ir->last_toggle = poll_result.toggle_bit; |
205 | (gpio & ir->mask_keydown) ? " down" : "", | 269 | ir->repeat_interval = 0; |
206 | (gpio & ir->mask_keyup) ? " up" : ""); | 270 | do_sendkey = 1; |
207 | 271 | } else if (poll_result.toggle_bit == ir->last_toggle && | |
208 | /* Generate keyup/keydown events */ | 272 | poll_result.read_count > 0 && |
209 | if (ir->mask_keydown) { | 273 | poll_result.read_count != ir->last_readcount) { |
210 | /* bit set on keydown */ | 274 | /* The button is still being held down */ |
211 | if (gpio & ir->mask_keydown) | 275 | dprintk("button being held down\n"); |
212 | ir_input_keydown(ir->input, &ir->ir, data, data); | 276 | |
213 | else | 277 | /* Debouncer for first keypress */ |
214 | ir_input_nokey(ir->input, &ir->ir); | 278 | if (ir->repeat_interval++ > 9) { |
215 | } else if (ir->mask_keyup) { | 279 | /* Start repeating after 1 second */ |
216 | /* bit cleared on keydown */ | 280 | do_sendkey = 1; |
217 | if (!(gpio & ir->mask_keyup)) | ||
218 | ir_input_keydown(ir->input, &ir->ir, data, data); | ||
219 | else | ||
220 | ir_input_nokey(ir->input, &ir->ir); | ||
221 | } else if (ir->mask_repeat) { | ||
222 | int count = ir->mask_repeat & gpio; | ||
223 | |||
224 | /* Avoid keyboard bouncing */ | ||
225 | if ((count == 1) || (count >= 5)) { | ||
226 | ir_input_keydown(ir->input, &ir->ir, data, data); | ||
227 | ir_input_nokey(ir->input, &ir->ir); | ||
228 | } | 281 | } |
229 | } else { | 282 | } |
230 | /* can't distinguish keydown/up :-/ */ | 283 | |
231 | ir_input_keydown(ir->input, &ir->ir, data, data); | 284 | if (do_sendkey) { |
285 | dprintk("sending keypress\n"); | ||
286 | ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0], | ||
287 | poll_result.rc_data[0]); | ||
232 | ir_input_nokey(ir->input, &ir->ir); | 288 | ir_input_nokey(ir->input, &ir->ir); |
233 | } | 289 | } |
290 | |||
291 | ir->last_readcount = poll_result.read_count; | ||
292 | return; | ||
234 | } | 293 | } |
235 | 294 | ||
236 | static void ir_timer(unsigned long data) | 295 | static void ir_timer(unsigned long data) |
@@ -265,10 +324,14 @@ int em28xx_ir_init(struct em28xx *dev) | |||
265 | { | 324 | { |
266 | struct em28xx_IR *ir; | 325 | struct em28xx_IR *ir; |
267 | struct input_dev *input_dev; | 326 | struct input_dev *input_dev; |
268 | IR_KEYTAB_TYPE *ir_codes = NULL; | 327 | u8 ir_config; |
269 | int ir_type = IR_TYPE_OTHER; | ||
270 | int err = -ENOMEM; | 328 | int err = -ENOMEM; |
271 | 329 | ||
330 | if (dev->ir_codes == NULL) { | ||
331 | /* No remote control support */ | ||
332 | return 0; | ||
333 | } | ||
334 | |||
272 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); | 335 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); |
273 | input_dev = input_allocate_device(); | 336 | input_dev = input_allocate_device(); |
274 | if (!ir || !input_dev) | 337 | if (!ir || !input_dev) |
@@ -276,25 +339,26 @@ int em28xx_ir_init(struct em28xx *dev) | |||
276 | 339 | ||
277 | ir->input = input_dev; | 340 | ir->input = input_dev; |
278 | 341 | ||
279 | /* */ | 342 | /* Setup the proper handler based on the chip */ |
280 | ir->get_key = default_polling_getkey; | 343 | switch (dev->chip_id) { |
281 | ir->polling = 50; /* ms */ | 344 | case CHIP_ID_EM2860: |
282 | 345 | case CHIP_ID_EM2883: | |
283 | /* detect & configure */ | 346 | ir->get_key = default_polling_getkey; |
284 | switch (dev->model) { | ||
285 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | ||
286 | ir_type = IR_TYPE_OTHER; | ||
287 | ir_codes = ir_codes_hauppauge_new; | ||
288 | ir->mask_keycode = 0x007f0000; | ||
289 | ir->mask_repeat = 0x0000007f; | ||
290 | break; | 347 | break; |
291 | } | 348 | case CHIP_ID_EM2874: |
292 | 349 | ir->get_key = em2874_polling_getkey; | |
293 | if (NULL == ir_codes) { | 350 | /* For now we only support RC5, so enable it */ |
294 | err = -ENODEV; | 351 | ir_config = EM2874_IR_RC5; |
352 | em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); | ||
353 | break; | ||
354 | default: | ||
355 | printk("Unrecognized em28xx chip id: IR not supported\n"); | ||
295 | goto err_out_free; | 356 | goto err_out_free; |
296 | } | 357 | } |
297 | 358 | ||
359 | /* This is how often we ask the chip for IR information */ | ||
360 | ir->polling = 100; /* ms */ | ||
361 | |||
298 | /* init input device */ | 362 | /* init input device */ |
299 | snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", | 363 | snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", |
300 | dev->name); | 364 | dev->name); |
@@ -302,7 +366,7 @@ int em28xx_ir_init(struct em28xx *dev) | |||
302 | usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); | 366 | usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); |
303 | strlcat(ir->phys, "/input0", sizeof(ir->phys)); | 367 | strlcat(ir->phys, "/input0", sizeof(ir->phys)); |
304 | 368 | ||
305 | ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | 369 | ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->ir_codes); |
306 | input_dev->name = ir->name; | 370 | input_dev->name = ir->name; |
307 | input_dev->phys = ir->phys; | 371 | input_dev->phys = ir->phys; |
308 | input_dev->id.bustype = BUS_USB; | 372 | input_dev->id.bustype = BUS_USB; |
@@ -315,10 +379,6 @@ int em28xx_ir_init(struct em28xx *dev) | |||
315 | ir->dev = dev; | 379 | ir->dev = dev; |
316 | dev->ir = ir; | 380 | dev->ir = ir; |
317 | 381 | ||
318 | /* Get the current key status, to avoid adding an | ||
319 | unexistent key code */ | ||
320 | ir->last_gpio = ir->get_key(ir); | ||
321 | |||
322 | em28xx_ir_start(ir); | 382 | em28xx_ir_start(ir); |
323 | 383 | ||
324 | /* all done */ | 384 | /* all done */ |
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index f67955a1b818..b8e97836370f 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h | |||
@@ -84,9 +84,17 @@ | |||
84 | #define EM28XX_R14_VIDEO_AC97 0x14 | 84 | #define EM28XX_R14_VIDEO_AC97 0x14 |
85 | 85 | ||
86 | /* em2874 registers */ | 86 | /* em2874 registers */ |
87 | #define EM2874_R50_IR_CONFIG 0x50 | ||
88 | #define EM2874_R51_IR 0x51 | ||
87 | #define EM2874_R5F_TS_ENABLE 0x5f | 89 | #define EM2874_R5F_TS_ENABLE 0x5f |
88 | #define EM2874_R80_GPIO 0x80 | 90 | #define EM2874_R80_GPIO 0x80 |
89 | 91 | ||
92 | /* em2874 IR config register (0x50) */ | ||
93 | #define EM2874_IR_NEC 0x00 | ||
94 | #define EM2874_IR_RC5 0x04 | ||
95 | #define EM2874_IR_RC5_MODE_0 0x08 | ||
96 | #define EM2874_IR_RC5_MODE_6A 0x0b | ||
97 | |||
90 | /* em2874 Transport Stream Enable Register (0x5f) */ | 98 | /* em2874 Transport Stream Enable Register (0x5f) */ |
91 | #define EM2874_TS1_CAPTURE_ENABLE (1 << 0) | 99 | #define EM2874_TS1_CAPTURE_ENABLE (1 << 0) |
92 | #define EM2874_TS1_FILTER_ENABLE (1 << 1) | 100 | #define EM2874_TS1_FILTER_ENABLE (1 << 1) |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 73fd9e9e0403..9ff3c83e63d0 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -305,6 +305,7 @@ struct em28xx_board { | |||
305 | 305 | ||
306 | struct em28xx_input input[MAX_EM28XX_INPUT]; | 306 | struct em28xx_input input[MAX_EM28XX_INPUT]; |
307 | struct em28xx_input radio; | 307 | struct em28xx_input radio; |
308 | IR_KEYTAB_TYPE *ir_codes; | ||
308 | }; | 309 | }; |
309 | 310 | ||
310 | struct em28xx_eeprom { | 311 | struct em28xx_eeprom { |
@@ -481,6 +482,9 @@ struct em28xx { | |||
481 | /* Caches GPO and GPIO registers */ | 482 | /* Caches GPO and GPIO registers */ |
482 | unsigned char reg_gpo, reg_gpio; | 483 | unsigned char reg_gpo, reg_gpio; |
483 | 484 | ||
485 | /* Infrared remote control support */ | ||
486 | IR_KEYTAB_TYPE *ir_codes; | ||
487 | |||
484 | /* Snapshot button */ | 488 | /* Snapshot button */ |
485 | char snapshot_button_path[30]; /* path of the input dev */ | 489 | char snapshot_button_path[30]; /* path of the input dev */ |
486 | struct input_dev *sbutton_input_dev; | 490 | struct input_dev *sbutton_input_dev; |