]> err.no Git - linux-2.6/commitdiff
V4L/DVB (7474): support key repeat with dib0700 ir receiver
authorPatrick Boettcher <pb@linuxtv.org>
Sun, 30 Mar 2008 00:37:01 +0000 (21:37 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Thu, 24 Apr 2008 17:07:56 +0000 (14:07 -0300)
This patch enables support for repeating last event when a key is holded
down with dib0700 devices. It works with rc5 and nec remotes.
It also fixes an annoying bug that floods kernel log with "Unknown key"
messages after each keypress. This happened because the driver was not
resetting infrared register after each poll so it kept polling last key
even if nothing was being pressed. Fixing this, (calling rc_setup after
each poll), permits to implement key repeat.

Signed-off-by: Filippo Argiolas <filippo.argiolas at gmail.com>
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c

index 4a903ea958965d5bc7cbadbd96f2282e89dedf34..66d4dc6ba46fe8a78a9d597f3d45bdb6e6c5cf01 100644 (file)
@@ -37,6 +37,7 @@ struct dib0700_state {
        u8 channel_state;
        u16 mt2060_if1[2];
        u8 rc_toggle;
+       u8 rc_counter;
        u8 is_dib7000pc;
 };
 
@@ -44,12 +45,15 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8
 extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
 extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
 extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
+extern int dib0700_rc_setup(struct dvb_usb_device *d);
 extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 extern struct i2c_algorithm dib0700_i2c_algo;
 extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
                        struct dvb_usb_device_description **desc, int *cold);
 
 extern int dib0700_device_count;
+extern int dvb_usb_dib0700_ir_proto;
 extern struct dvb_usb_device_properties dib0700_devices[];
 extern struct usb_device_id dib0700_usb_id_table[];
+
 #endif
index c9857d5c69829e68bbc9e82af68026ebc4d4288c..4b3836e63be94e20383ad2375906c5807865f185 100644 (file)
@@ -13,7 +13,7 @@ int dvb_usb_dib0700_debug;
 module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
 
-static int dvb_usb_dib0700_ir_proto = 1;
+int dvb_usb_dib0700_ir_proto = 1;
 module_param(dvb_usb_dib0700_ir_proto, int, 0644);
 MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
 
@@ -261,7 +261,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
-static int dib0700_rc_setup(struct dvb_usb_device *d)
+int dib0700_rc_setup(struct dvb_usb_device *d)
 {
        u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
        int i = dib0700_ctrl_wr(d, rc_setup, 3);
index 9fd8399e5d8f05659afeff2b9b9b669cd4fe9431..fe96f795792bce381a77ef40bc0cee1808f02708 100644 (file)
@@ -445,6 +445,9 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
 
 static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY 2
+
 static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        u8 key[4];
@@ -458,18 +461,67 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                err("RC Query Failed");
                return -1;
        }
+
+       /* losing half of KEY_0 events from Philipps rc5 remotes.. */
        if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
-       if (key[3-1]!=st->rc_toggle) {
+
+       /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
+
+       dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
+
+       switch (dvb_usb_dib0700_ir_proto) {
+       case 0: {
+               /* NEC protocol sends repeat code as 0 0 0 FF */
+               if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
+                   (key[3] == 0xFF)) {
+                       st->rc_counter++;
+                       if (st->rc_counter > RC_REPEAT_DELAY) {
+                               *event = d->last_event;
+                               *state = REMOTE_KEY_PRESSED;
+                               st->rc_counter = RC_REPEAT_DELAY;
+                       }
+                       return 0;
+               }
                for (i=0;i<d->props.rc_key_map_size; i++) {
                        if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+                               st->rc_counter = 0;
+                               *event = keymap[i].event;
+                               *state = REMOTE_KEY_PRESSED;
+                               d->last_event = keymap[i].event;
+                               return 0;
+                       }
+               }
+               break;
+       }
+       default: {
+               /* RC-5 protocol changes toggle bit on new keypress */
+               for (i = 0; i < d->props.rc_key_map_size; i++) {
+                       if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+                               if (d->last_event == keymap[i].event &&
+                                       key[3-1] == st->rc_toggle) {
+                                       st->rc_counter++;
+                                       /* prevents unwanted double hits */
+                                       if (st->rc_counter > RC_REPEAT_DELAY) {
+                                               *event = d->last_event;
+                                               *state = REMOTE_KEY_PRESSED;
+                                               st->rc_counter = RC_REPEAT_DELAY;
+                                       }
+
+                                       return 0;
+                               }
+                               st->rc_counter = 0;
                                *event = keymap[i].event;
                                *state = REMOTE_KEY_PRESSED;
-                               st->rc_toggle=key[3-1];
+                               st->rc_toggle = key[3-1];
+                               d->last_event = keymap[i].event;
                                return 0;
                        }
                }
-               err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+               break;
+       }
        }
+       err("Unknown remote controller key: %2X %2X %2X %2X", (int) key[3-2], (int) key[3-3], (int) key[3-1], (int) key[3]);
+       d->last_event = 0;
        return 0;
 }