diff options
author | Patrick Boettcher <devnull@localhost> | 2004-11-07 18:46:20 +0000 |
---|---|---|
committer | Patrick Boettcher <devnull@localhost> | 2004-11-07 18:46:20 +0000 |
commit | b1adb56ca9f64c2cec0ba0ebb75332e51fd4ea79 (patch) | |
tree | 1aa61031b84e0b54f9c77c7f7d88e5a472e5a269 /linux | |
parent | 42f883be562bf0649c308d7e206e73098074a72e (diff) | |
download | mediapointer-dvb-s2-b1adb56ca9f64c2cec0ba0ebb75332e51fd4ea79.tar.gz mediapointer-dvb-s2-b1adb56ca9f64c2cec0ba0ebb75332e51fd4ea79.tar.bz2 |
added remote control event handling. Thanks to David Matthews.
Diffstat (limited to 'linux')
-rw-r--r-- | linux/Documentation/dvb/README.dibusb | 5 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dibusb/Kconfig | 7 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dibusb/dvb-dibusb.c | 187 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dibusb/dvb-dibusb.h | 5 |
4 files changed, 176 insertions, 28 deletions
diff --git a/linux/Documentation/dvb/README.dibusb b/linux/Documentation/dvb/README.dibusb index 0c1da012c..554f65606 100644 --- a/linux/Documentation/dvb/README.dibusb +++ b/linux/Documentation/dvb/README.dibusb @@ -71,6 +71,7 @@ Supported devices USB2.0 0. NEWS: + 2004-11-07 - added remote control support. Thanks to David Matthews. 2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec) - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD - moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems @@ -197,6 +198,9 @@ Patches, comments and suggestions are very very welcome providing specs, code and help, on which the dvb-dibusb and dib3000mb are based. + David Matthews for identifying a new device type (Artec T1 with AN2235) + and for extending dibusb with remote control event handling. Thank you. + Alex Woods for frequently answering question about usb and dvb stuff, a big thank you @@ -208,7 +212,6 @@ Patches, comments and suggestions are very very welcome user-level firmware loader, which saves a lot of time (when writing the vp7041 driver) - David Matthews for identifying a new device type (Artec T1 with AN2235) Ulf Hermenau for helping me out with traditional chinese. diff --git a/linux/drivers/media/dvb/dibusb/Kconfig b/linux/drivers/media/dvb/dibusb/Kconfig index c37fb4bac..028980897 100644 --- a/linux/drivers/media/dvb/dibusb/Kconfig +++ b/linux/drivers/media/dvb/dibusb/Kconfig @@ -42,3 +42,10 @@ config DVB_DIBUSB_MISDESIGNED_AN2235 CY7C64613 (AN2235). Say Y if your Artec device has 0x0574 as Vendor ID and 0x2235 as Product ID. + +config DVB_DIBCOM_DEBUG + bool "Enable extended debug support for DiBcom USB device" + depends on DVB_DIBUSB + help + Say Y if you want to enable debuging. See modinfo dvb-dibusb for + debug level. diff --git a/linux/drivers/media/dvb/dibusb/dvb-dibusb.c b/linux/drivers/media/dvb/dibusb/dvb-dibusb.c index 7a064bbd9..713d66b1d 100644 --- a/linux/drivers/media/dvb/dibusb/dvb-dibusb.c +++ b/linux/drivers/media/dvb/dibusb/dvb-dibusb.c @@ -10,6 +10,8 @@ * * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) * + * + * Remote control code added by David Matthews (dm@prolingua.co.uk) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,6 +32,7 @@ #include <linux/version.h> #include <linux/moduleparam.h> #include <linux/pci.h> +#include <linux/input.h> #include "dmxdev.h" #include "dvb_demux.h" @@ -42,7 +45,6 @@ /* debug */ - #ifdef CONFIG_DVB_DIBCOM_DEBUG #define dprintk(level,args...) \ do { if ((debug & level)) { printk(args); } } while (0) @@ -55,7 +57,7 @@ static int debug; module_param(debug, int, 0x644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err (|-able))."); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))."); #else #define dprintk(args...) #define debug_dump(b,l) @@ -66,6 +68,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=e #define deb_alot(args...) dprintk(0x04,args) #define deb_ts(args...) dprintk(0x08,args) #define deb_err(args...) dprintk(0x10,args) +#define deb_rc(args...) dprintk(0x20,args) + /* Version information */ #define DRIVER_VERSION "0.1" @@ -234,6 +238,136 @@ static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,0); } +/* Table to map raw key codes to key events. This should not be hard-wired + into the kernel. */ +static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] = +{ + /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ + { 0x00, 0xff, 0x16, KEY_POWER }, + { 0x00, 0xff, 0x10, KEY_MUTE }, + { 0x00, 0xff, 0x03, KEY_1 }, + { 0x00, 0xff, 0x01, KEY_2 }, + { 0x00, 0xff, 0x06, KEY_3 }, + { 0x00, 0xff, 0x09, KEY_4 }, + { 0x00, 0xff, 0x1d, KEY_5 }, + { 0x00, 0xff, 0x1f, KEY_6 }, + { 0x00, 0xff, 0x0d, KEY_7 }, + { 0x00, 0xff, 0x19, KEY_8 }, + { 0x00, 0xff, 0x1b, KEY_9 }, + { 0x00, 0xff, 0x15, KEY_0 }, + { 0x00, 0xff, 0x05, KEY_CHANNELUP }, + { 0x00, 0xff, 0x02, KEY_CHANNELDOWN }, + { 0x00, 0xff, 0x1e, KEY_VOLUMEUP }, + { 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN }, + { 0x00, 0xff, 0x11, KEY_RECORD }, + { 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x00, 0xff, 0x14, KEY_PLAY }, + { 0x00, 0xff, 0x1a, KEY_STOP }, + { 0x00, 0xff, 0x40, KEY_REWIND }, + { 0x00, 0xff, 0x12, KEY_FASTFORWARD }, + { 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x00, 0xff, 0x4c, KEY_PAUSE }, + { 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */ + { 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + /* Key codes for the KWorld/ADSTech/JetWay remote. */ + { 0x86, 0x6b, 0x12, KEY_POWER }, + { 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */ + { 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */ + { 0x86, 0x6b, 0x0b, KEY_EPG }, + { 0x86, 0x6b, 0x10, KEY_MUTE }, + { 0x86, 0x6b, 0x01, KEY_1 }, + { 0x86, 0x6b, 0x02, KEY_2 }, + { 0x86, 0x6b, 0x03, KEY_3 }, + { 0x86, 0x6b, 0x04, KEY_4 }, + { 0x86, 0x6b, 0x05, KEY_5 }, + { 0x86, 0x6b, 0x06, KEY_6 }, + { 0x86, 0x6b, 0x07, KEY_7 }, + { 0x86, 0x6b, 0x08, KEY_8 }, + { 0x86, 0x6b, 0x09, KEY_9 }, + { 0x86, 0x6b, 0x0a, KEY_0 }, + { 0x86, 0x6b, 0x18, KEY_ZOOM }, + { 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */ + { 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */ + { 0x86, 0x6b, 0x00, KEY_UNDO }, + { 0x86, 0x6b, 0x1d, KEY_RECORD }, + { 0x86, 0x6b, 0x0d, KEY_STOP }, + { 0x86, 0x6b, 0x0e, KEY_PAUSE }, + { 0x86, 0x6b, 0x16, KEY_PLAY }, + { 0x86, 0x6b, 0x11, KEY_BACK }, + { 0x86, 0x6b, 0x19, KEY_FORWARD }, + { 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */ + { 0x86, 0x6b, 0x15, KEY_ESC }, + { 0x86, 0x6b, 0x1a, KEY_UP }, + { 0x86, 0x6b, 0x1e, KEY_DOWN }, + { 0x86, 0x6b, 0x1f, KEY_LEFT }, + { 0x86, 0x6b, 0x1b, KEY_RIGHT }, +}; + +/* + * Read the remote control and feed the appropriate event. + * NEC protocol is used for remote controls + */ +static int dibusb_read_remote_control(struct usb_dibusb *dib) +{ + u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5]; + int ret; + int i; + if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5))) + return ret; + + switch (rb[0]) { + case DIBUSB_RC_NEC_KEY_PRESSED: + /* rb[1-3] is the actual key, rb[4] is a checksum */ + deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + rb[1], rb[2], rb[3], rb[4]); + + if ((0xff - rb[3]) != rb[4]) { + deb_rc("remote control checksum failed.\n"); + break; + } + + /* See if we can match the raw key code. */ + for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) { + if (rc_keys[i].c0 == rb[1] && + rc_keys[i].c1 == rb[2] && + rc_keys[i].c2 == rb[3]) { + dib->rc_input_event = rc_keys[i].key; + deb_rc("Translated key 0x%04x\n", dib->rc_input_event); + /* Signal down and up events for this key. */ + input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1); + input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0); + input_sync(&dib->rc_input_dev); + break; + } + } + break; + case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */ + break; + case DIBUSB_RC_NEC_KEY_REPEATED: + /* rb[1]..rb[4] are always zero.*/ + /* Repeats often seem to occur so for the moment just ignore this. */ + deb_rc("Key repeat\n"); + break; + default: + break; + } + return 0; +} + +#define RC_QUERY_INTERVAL (100) /* milliseconds */ + +/* Remote-control poll function - called every RC_QUERY_INTERVAL ms to see + whether the remote control has received anything. */ +static void dibusb_query_rc (void *data) +{ + struct usb_dibusb *dib = (struct usb_dibusb *) data; + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + dibusb_read_remote_control(dib); + schedule_delayed_work(&dib->rc_query_work, + msecs_to_jiffies(RC_QUERY_INTERVAL)); +} + /* * Cypress controls */ @@ -261,31 +395,6 @@ static int dibusb_interrupt_read_loop(struct usb_dibusb *dib) } /* - * TODO: a tasklet should run with a delay of 1/10 second - * and feed an appropriate event device ? - * NEC protocol is used for remote controls - */ -static int dibusb_read_remote_control(struct usb_dibusb *dib) -{ - u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5]; - int ret; - if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5))) - return ret; - - switch (rb[0]) { - case DIBUSB_RC_NEC_KEY_PRESSED: - /* rb[1-4] is the actual key */ - break; - case DIBUSB_RC_NEC_EMPTY: - case DIBUSB_RC_NEC_KEY_REPEATED: - default: - break; - } - - return 0; -} - -/* * ioctl for the firmware */ static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen) @@ -471,6 +580,9 @@ static int dibusb_dvb_init(struct usb_dibusb *dib) frontend_init(dib); + /* Start the remote-control polling. */ + schedule_delayed_work(&dib->rc_query_work, msecs_to_jiffies(RC_QUERY_INTERVAL)); + goto success; err_dmx_dev: dvb_dmx_release(&dib->demux); @@ -487,6 +599,10 @@ success: static int dibusb_dvb_exit(struct usb_dibusb *dib) { + cancel_delayed_work(&dib->rc_query_work); + flush_scheduled_work(); + input_unregister_device(&dib->rc_input_dev); + dib->dvb_is_ready = 0; deb_info("unregistering DVB part\n"); dvb_net_release(&dib->dvb_net); @@ -586,6 +702,23 @@ static int dibusb_init(struct usb_dibusb *dib) } dib->dvb_is_ready = 0; + + /* Initialise the remote-control structures.*/ + init_input_dev(&dib->rc_input_dev); + + dib->rc_input_dev.evbit[0] = BIT(EV_KEY); + dib->rc_input_dev.keycodesize = sizeof(unsigned char); + dib->rc_input_dev.keycodemax = KEY_MAX; + dib->rc_input_dev.name = DRIVER_DESC " remote control"; + + for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++) + set_bit(rc_keys[i].key, dib->rc_input_dev.keybit); + + input_register_device(&dib->rc_input_dev); + + dib->rc_input_event = KEY_MAX; + + INIT_WORK(&dib->rc_query_work, dibusb_query_rc, dib); if ((ret = dibusb_dvb_init(dib))) { dibusb_exit(dib); diff --git a/linux/drivers/media/dvb/dibusb/dvb-dibusb.h b/linux/drivers/media/dvb/dibusb/dvb-dibusb.h index 4e2a2e464..5a55d5f73 100644 --- a/linux/drivers/media/dvb/dibusb/dvb-dibusb.h +++ b/linux/drivers/media/dvb/dibusb/dvb-dibusb.h @@ -281,6 +281,11 @@ struct usb_dibusb { struct dvb_demux demux; struct dvb_net dvb_net; struct dvb_frontend* fe; + + /* remote control */ + struct input_dev rc_input_dev; + struct work_struct rc_query_work; + int rc_input_event; }; |