[linux-dvb] [PATCH] Add support for remote control to DEC2000-T
Peter Beutner
p.beutner at gmx.net
Mon Feb 21 01:33:21 CET 2005
Hi
This patch adds support for recieving signals from an infrared remote
control with the DEC2000-T box.
This is done by configuring an extra pipe to the usb device and getting
interrupt events from the box over it.
This is enabled by a specific command which has to be send to the
device( at least that is *my guessing* of the
command, as i get it only via sniffing the windows driver).
The driver registers itself in the linux input system, so that the
events from the remote control can be read out
via /dev/input/eventX (using LIRC for example).
I only testet it with the remote control shipped with my box, dont know
if others will work too.
I also cant say if it will work with all models/frmware versions of the
DEC2000T(or even DEC3000S?)
Please also take a closer look at the code, as this is actually my first
coding 'inside the linux kernel', so maybe
there are some errors in it.
There is a point in the code which may still need a bit work, which the
the proper handling of keyrepeat events.
For now all signals are handled as single key up and down event.
I remember that topic was already discussed in the list(i think for the
cinergy driver), i just havent had time yet
to read it again.
As I wont have much time in the next weeks because of my exams just
startet, I decided to send the patch as it
is now to get some more people the chance to test it.
Thanks
Peter
-------------- next part --------------
Index: ttusb_dec.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c,v
retrieving revision 1.64
diff -p -u -r1.64 ttusb_dec.c
--- ttusb_dec.c 8 Feb 2005 13:00:53 -0000 1.64
+++ ttusb_dec.c 21 Feb 2005 00:14:57 -0000
@@ -32,6 +32,7 @@
#include <linux/firmware.h>
#include <linux/crc32.h>
#include <linux/init.h>
+#include <linux/input.h>
#include "dmxdev.h"
#include "dvb_demux.h"
@@ -42,11 +43,14 @@
static int debug;
static int output_pva;
+static int enable_rc;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
module_param(output_pva, int, 0444);
MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
+module_param(enable_rc, int, 0644);
+MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
#define dprintk if (debug) printk
@@ -56,9 +60,11 @@ MODULE_PARM_DESC(output_pva, "Output PVA
#define RESULT_PIPE 0x84
#define IN_PIPE 0x88
#define OUT_PIPE 0x07
+#define IRQ_PIPE 0x8A
#define COMMAND_PACKET_SIZE 0x3c
#define ARM_PACKET_SIZE 0x1000
+#define IRQ_PACKET_SIZE 0x8
#define ISO_BUF_COUNT 0x04
#define FRAMES_PER_ISO_BUF 0x04
@@ -107,9 +113,13 @@ struct ttusb_dec {
unsigned int result_pipe;
unsigned int in_pipe;
unsigned int out_pipe;
+ unsigned int irq_pipe;
enum ttusb_dec_interface interface;
struct semaphore usb_sem;
+ void *irq_buffer;
+ struct urb *irq_urb;
+ dma_addr_t irq_dma_handle;
void *iso_buffer;
dma_addr_t iso_dma_handle;
struct urb *iso_urb[ISO_BUF_COUNT];
@@ -141,6 +151,8 @@ struct ttusb_dec {
struct dvb_demux_filter *video_filter;
struct list_head filter_info_list;
spinlock_t filter_info_list_lock;
+
+ struct input_dev rc_input_dev;
int active; /* Loaded successfully */
};
@@ -157,9 +169,83 @@ struct filter_info {
struct list_head filter_info_list;
};
+const uint16_t rc_keys[] = {
+ KEY_POWER,
+ KEY_MUTE,
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_0,
+ KEY_CHANNELUP,
+ KEY_VOLUMEDOWN,
+ KEY_OK,
+ KEY_VOLUMEUP,
+ KEY_CHANNELDOWN,
+ KEY_PREVIOUS,
+ KEY_ESC,
+ KEY_RED,
+ KEY_GREEN,
+ KEY_YELLOW,
+ KEY_BLUE,
+ KEY_OPTION,
+ KEY_M,
+ KEY_RADIO
+};
+
static void ttusb_dec_set_model(struct ttusb_dec *dec,
enum ttusb_dec_model model);
+static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
+{
+ struct ttusb_dec * dec = urb->context;
+ char *buffer = dec->irq_buffer;
+ int retval;
+
+ switch(urb->status) {
+ case 0: /*success*/
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -ETIMEDOUT:
+ /* this urb is dead, cleanup */
+ dprintk("%s:urb shutting down with status: %d\n",
+ __FUNCTION__, urb->status);
+ return;
+ default:
+ dprintk("%s:nonzero status received: %d\n",
+ __FUNCTION__,urb->status);
+ goto exit;
+ }
+
+ if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) {
+ /* IR - Event */
+ /* this is an fact a bit too simple implementation;
+ * the box also reports a keyrepeat signal
+ * (with buffer[3] == 0x40) in an intervall of ~100ms.
+ * But to handle this correctly we had to imlemenent some
+ * kind of timer which signals a 'key up' event if no
+ * keyrepeat signal is recieved for lets say 200ms.
+ * this should/could be added later ...
+ * for now lets report each signal as a key down and up*/
+ dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
+ input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],1);
+ input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],0);
+ input_sync(&dec->rc_input_dev);
+ }
+
+exit: retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if(retval)
+ printk("%s - usb_commit_urb failed with result: %d\n",
+ __FUNCTION__, retval);
+}
+
static u16 crc16(u16 crc, const u8 *buf, size_t len)
{
u16 tmp;
@@ -1095,6 +1181,30 @@ static void ttusb_dec_init_tasklet(struc
(unsigned long)dec);
}
+static void ttusb_init_rc( struct ttusb_dec *dec)
+{
+ u8 b[] = { 0x00, 0x01 };
+ int i;
+
+ init_input_dev(&dec->rc_input_dev);
+
+ dec->rc_input_dev.name = "ttusb_dec remote control";
+ dec->rc_input_dev.evbit[0] = BIT(EV_KEY);
+ dec->rc_input_dev.keycodesize = sizeof(unsigned char);
+ dec->rc_input_dev.keycodemax = KEY_MAX;
+
+ for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
+ set_bit(rc_keys[i], dec->rc_input_dev.keybit);
+
+ input_register_device(&dec->rc_input_dev);
+
+ if(usb_submit_urb(dec->irq_urb,GFP_KERNEL)) {
+ printk("%s: usb_submit_urb failed\n",__FUNCTION__);
+ }
+ /* enable irq pipe */
+ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
+}
+
static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
{
dprintk("%s\n", __FUNCTION__);
@@ -1105,7 +1215,7 @@ static void ttusb_dec_init_v_pes(struct
dec->v_pes[3] = 0xe0;
}
-static void ttusb_dec_init_usb(struct ttusb_dec *dec)
+static int ttusb_dec_init_usb(struct ttusb_dec *dec)
{
dprintk("%s\n", __FUNCTION__);
@@ -1116,8 +1226,26 @@ static void ttusb_dec_init_usb(struct tt
dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
+ dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);
- ttusb_dec_alloc_iso_urbs(dec);
+ if(enable_rc) {
+ dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if(!dec->irq_urb) {
+ return -ENOMEM;
+ }
+ dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,
+ SLAB_ATOMIC, &dec->irq_dma_handle);
+ if(!dec->irq_buffer) {
+ return -ENOMEM;
+ }
+ usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,
+ dec->irq_buffer, IRQ_PACKET_SIZE,
+ ttusb_dec_handle_irq, dec, 1);
+ dec->irq_urb->transfer_dma = dec->irq_dma_handle;
+ dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
+
+ return ttusb_dec_alloc_iso_urbs(dec);
}
static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
@@ -1381,6 +1509,20 @@ static void ttusb_dec_exit_usb(struct tt
usb_kill_urb(dec->iso_urb[i]);
ttusb_dec_free_iso_urbs(dec);
+
+ if(enable_rc) {
+ /* we have to check whether the irq URB is already submitted.
+ * As the irq is submitted after the interface is changed,
+ * this is the best method i figured out.
+ * Any other possibilities?*/
+ if(dec->interface == TTUSB_DEC_INTERFACE_IN)
+ usb_kill_urb(dec->irq_urb);
+
+ usb_free_urb(dec->irq_urb);
+
+ usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,
+ dec->irq_buffer, dec->irq_dma_handle);
+ }
}
static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
@@ -1462,7 +1604,8 @@ static int ttusb_dec_probe(struct usb_in
dec->udev = udev;
- ttusb_dec_init_usb(dec);
+ if (ttusb_dec_init_usb(dec))
+ return 0;
if (ttusb_dec_init_stb(dec)) {
ttusb_dec_exit_usb(dec);
return 0;
@@ -1502,6 +1645,9 @@ static int ttusb_dec_probe(struct usb_in
ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
+ if(enable_rc)
+ ttusb_init_rc(dec);
+
return 0;
}
More information about the linux-dvb
mailing list