summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Boettcher <devnull@localhost>2004-11-07 18:46:20 +0000
committerPatrick Boettcher <devnull@localhost>2004-11-07 18:46:20 +0000
commitb1adb56ca9f64c2cec0ba0ebb75332e51fd4ea79 (patch)
tree1aa61031b84e0b54f9c77c7f7d88e5a472e5a269
parent42f883be562bf0649c308d7e206e73098074a72e (diff)
downloadmediapointer-dvb-s2-b1adb56ca9f64c2cec0ba0ebb75332e51fd4ea79.tar.gz
mediapointer-dvb-s2-b1adb56ca9f64c2cec0ba0ebb75332e51fd4ea79.tar.bz2
added remote control event handling. Thanks to David Matthews.
-rw-r--r--linux/Documentation/dvb/README.dibusb5
-rw-r--r--linux/drivers/media/dvb/dibusb/Kconfig7
-rw-r--r--linux/drivers/media/dvb/dibusb/dvb-dibusb.c187
-rw-r--r--linux/drivers/media/dvb/dibusb/dvb-dibusb.h5
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;
};