]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/dvb/dvb-usb/dib0700_devices.c
V4L/DVB (9639): Make dib0700 remote control support work with firmware v1.20
[linux-2.6-omap-h63xx.git] / drivers / media / dvb / dvb-usb / dib0700_devices.c
index 0cfccc24b1907acad9d4db7ea6f3d77b5a6e7a1a..f28d3ae59e046cd8e9d1d6c74565848ccb4a9833 100644 (file)
@@ -38,6 +38,7 @@ static struct mt2060_config bristol_mt2060_config[2] = {
        }
 };
 
+
 static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
        .band_caps = BAND_VHF | BAND_UHF,
        .setup     = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
@@ -451,8 +452,13 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY 2
+#define RC_REPEAT_DELAY_V1_20 5
 
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+
+
+/* Used by firmware versions < 1.20 (deprecated) */
+static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
+                                  int *state)
 {
        u8 key[4];
        int i;
@@ -529,6 +535,137 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        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;
+       u8 system_msb;
+       u8 system_lsb;
+       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;
+       }
+
+       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_msb = buf[2];
+       poll_reply.system_lsb = buf[3];
+       poll_reply.data       = buf[4];
+       poll_reply.not_data   = buf[5];
+
+       /*
+       info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n",
+            poll_reply.report_id, poll_reply.data_state,
+            poll_reply.system_msb, poll_reply.system_lsb,
+            poll_reply.data, poll_reply.not_data);
+       */
+
+       if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+               /* Key failed integrity check */
+               err("key failed integrity check: %02x %02x %02x %02x",
+                   poll_reply.system_msb, poll_reply.system_lsb,
+                   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 (keymap[i].custom == poll_reply.system_lsb &&
+                   keymap[i].data == poll_reply.data) {
+                       *event = keymap[i].event;
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found == 0) {
+               err("Unknown remote controller key: %02x %02x %02x %02x",
+                   poll_reply.system_msb, poll_reply.system_lsb,
+                   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*/
        { 0x07, 0x00, KEY_MUTE },