V4L/DVB (13930): dib0700: rework IR logic for firmware 1.20
authorDevin Heitmueller <dheitmueller@kernellabs.com>
Mon, 4 Jan 2010 05:43:19 +0000 (02:43 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 26 Feb 2010 18:10:32 +0000 (15:10 -0300)
When firmware 1.20 was introduced, the dib0700 switched from a polling model
using a USB control message, to the messages being delivered on a USB bulk
pipe.  The code I originally added would do a blocking read on the pipe with a
50ms timeout.  Because the dvb-usb-remote code makes use of the global
workqueue, this resulted in the global workqueue being blocked 50% of the
time.  Also, the synchronous urb_bulk_msg() call would burn excess CPU time
(reflected as an abnormal increase in the system's load average when devices
were connected).

Rework the logic so that we now setup an asynchronous callback on the bulk
pipe, so that we now only handle RC data when it arrives on the pipe.  Note
that we provide a stub function for the RC polling callback so that we can
continue to leverage the shared code in dvb-usb-rc for the setting up of the
input device.

Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c

index 495a90577c5f7f1f9d0524b5edf55d141bb77846..83fc24a6c31a6b6b4b7836a028ea0d6a23f1d60b 100644 (file)
@@ -42,7 +42,6 @@ struct dib0700_state {
        u16 mt2060_if1[2];
        u8 rc_toggle;
        u8 rc_counter;
-       u8 rc_func_version;
        u8 is_dib7000pc;
        u8 fw_use_new_i2c_api;
        u8 disable_streaming_master_mode;
index 0d3c9a9a33be4bd1bf74d7a51042592099b315de..4450214e2c6464f809ed1d70a64a27377bf9e886 100644 (file)
@@ -471,14 +471,208 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY_V1_20 10
+
+/* This is the structure of the RC response packet starting in firmware 1.20 */
+struct dib0700_rc_response {
+       u8 report_id;
+       u8 data_state;
+       u16 system;
+       u8 data;
+       u8 not_data;
+};
+#define RC_MSG_SIZE_V1_20 6
+
+static void dib0700_rc_urb_completion(struct urb *purb)
+{
+       struct dvb_usb_device *d = purb->context;
+       struct dvb_usb_rc_key *keymap;
+       struct dib0700_state *st;
+       struct dib0700_rc_response poll_reply;
+       u8 *buf;
+       int found = 0;
+       u32 event;
+       int state;
+       int i;
+
+       deb_info("%s()\n", __func__);
+       if (d == NULL)
+               return;
+
+       if (d->rc_input_dev == NULL) {
+               /* This will occur if disable_rc_polling=1 */
+               usb_free_urb(purb);
+               return;
+       }
+
+       keymap = d->props.rc_key_map;
+       st = d->priv;
+       buf = (u8 *)purb->transfer_buffer;
+
+       if (purb->status < 0) {
+               deb_info("discontinuing polling\n");
+               usb_free_urb(purb);
+               return;
+       }
+
+       if (purb->actual_length != RC_MSG_SIZE_V1_20) {
+               deb_info("malformed rc msg size=%d\n", purb->actual_length);
+               goto resubmit;
+       }
+
+       /* Set initial results in case we exit the function early */
+       event = 0;
+       state = REMOTE_NO_KEY_PRESSED;
+
+       deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
+                buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
+
+       switch (dvb_usb_dib0700_ir_proto) {
+       case 0:
+               /* NEC Protocol */
+               poll_reply.report_id  = 0;
+               poll_reply.data_state = 1;
+               poll_reply.system     = buf[2];
+               poll_reply.data       = buf[4];
+               poll_reply.not_data   = buf[5];
+
+               /* NEC protocol sends repeat code as 0 0 0 FF */
+               if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
+                   && (poll_reply.not_data == 0xff)) {
+                       poll_reply.data_state = 2;
+                       break;
+               }
+               break;
+       default:
+               /* RC5 Protocol */
+               poll_reply.report_id  = buf[0];
+               poll_reply.data_state = buf[1];
+               poll_reply.system     = (buf[2] << 8) | buf[3];
+               poll_reply.data       = buf[4];
+               poll_reply.not_data   = buf[5];
+               break;
+       }
+
+       if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+               /* Key failed integrity check */
+               err("key failed integrity check: %04x %02x %02x",
+                   poll_reply.system,
+                   poll_reply.data, poll_reply.not_data);
+               goto resubmit;
+       }
+
+       deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
+                poll_reply.report_id, poll_reply.data_state,
+                poll_reply.system, poll_reply.data, poll_reply.not_data);
+
+       /* Find the key in the map */
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
+                   rc5_data(&keymap[i]) == poll_reply.data) {
+                       event = keymap[i].event;
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found == 0) {
+               err("Unknown remote controller key: %04x %02x %02x",
+                   poll_reply.system, poll_reply.data, poll_reply.not_data);
+               d->last_event = 0;
+               goto resubmit;
+       }
+
+       if (poll_reply.data_state == 1) {
+               /* New key hit */
+               st->rc_counter = 0;
+               event = keymap[i].event;
+               state = REMOTE_KEY_PRESSED;
+               d->last_event = keymap[i].event;
+       } else if (poll_reply.data_state == 2) {
+               /* Key repeated */
+               st->rc_counter++;
+
+               /* prevents unwanted double hits */
+               if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
+                       event = d->last_event;
+                       state = REMOTE_KEY_PRESSED;
+                       st->rc_counter = RC_REPEAT_DELAY_V1_20;
+               }
+       } else {
+               err("Unknown data state [%d]", poll_reply.data_state);
+       }
+
+       switch (state) {
+       case REMOTE_NO_KEY_PRESSED:
+               break;
+       case REMOTE_KEY_PRESSED:
+               deb_info("key pressed\n");
+               d->last_event = event;
+       case REMOTE_KEY_REPEAT:
+               deb_info("key repeated\n");
+               input_event(d->rc_input_dev, EV_KEY, event, 1);
+               input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
+               input_sync(d->rc_input_dev);
+               break;
+       default:
+               break;
+       }
+
+resubmit:
+       /* Clean the buffer before we requeue */
+       memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
+
+       /* Requeue URB */
+       usb_submit_urb(purb, GFP_ATOMIC);
+}
+
 int dib0700_rc_setup(struct dvb_usb_device *d)
 {
+       struct dib0700_state *st = d->priv;
        u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
-       int i = dib0700_ctrl_wr(d, rc_setup, 3);
+       struct urb *purb;
+       int ret;
+       int i;
+
+       if (d->props.rc_key_map == NULL)
+               return 0;
+
+       /* Set the IR mode */
+       i = dib0700_ctrl_wr(d, rc_setup, 3);
        if (i<0) {
                err("ir protocol setup failed");
                return -1;
        }
+
+       if (st->fw_version < 0x10200)
+               return 0;
+
+       /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+       purb = usb_alloc_urb(0, GFP_KERNEL);
+       if (purb == NULL) {
+               err("rc usb alloc urb failed\n");
+               return -1;
+       }
+
+       purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
+       if (purb->transfer_buffer == NULL) {
+               err("rc kzalloc failed\n");
+               usb_free_urb(purb);
+               return -1;
+       }
+
+       purb->status = -EINPROGRESS;
+       usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
+                         purb->transfer_buffer, RC_MSG_SIZE_V1_20,
+                         dib0700_rc_urb_completion, d);
+
+       ret = usb_submit_urb(purb, GFP_ATOMIC);
+       if (ret != 0) {
+               err("rc submit urb failed\n");
+               return -1;
+       }
+
        return 0;
 }
 
