V4L/DVB (13930): dib0700: rework IR logic for firmware 1.20
[safe/jmp/linux-2.6] / drivers / media / dvb / dvb-usb / dib0700_core.c
index dd53cee..4450214 100644 (file)
@@ -17,8 +17,36 @@ 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).");
 
+static int nb_packet_buffer_size = 21;
+module_param(nb_packet_buffer_size, int, 0644);
+MODULE_PARM_DESC(nb_packet_buffer_size,
+       "Set the dib0700 driver data buffer size. This parameter "
+       "corresponds to the number of TS packets. The actual size of "
+       "the data buffer corresponds to this parameter "
+       "multiplied by 188 (default: 21)");
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+
+int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+                       u32 *romversion, u32 *ramversion, u32 *fwtype)
+{
+       u8 b[16];
+       int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+                                 REQUEST_GET_VERSION,
+                                 USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                                 b, sizeof(b), USB_CTRL_GET_TIMEOUT);
+       if (hwversion != NULL)
+               *hwversion  = (b[0] << 24)  | (b[1] << 16)  | (b[2] << 8)  | b[3];
+       if (romversion != NULL)
+               *romversion = (b[4] << 24)  | (b[5] << 16)  | (b[6] << 8)  | b[7];
+       if (ramversion != NULL)
+               *ramversion = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+       if (fwtype != NULL)
+               *fwtype     = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
+       return ret;
+}
+
 /* expecting rx buffer: request data[0] data[1] ... data[2] */
 static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
 {
@@ -81,6 +109,27 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
        return dib0700_ctrl_wr(d,buf,3);
 }
 
+static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+{
+    struct dib0700_state *st = d->priv;
+    u8 b[3];
+    int ret;
+
+    if (st->fw_version >= 0x10201) {
+       b[0] = REQUEST_SET_USB_XFER_LEN;
+       b[1] = (nb_ts_packets >> 8)&0xff;
+       b[2] = nb_ts_packets & 0xff;
+
+       deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+       ret = dib0700_ctrl_wr(d, b, 3);
+    } else {
+       deb_info("this firmware does not allow to change the USB xfer len\n");
+       ret = -EIO;
+    }
+    return ret;
+}
+
 /*
  * I2C master xfer function (supported in 1.20 firmware)
  */
@@ -142,6 +191,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                err("i2c read error (status = %d)\n", result);
                                break;
                        }
+
+                       deb_data("<<< ");
+                       debug_dump(msg[i].buf, msg[i].len, deb_data);
+
                } else {
                        /* Write request */
                        buf[0] = REQUEST_NEW_I2C_WRITE;
@@ -153,6 +206,9 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                        /* The Actual i2c payload */
                        memcpy(&buf[4], msg[i].buf, msg[i].len);
 
+                       deb_data(">>> ");
+                       debug_dump(buf, msg[i].len + 4, deb_data);
+
                        result = usb_control_msg(d->udev,
                                                 usb_sndctrlpipe(d->udev, 0),
                                                 REQUEST_NEW_I2C_WRITE,
@@ -195,7 +251,8 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
 
                        /* special thing in the current firmware: when length is zero the read-failed */
                        if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
-                               deb_info("I2C read failed on address %x\n", msg[i].addr);
+                               deb_info("I2C read failed on address 0x%02x\n",
+                                        msg[i].addr);
                                break;
                        }
 
@@ -304,7 +361,9 @@ static int dib0700_jumpram(struct usb_device *udev, u32 address)
 int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
        struct hexline hx;
-       int pos = 0, ret, act_len;
+       int pos = 0, ret, act_len, i, adap_num;
+       u8 b[16];
+       u32 fw_version;
 
        u8 buf[260];
 
@@ -340,6 +399,34 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
        } else
                ret = -EIO;
 
+       /* the number of ts packet has to be at least 1 */
+       if (nb_packet_buffer_size < 1)
+               nb_packet_buffer_size = 1;
+
+       /* get the fimware version */
+       usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                                 REQUEST_GET_VERSION,
+                                 USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                                 b, sizeof(b), USB_CTRL_GET_TIMEOUT);
+       fw_version = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+
+       /* set the buffer size - DVB-USB is allocating URB buffers
+        * only after the firwmare download was successful */
+       for (i = 0; i < dib0700_device_count; i++) {
+               for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
+                               adap_num++) {
+                       if (fw_version >= 0x10201)
+                               dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
+                       else {
+                               /* for fw version older than 1.20.1,
+                                * the buffersize has to be n times 512 */
+                               dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
+                               if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512)
+                                       dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512;
+                       }
+               }
+       }
+
        return ret;
 }
 
@@ -347,6 +434,18 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct dib0700_state *st = adap->dev->priv;
        u8 b[4];
+       int ret;
+
+       if ((onoff != 0) && (st->fw_version >= 0x10201)) {
+               /* for firmware later than 1.20.1,
+                * the USB xfer length can be set  */
+               ret = dib0700_set_usb_xfer_len(adap->dev,
+                       st->nb_packet_buffer_size);
+               if (ret < 0) {
+                       deb_info("can not set the USB xfer len\n");
+                       return ret;
+               }
+       }
 
        b[0] = REQUEST_ENABLE_VIDEO;
        b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
@@ -372,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;
 }
 
@@ -391,9 +684,21 @@ static int dib0700_probe(struct usb_interface *intf,
 
        for (i = 0; i < dib0700_device_count; i++)
                if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
-                                       &dev, adapter_nr) == 0)
-               {
+                   &dev, adapter_nr) == 0) {
+                       struct dib0700_state *st = dev->priv;
+                       u32 hwversion, romversion, fw_version, fwtype;
+
+                       dib0700_get_version(dev, &hwversion, &romversion,
+                               &fw_version, &fwtype);
+
+                       deb_info("Firmware version: %x, %d, 0x%x, %d\n",
+                               hwversion, romversion, fw_version, fwtype);
+
+                       st->fw_version = fw_version;
+                       st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
+
                        dib0700_rc_setup(dev);
+
                        return 0;
                }