V4L/DVB (4763): Pvrusb2: Implement IR reception for 24xxx devices
authorMike Isely <isely@pobox.com>
Mon, 16 Oct 2006 00:35:14 +0000 (21:35 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 10 Dec 2006 10:50:58 +0000 (08:50 -0200)
Unlike 29xxx devices, the 24xxx model series does not have a dedicated
I2C device for reception of IR codes.  Instead IR is handled directly
by the FX2 microcontroller and the results are communicated via
commands to the FX2.  Rather than implement a whole new IR reception
pathway for 24xxx devices, this changeset instead emulates the
presence of the 29xxx device's I2C based IR receiver by intercepting
commands to that chip and issuing appropriate FX2 commands to do the
needed action.  This has the result of allowing all the usual IR
frameworks (ir-kbd-i2c or lirc) to continue working unmodified for
24xxx devices.

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c

index 3b9012f..f9bb41d 100644 (file)
@@ -185,6 +185,79 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
        }
 }
 
+
+/* 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
    part doesn't work, but we know it is really there.  So let's look for
@@ -887,17 +960,17 @@ 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;
        }
 
-       // 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;
        }
 
        // Configure the adapter and set up everything else related to it.