fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / media / video / pvrusb2 / pvrusb2-i2c-core.c
index 7fca479..f9bb41d 100644 (file)
@@ -185,7 +185,78 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
        }
 }
 
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+
+/* This is a special entry point for cases of I2C transaction attempts to
+   the IR receiver.  The implementation here simulates the IR receiver by
+   issuing a command to the FX2 firmware and using that response to return
+   what the real I2C receiver would have returned.  We use this for 24xxx
+   devices, where the IR receiver chip has been removed and replaced with
+   FX2 related logic. */
+static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
+                       u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+       u8 dat[4];
+       unsigned int stat;
+
+       if (!(rlen || wlen)) {
+               /* This is a probe attempt.  Just let it succeed. */
+               return 0;
+       }
+
+       /* We don't understand this kind of transaction */
+       if ((wlen != 0) || (rlen == 0)) return -EIO;
+
+       if (rlen < 3) {
+               /* Mike Isely <isely@pobox.com> Appears to be a probe
+                  attempt from lirc.  Just fill in zeroes and return.  If
+                  we try instead to do the full transaction here, then bad
+                  things seem to happen within the lirc driver module
+                  (version 0.8.0-7 sources from Debian, when run under
+                  vanilla 2.6.17.6 kernel) - and I don't have the patience
+                  to chase it down. */
+               if (rlen > 0) rdata[0] = 0;
+               if (rlen > 1) rdata[1] = 0;
+               return 0;
+       }
+
+       /* Issue a command to the FX2 to read the IR receiver. */
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0xec;
+               stat = pvr2_send_request(hdw,
+                                        hdw->cmd_buffer,1,
+                                        hdw->cmd_buffer,4);
+               dat[0] = hdw->cmd_buffer[0];
+               dat[1] = hdw->cmd_buffer[1];
+               dat[2] = hdw->cmd_buffer[2];
+               dat[3] = hdw->cmd_buffer[3];
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+
+       /* Give up if that operation failed. */
+       if (stat != 0) return stat;
+
+       /* Mangle the results into something that looks like the real IR
+          receiver. */
+       rdata[2] = 0xc1;
+       if (dat[0] != 1) {
+               /* No code received. */
+               rdata[0] = 0;
+               rdata[1] = 0;
+       } else {
+               u16 val;
+               /* Mash the FX2 firmware-provided IR code into something
+                  that the normal i2c chip-level driver expects. */
+               val = dat[1];
+               val <<= 8;
+               val |= dat[2];
+               val >>= 1;
+               val &= ~0x0003;
+               val |= 0x8000;
+               rdata[0] = (val >> 8) & 0xffu;
+               rdata[1] = val & 0xffu;
+       }
+
+       return 0;
+}
 
 /* This is a special entry point that is entered if an I2C operation is
    attempted to a wm8775 chip on model 24xxx hardware.  Autodetect of this
@@ -289,8 +360,6 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
        return -EIO;
 }
 
-#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
-
 /* This is a very, very limited I2C adapter implementation.  We can only
    support what we actually know will work on the device... */
 static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -891,20 +960,18 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
 {
        unsigned int idx;
 
-       // The default action for all possible I2C addresses is just to do
-       // the transfer normally.
+       /* The default action for all possible I2C addresses is just to do
+          the transfer normally. */
        for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
                hdw->i2c_func[idx] = pvr2_i2c_basic_op;
        }
 
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
-       // If however we're dealing with new hardware, insert some hacks in
-       // the I2C transfer stack to let things work better.
+       /* However, deal with various special cases for 24xxx hardware. */
        if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
                hdw->i2c_func[0x1b] = i2c_hack_wm8775;
                hdw->i2c_func[0x44] = i2c_hack_cx25840;
+               hdw->i2c_func[0x18] = i2c_24xxx_ir;
        }
-#endif
 
        // Configure the adapter and set up everything else related to it.
        memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));