index 44972d01bbd02fddc22b66e84b78dcad712cb21a..34eab05afc6cd08d83d74468f7614b9a5f2a3468 100644 (file)
@@ -472,20 +472,25 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY 6
-#define RC_REPEAT_DELAY_V1_20 10
 
-
-
-/* Used by firmware versions < 1.20 (deprecated) */
-static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
-                                  int *state)
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        u8 key[4];
        int i;
        struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
        struct dib0700_state *st = d->priv;
+
        *event = 0;
        *state = REMOTE_NO_KEY_PRESSED;
+
+       if (st->fw_version >= 0x10200) {
+               /* For 1.20 firmware , We need to keep the RC polling
+                  callback so we can reuse the input device setup in
+                  dvb-usb-remote.c.  However, the actual work is being done
+                  in the bulk URB completion handler. */
+               return 0;
+       }
+
        i=dib0700_ctrl_rd(d,rc_request,2,key,4);
        if (i<=0) {
                err("RC Query Failed");
@@ -557,149 +562,6 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
        return 0;
 }
 
-/* This is the structure of the RC response packet starting in firmware 1.20 */
-struct dib0700_rc_response {
-       u8 report_id;
-       u8 data_state;
-       u16 system;
-       u8 data;
-       u8 not_data;
-};
-
-/* This supports the new IR response format for firmware v1.20 */
-static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
-                                 int *state)
-{
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
-       struct dib0700_state *st = d->priv;
-       struct dib0700_rc_response poll_reply;
-       u8 buf[6];
-       int i;
-       int status;
-       int actlen;
-       int found = 0;
-
-       /* Set initial results in case we exit the function early */
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
-
-       /* Firmware v1.20 provides RC data via bulk endpoint 1 */
-       status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf,
-                             sizeof(buf), &actlen, 50);
-       if (status < 0) {
-               /* No data available (meaning no key press) */
-               return 0;
-       }
-
-
-       switch (dvb_usb_dib0700_ir_proto) {
-       case 0:
-               poll_reply.report_id  = 0;
-               poll_reply.data_state = 1;
-               poll_reply.system     = buf[2];
-               poll_reply.data       = buf[4];
-               poll_reply.not_data   = buf[5];
-
-               /* NEC protocol sends repeat code as 0 0 0 FF */
-               if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
-                   && (poll_reply.not_data == 0xff)) {
-                       poll_reply.data_state = 2;
-                       break;
-               }
-               break;
-       default:
-       if (actlen != sizeof(buf)) {
-               /* We didn't get back the 6 byte message we expected */
-               err("Unexpected RC response size [%d]", actlen);
-               return -1;
-       }
-
-       poll_reply.report_id  = buf[0];
-       poll_reply.data_state = buf[1];
-               poll_reply.system     = (buf[2] << 8) | buf[3];
-       poll_reply.data       = buf[4];
-       poll_reply.not_data   = buf[5];
-
-               break;
-       }
-
-       if ((poll_reply.data + poll_reply.not_data) != 0xff) {
-               /* Key failed integrity check */
-               err("key failed integrity check: %04x %02x %02x",
-                   poll_reply.system,
-                   poll_reply.data, poll_reply.not_data);
-               return -1;
-       }
-
-
-       /* Find the key in the map */
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
-                       rc5_data(&keymap[i]) == poll_reply.data) {
-                       *event = keymap[i].event;
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found == 0) {
-               err("Unknown remote controller key: %04x %02x %02x",
-                       poll_reply.system,
-                       poll_reply.data, poll_reply.not_data);
-               d->last_event = 0;
-               return 0;
-       }
-
-       if (poll_reply.data_state == 1) {
-               /* New key hit */
-               st->rc_counter = 0;
-               *event = keymap[i].event;
-               *state = REMOTE_KEY_PRESSED;
-               d->last_event = keymap[i].event;
-       } else if (poll_reply.data_state == 2) {
-               /* Key repeated */
-               st->rc_counter++;
-
-               /* prevents unwanted double hits */
-               if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
-                       *event = d->last_event;
-                       *state = REMOTE_KEY_PRESSED;
-                       st->rc_counter = RC_REPEAT_DELAY_V1_20;
-               }
-       } else {
-               err("Unknown data state [%d]", poll_reply.data_state);
-       }
-
-       return 0;
-}
-
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-       struct dib0700_state *st = d->priv;
-
-       /* Because some people may have improperly named firmware files,
-          let's figure out whether to use the new firmware call or the legacy
-          call based on the firmware version embedded in the file */
-       if (st->rc_func_version == 0) {
-               u32 hwver, romver, ramver, fwtype;
-               int ret = dib0700_get_version(d, &hwver, &romver, &ramver,
-                                             &fwtype);
-               if (ret < 0) {
-                       err("Could not determine version info");
-                       return -1;
-               }
-               if (ramver < 0x10200)
-                       st->rc_func_version = 1;
-               else
-                       st->rc_func_version = 2;
-       }
-
-       if (st->rc_func_version == 2)
-               return dib0700_rc_query_v1_20(d, event, state);
-       else
-               return dib0700_rc_query_legacy(d, event, state);
-}
-
 static struct dvb_usb_rc_key dib0700_rc_keys[] = {
        /* Key codes for the tiny Pinnacle remote*/
        { 0x0700, KEY_MUTE },