]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/dvb/dvb-usb/dib0700_core.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6-omap-h63xx.git] / drivers / media / dvb / dvb-usb / dib0700_core.c
index 595a04696c87af2590588bf87013a44b8e44aa7c..200b215f4d8b37f2441bd058b7f9b06f5cb25086 100644 (file)
@@ -19,6 +19,22 @@ MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (defau
 
 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);
+       *hwversion  = (b[0] << 24)  | (b[1] << 16)  | (b[2] << 8)  | b[3];
+       *romversion = (b[4] << 24)  | (b[5] << 16)  | (b[6] << 8)  | b[7];
+       *ramversion = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+       *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)
 {
@@ -82,9 +98,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
 }
 
 /*
- * I2C master xfer function
+ * I2C master xfer function (supported in 1.20 firmware)
+ */
+static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+                               int num)
+{
+       /* The new i2c firmware messages are more reliable and in particular
+          properly support i2c read calls not preceded by a write */
+
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       uint8_t bus_mode = 1;  /* 0=eeprom bus, 1=frontend bus */
+       uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
+       uint8_t en_start = 0;
+       uint8_t en_stop = 0;
+       uint8_t buf[255]; /* TBV: malloc ? */
+       int result, i;
+
+       /* Ensure nobody else hits the i2c bus while we're sending our
+          sequence of messages, (such as the remote control thread) */
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               if (i == 0) {
+                       /* First message in the transaction */
+                       en_start = 1;
+               } else if (!(msg[i].flags & I2C_M_NOSTART)) {
+                       /* Device supports repeated-start */
+                       en_start = 1;
+               } else {
+                       /* Not the first packet and device doesn't support
+                          repeated start */
+                       en_start = 0;
+               }
+               if (i == (num - 1)) {
+                       /* Last message in the transaction */
+                       en_stop = 1;
+               }
+
+               if (msg[i].flags & I2C_M_RD) {
+                       /* Read request */
+                       u16 index, value;
+                       uint8_t i2c_dest;
+
+                       i2c_dest = (msg[i].addr << 1);
+                       value = ((en_start << 7) | (en_stop << 6) |
+                                (msg[i].len & 0x3F)) << 8 | i2c_dest;
+                       /* I2C ctrl + FE bus; */
+                       index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+
+                       result = usb_control_msg(d->udev,
+                                                usb_rcvctrlpipe(d->udev, 0),
+                                                REQUEST_NEW_I2C_READ,
+                                                USB_TYPE_VENDOR | USB_DIR_IN,
+                                                value, index, msg[i].buf,
+                                                msg[i].len,
+                                                USB_CTRL_GET_TIMEOUT);
+                       if (result < 0) {
+                               err("i2c read error (status = %d)\n", result);
+                               break;
+                       }
+               } else {
+                       /* Write request */
+                       buf[0] = REQUEST_NEW_I2C_WRITE;
+                       buf[1] = (msg[i].addr << 1);
+                       buf[2] = (en_start << 7) | (en_stop << 6) |
+                               (msg[i].len & 0x3F);
+                       /* I2C ctrl + FE bus; */
+                       buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+                       /* The Actual i2c payload */
+                       memcpy(&buf[4], msg[i].buf, msg[i].len);
+
+                       result = usb_control_msg(d->udev,
+                                                usb_sndctrlpipe(d->udev, 0),
+                                                REQUEST_NEW_I2C_WRITE,
+                                                USB_TYPE_VENDOR | USB_DIR_OUT,
+                                                0, 0, buf, msg[i].len + 4,
+                                                USB_CTRL_GET_TIMEOUT);
+                       if (result < 0) {
+                               err("i2c write error (status = %d)\n", result);
+                               break;
+                       }
+               }
+       }
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+/*
+ * I2C master xfer function (pre-1.20 firmware)
  */
-static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
+static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+                                  struct i2c_msg *msg, int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i,len;
@@ -124,6 +229,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num
        return i;
 }
 
+static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+                           int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct dib0700_state *st = d->priv;
+
+       if (st->fw_use_new_i2c_api == 1) {
+               /* User running at least fw 1.20 */
+               return dib0700_i2c_xfer_new(adap, msg, num);
+       } else {
+               /* Use legacy calls */
+               return dib0700_i2c_xfer_legacy(adap, msg, num);
+       }
+}
+
 static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -246,7 +366,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
        b[0] = REQUEST_ENABLE_VIDEO;
        b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
-       b[2] = (0x01 << 4); /* Master mode */
+
+       if (st->disable_streaming_master_mode == 1)
+               b[2] = 0x00;
+       else
+               b[2] = (0x01 << 4); /* Master mode */
+
        b[3] = 0x00;
 
        deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);