V4L/DVB (11154): pvrusb2: Split i2c module handling from i2c adapter
authorMike Isely <isely@pobox.com>
Sat, 7 Mar 2009 06:06:09 +0000 (03:06 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 30 Mar 2009 15:43:32 +0000 (12:43 -0300)
This is the first step in the effort to move the pvrusb2 driver over
to using the v4l2-subdev framework.  This commit involves mainly
splitting apart pvrusb2-i2c-core - part of it is the driver's I2C
adapter driver and the rest is the old i2c module handling logic.  The
i2c module handling junk is moved out to pvrusb2-i2c-track and various
header references are correspondingly updated.  Yes, this patch has a
huge pile of checkpatch complaints, but I'm NOT going to fix any of
it.  Why?  First, I'm moving a large chunk of existing code and I'm
not going to spend time adjusting it to match someone's idea of coding
style.  Second, in the end I expect all that moved code to go away by
the time the rework is done so wasting time on it now to adhere to the
standard is in the end a large waste of time.

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
14 files changed:
drivers/media/video/pvrusb2/Makefile
drivers/media/video/pvrusb2/pvrusb2-audio.h
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
drivers/media/video/pvrusb2/pvrusb2-debugifc.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
drivers/media/video/pvrusb2/pvrusb2-i2c-track.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-track.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-tuner.h
drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
drivers/media/video/pvrusb2/pvrusb2-wm8775.h

index 4fda2de..931d9d1 100644 (file)
@@ -3,6 +3,7 @@ obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
 obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
 
 pvrusb2-objs   := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+                  pvrusb2-i2c-track.o \
                   pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
                   pvrusb2-encoder.o pvrusb2-video-v4l.o \
                   pvrusb2-eeprom.o pvrusb2-tuner.o \
index ac54eed..f7f0a40 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __PVRUSB2_AUDIO_H
 #define __PVRUSB2_AUDIO_H
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
 
index 66abf77..f664f59 100644 (file)
@@ -34,7 +34,7 @@
 
 
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
 
index ca892fb..cc4ef89 100644 (file)
@@ -23,7 +23,7 @@
 #include "pvrusb2-debugifc.h"
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-debug.h"
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 struct debugifc_mask_item {
        const char *name;
index ed8a456..9441bcc 100644 (file)
@@ -29,6 +29,7 @@
 #include "pvrusb2-util.h"
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 #include "pvrusb2-tuner.h"
 #include "pvrusb2-eeprom.h"
 #include "pvrusb2-hdw-internal.h"
@@ -1990,6 +1991,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        }
 
        // This step MUST happen after the earlier powerup step.
+       pvr2_i2c_track_init(hdw);
        pvr2_i2c_core_init(hdw);
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
@@ -2501,6 +2503,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
        }
        pvr2_i2c_core_done(hdw);
+       pvr2_i2c_track_done(hdw);
        pvr2_hdw_remove_usb_stuff(hdw);
        mutex_lock(&pvr2_unit_mtx); do {
                if ((hdw->unit_number >= 0) &&
index 4cf980c..8f32c2e 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include <linux/kernel.h>
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
 #include "pvrusb2-i2c-cmd-v4l2.h"
index 69a63f2..8472637 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __PVRUSB2_CMD_V4L2_H
 #define __PVRUSB2_CMD_V4L2_H
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
index 57a0247..2ba429f 100644 (file)
@@ -18,7 +18,9 @@
  *
  */
 
+#include <linux/i2c.h>
 #include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
 #include "pvrusb2-fx2-cmd.h"
@@ -29,8 +31,7 @@
 /*
 
   This module attempts to implement a compliant I2C adapter for the pvrusb2
-  device.  By doing this we can then make use of existing functionality in
-  V4L (e.g. tuner.c) rather than rolling our own.
+  device.
 
 */
 
@@ -42,10 +43,6 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
 module_param_array(ir_mode, int, NULL, 0444);
 MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
 
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
-                                            unsigned int detail,
-                                            char *buf,unsigned int maxlen);
-
 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
                          u8 i2c_addr,      /* I2C address we're talking to */
                          u8 *data,         /* Data to write */
@@ -524,414 +521,15 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
-static int pvr2_i2c_core_singleton(struct i2c_client *cp,
-                                  unsigned int cmd,void *arg)
-{
-       int stat;
-       if (!cp) return -EINVAL;
-       if (!(cp->driver)) return -EINVAL;
-       if (!(cp->driver->command)) return -EINVAL;
-       if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
-       stat = cp->driver->command(cp,cmd,arg);
-       module_put(cp->driver->driver.owner);
-       return stat;
-}
-
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
-{
-       int stat;
-       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
-               char buf[100];
-               unsigned int cnt;
-               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
-                                              buf,sizeof(buf));
-               pvr2_trace(PVR2_TRACE_I2C_CMD,
-                          "i2c COMMAND (code=%u 0x%x) to %.*s",
-                          cmd,cmd,cnt,buf);
-       }
-       stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
-       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
-               char buf[100];
-               unsigned int cnt;
-               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
-                                              buf,sizeof(buf));
-               pvr2_trace(PVR2_TRACE_I2C_CMD,
-                          "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
-       }
-       return stat;
-}
-
-int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
-{
-       struct pvr2_i2c_client *cp, *ncp;
-       int stat = -EINVAL;
-
-       if (!hdw) return stat;
-
-       mutex_lock(&hdw->i2c_list_lock);
-       list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
-               if (!cp->recv_enable) continue;
-               mutex_unlock(&hdw->i2c_list_lock);
-               stat = pvr2_i2c_client_cmd(cp,cmd,arg);
-               mutex_lock(&hdw->i2c_list_lock);
-       }
-       mutex_unlock(&hdw->i2c_list_lock);
-       return stat;
-}
-
-
-static int handler_check(struct pvr2_i2c_client *cp)
-{
-       struct pvr2_i2c_handler *hp = cp->handler;
-       if (!hp) return 0;
-       if (!hp->func_table->check) return 0;
-       return hp->func_table->check(hp->func_data) != 0;
-}
-
-#define BUFSIZE 500
-
-
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
-{
-       struct pvr2_i2c_client *cp;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
-               memset(vtp,0,sizeof(*vtp));
-               list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                       if (!cp->detected_flag) continue;
-                       if (!cp->status_poll) continue;
-                       cp->status_poll(cp);
-               }
-               hdw->tuner_signal_stale = 0;
-               pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
-                          " type=%u strength=%u audio=0x%x cap=0x%x"
-                          " low=%u hi=%u",
-                          vtp->type,
-                          vtp->signal,vtp->rxsubchans,vtp->capability,
-                          vtp->rangelow,vtp->rangehigh);
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-
-/* Issue various I2C operations to bring chip-level drivers into sync with
-   state stored in this driver. */
-void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
-{
-       unsigned long msk;
-       unsigned int idx;
-       struct pvr2_i2c_client *cp, *ncp;
-
-       if (!hdw->i2c_linked) return;
-       if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
-               return;
-       }
-       mutex_lock(&hdw->i2c_list_lock); do {
-               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
-                       /* One or more I2C clients have attached since we
-                          last synced.  So scan the list and identify the
-                          new clients. */
-                       char *buf;
-                       unsigned int cnt;
-                       unsigned long amask = 0;
-                       buf = kmalloc(BUFSIZE,GFP_KERNEL);
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
-                       list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                               if (!cp->detected_flag) {
-                                       cp->ctl_mask = 0;
-                                       pvr2_i2c_probe(hdw,cp);
-                                       cp->detected_flag = !0;
-                                       msk = cp->ctl_mask;
-                                       cnt = 0;
-                                       if (buf) {
-                                               cnt = pvr2_i2c_client_describe(
-                                                       cp,
-                                                       PVR2_I2C_DETAIL_ALL,
-                                                       buf,BUFSIZE);
-                                       }
-                                       trace_i2c("Probed: %.*s",cnt,buf);
-                                       if (handler_check(cp)) {
-                                               hdw->i2c_pend_types |=
-                                                       PVR2_I2C_PEND_CLIENT;
-                                       }
-                                       cp->pend_mask = msk;
-                                       hdw->i2c_pend_mask |= msk;
-                                       hdw->i2c_pend_types |=
-                                               PVR2_I2C_PEND_REFRESH;
-                               }
-                               amask |= cp->ctl_mask;
-                       }
-                       hdw->i2c_active_mask = amask;
-                       if (buf) kfree(buf);
-               }
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
-                       /* Need to do one or more global updates.  Arrange
-                          for this to happen. */
-                       unsigned long m2;
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,
-                                  "i2c: PEND_STALE (0x%lx)",
-                                  hdw->i2c_stale_mask);
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
-                       list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                               m2 = hdw->i2c_stale_mask;
-                               m2 &= cp->ctl_mask;
-                               m2 &= ~cp->pend_mask;
-                               if (m2) {
-                                       pvr2_trace(PVR2_TRACE_I2C_CORE,
-                                                  "i2c: cp=%p setting 0x%lx",
-                                                  cp,m2);
-                                       cp->pend_mask |= m2;
-                               }
-                       }
-                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
-                       hdw->i2c_stale_mask = 0;
-                       hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
-               }
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
-                       /* One or more client handlers are asking for an
-                          update.  Run through the list of known clients
-                          and update each one. */
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
-                       list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
-                                                list) {
-                               if (!cp->handler) continue;
-                               if (!cp->handler->func_table->update) continue;
-                               pvr2_trace(PVR2_TRACE_I2C_CORE,
-                                          "i2c: cp=%p update",cp);
-                               mutex_unlock(&hdw->i2c_list_lock);
-                               cp->handler->func_table->update(
-                                       cp->handler->func_data);
-                               mutex_lock(&hdw->i2c_list_lock);
-                               /* If client's update function set some
-                                  additional pending bits, account for that
-                                  here. */
-                               if (cp->pend_mask & ~hdw->i2c_pend_mask) {
-                                       hdw->i2c_pend_mask |= cp->pend_mask;
-                                       hdw->i2c_pend_types |=
-                                               PVR2_I2C_PEND_REFRESH;
-                               }
-                       }
-               }
-               if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
-                       const struct pvr2_i2c_op *opf;
-                       unsigned long pm;
-                       /* Some actual updates are pending.  Walk through
-                          each update type and perform it. */
-                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
-                                  " (0x%lx)",hdw->i2c_pend_mask);
-                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
-                       pm = hdw->i2c_pend_mask;
-                       hdw->i2c_pend_mask = 0;
-                       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
-                               if (!(pm & msk)) continue;
-                               pm &= ~msk;
-                               list_for_each_entry(cp, &hdw->i2c_clients,
-                                                   list) {
-                                       if (cp->pend_mask & msk) {
-                                               cp->pend_mask &= ~msk;
-                                               cp->recv_enable = !0;
-                                       } else {
-                                               cp->recv_enable = 0;
-                                       }
-                               }
-                               opf = pvr2_i2c_get_op(idx);
-                               if (!opf) continue;
-                               mutex_unlock(&hdw->i2c_list_lock);
-                               opf->update(hdw);
-                               mutex_lock(&hdw->i2c_list_lock);
-                       }
-               }
-               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
-{
-       unsigned long msk,sm,pm;
-       unsigned int idx;
-       const struct pvr2_i2c_op *opf;
-       struct pvr2_i2c_client *cp;
-       unsigned int pt = 0;
-
-       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
-
-       pm = hdw->i2c_active_mask;
-       sm = 0;
-       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
-               if (!(msk & pm)) continue;
-               pm &= ~msk;
-               opf = pvr2_i2c_get_op(idx);
-               if (!(opf && opf->check)) continue;
-               if (opf->check(hdw)) {
-                       sm |= msk;
-               }
-       }
-       if (sm) pt |= PVR2_I2C_PEND_STALE;
-
-       list_for_each_entry(cp, &hdw->i2c_clients, list)
-               if (handler_check(cp))
-                       pt |= PVR2_I2C_PEND_CLIENT;
-
-       if (pt) {
-               mutex_lock(&hdw->i2c_list_lock); do {
-                       hdw->i2c_pend_types |= pt;
-                       hdw->i2c_stale_mask |= sm;
-                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
-               } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       }
-
-       pvr2_trace(PVR2_TRACE_I2C_CORE,
-                  "i2c: types=0x%x stale=0x%lx pend=0x%lx",
-                  hdw->i2c_pend_types,
-                  hdw->i2c_stale_mask,
-                  hdw->i2c_pend_mask);
-       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
-
-       return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
-}
-
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
-                                            unsigned int detail,
-                                            char *buf,unsigned int maxlen)
-{
-       unsigned int ccnt,bcnt;
-       int spcfl = 0;
-       const struct pvr2_i2c_op *opf;
-
-       ccnt = 0;
-       if (detail & PVR2_I2C_DETAIL_DEBUG) {
-               bcnt = scnprintf(buf,maxlen,
-                                "ctxt=%p ctl_mask=0x%lx",
-                                cp,cp->ctl_mask);
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               spcfl = !0;
-       }
-       bcnt = scnprintf(buf,maxlen,
-                        "%s%s @ 0x%x",
-                        (spcfl ? " " : ""),
-                        cp->client->name,
-                        cp->client->addr);
-       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-       if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
-           cp->handler && cp->handler->func_table->describe) {
-               bcnt = scnprintf(buf,maxlen," (");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               bcnt = cp->handler->func_table->describe(
-                       cp->handler->func_data,buf,maxlen);
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               bcnt = scnprintf(buf,maxlen,")");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-       }
-       if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
-               unsigned int idx;
-               unsigned long msk,sm;
-
-               bcnt = scnprintf(buf,maxlen," [");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               sm = 0;
-               spcfl = 0;
-               for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
-                       if (!(cp->ctl_mask & msk)) continue;
-                       opf = pvr2_i2c_get_op(idx);
-                       if (opf) {
-                               bcnt = scnprintf(buf,maxlen,"%s%s",
-                                                spcfl ? " " : "",
-                                                opf->name);
-                               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-                               spcfl = !0;
-                       } else {
-                               sm |= msk;
-                       }
-               }
-               if (sm) {
-                       bcnt = scnprintf(buf,maxlen,"%s%lx",
-                                        idx != 0 ? " " : "",sm);
-                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               }
-               bcnt = scnprintf(buf,maxlen,"]");
-               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-       }
-       return ccnt;
-}
-
-unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
-                            char *buf,unsigned int maxlen)
-{
-       unsigned int ccnt,bcnt;
-       struct pvr2_i2c_client *cp;
-       ccnt = 0;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                       bcnt = pvr2_i2c_client_describe(
-                               cp,
-                               (PVR2_I2C_DETAIL_HANDLER|
-                                PVR2_I2C_DETAIL_CTLMASK),
-                               buf,maxlen);
-                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-                       bcnt = scnprintf(buf,maxlen,"\n");
-                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
-               }
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       return ccnt;
-}
-
 static int pvr2_i2c_attach_inform(struct i2c_client *client)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
-       struct pvr2_i2c_client *cp;
-       int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
-       cp = kzalloc(sizeof(*cp),GFP_KERNEL);
-       trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
-                 client->name,
-                 client->addr,cp);
-       if (!cp) return -ENOMEM;
-       cp->hdw = hdw;
-       INIT_LIST_HEAD(&cp->list);
-       cp->client = client;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               hdw->cropcap_stale = !0;
-               list_add_tail(&cp->list,&hdw->i2c_clients);
-               hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
+       pvr2_i2c_track_attach_inform(client);
        return 0;
 }
 
 static int pvr2_i2c_detach_inform(struct i2c_client *client)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
-       struct pvr2_i2c_client *cp, *ncp;
-       unsigned long amask = 0;
-       int foundfl = 0;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               hdw->cropcap_stale = !0;
-               list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
-                       if (cp->client == client) {
-                               trace_i2c("pvr2_i2c_detach"
-                                         " [client=%s @ 0x%x ctxt=%p]",
-                                         client->name,
-                                         client->addr,cp);
-                               if (cp->handler &&
-                                   cp->handler->func_table->detach) {
-                                       cp->handler->func_table->detach(
-                                               cp->handler->func_data);
-                               }
-                               list_del(&cp->list);
-                               kfree(cp);
-                               foundfl = !0;
-                               continue;
-                       }
-                       amask |= cp->ctl_mask;
-               }
-               hdw->i2c_active_mask = amask;
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       if (!foundfl) {
-               trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
-                         client->name,
-                         client->addr);
-       }
+       pvr2_i2c_track_detach_inform(client);
        return 0;
 }
 
@@ -1009,11 +607,6 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
        hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
        hdw->i2c_adap.algo = &hdw->i2c_algo;
        hdw->i2c_adap.algo_data = hdw;
-       hdw->i2c_pend_mask = 0;
-       hdw->i2c_stale_mask = 0;
-       hdw->i2c_active_mask = 0;
-       INIT_LIST_HEAD(&hdw->i2c_clients);
-       mutex_init(&hdw->i2c_list_lock);
        hdw->i2c_linked = !0;
        i2c_add_adapter(&hdw->i2c_adap);
        if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
index 6ef7a1c..6a75769 100644 (file)
 #ifndef __PVRUSB2_I2C_CORE_H
 #define __PVRUSB2_I2C_CORE_H
 
-#include <linux/list.h>
-#include <linux/i2c.h>
-
 struct pvr2_hdw;
-struct pvr2_i2c_client;
-struct pvr2_i2c_handler;
-struct pvr2_i2c_handler_functions;
-struct pvr2_i2c_op;
-struct pvr2_i2c_op_functions;
-
-struct pvr2_i2c_client {
-       struct i2c_client *client;
-       struct pvr2_i2c_handler *handler;
-       struct list_head list;
-       struct pvr2_hdw *hdw;
-       int detected_flag;
-       int recv_enable;
-       unsigned long pend_mask;
-       unsigned long ctl_mask;
-       void (*status_poll)(struct pvr2_i2c_client *);
-};
-
-struct pvr2_i2c_handler {
-       void *func_data;
-       const struct pvr2_i2c_handler_functions *func_table;
-};
-
-struct pvr2_i2c_handler_functions {
-       void (*detach)(void *);
-       int (*check)(void *);
-       void (*update)(void *);
-       unsigned int (*describe)(void *,char *,unsigned int);
-};
-
-struct pvr2_i2c_op {
-       int (*check)(struct pvr2_hdw *);
-       void (*update)(struct pvr2_hdw *);
-       const char *name;
-};
 
 void pvr2_i2c_core_init(struct pvr2_hdw *);
 void pvr2_i2c_core_done(struct pvr2_hdw *);
 
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
-int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
-void pvr2_i2c_core_sync(struct pvr2_hdw *);
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
-unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
-#define PVR2_I2C_DETAIL_DEBUG   0x0001
-#define PVR2_I2C_DETAIL_HANDLER 0x0002
-#define PVR2_I2C_DETAIL_CTLMASK 0x0004
-#define PVR2_I2C_DETAIL_ALL (\
-       PVR2_I2C_DETAIL_DEBUG |\
-       PVR2_I2C_DETAIL_HANDLER |\
-       PVR2_I2C_DETAIL_CTLMASK)
-
-void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
 
-#endif /* __PVRUSB2_I2C_CORE_H */
+#endif /* __PVRUSB2_I2C_ADAPTER_H */
 
 
 /*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
new file mode 100644 (file)
index 0000000..48cffa4
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ *
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-i2c-track.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
+#include "pvrusb2.h"
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+/*
+
+  This module implements the foundation of a rather large architecture for
+  tracking state in all the various V4L I2C modules.  This is obsolete with
+  kernels later than roughly 2.6.24, but it is still present in the
+  standalone pvrusb2 driver to allow continued operation with older
+  kernel.
+
+*/
+
+static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+                                            unsigned int detail,
+                                            char *buf,unsigned int maxlen);
+
+static int pvr2_i2c_core_singleton(struct i2c_client *cp,
+                                  unsigned int cmd,void *arg)
+{
+       int stat;
+       if (!cp) return -EINVAL;
+       if (!(cp->driver)) return -EINVAL;
+       if (!(cp->driver->command)) return -EINVAL;
+       if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
+       stat = cp->driver->command(cp,cmd,arg);
+       module_put(cp->driver->driver.owner);
+       return stat;
+}
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
+{
+       int stat;
+       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+               char buf[100];
+               unsigned int cnt;
+               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+                                              buf,sizeof(buf));
+               pvr2_trace(PVR2_TRACE_I2C_CMD,
+                          "i2c COMMAND (code=%u 0x%x) to %.*s",
+                          cmd,cmd,cnt,buf);
+       }
+       stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
+       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+               char buf[100];
+               unsigned int cnt;
+               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+                                              buf,sizeof(buf));
+               pvr2_trace(PVR2_TRACE_I2C_CMD,
+                          "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
+       }
+       return stat;
+}
+
+int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
+{
+       struct pvr2_i2c_client *cp, *ncp;
+       int stat = -EINVAL;
+
+       if (!hdw) return stat;
+
+       mutex_lock(&hdw->i2c_list_lock);
+       list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
+               if (!cp->recv_enable) continue;
+               mutex_unlock(&hdw->i2c_list_lock);
+               stat = pvr2_i2c_client_cmd(cp,cmd,arg);
+               mutex_lock(&hdw->i2c_list_lock);
+       }
+       mutex_unlock(&hdw->i2c_list_lock);
+       return stat;
+}
+
+
+static int handler_check(struct pvr2_i2c_client *cp)
+{
+       struct pvr2_i2c_handler *hp = cp->handler;
+       if (!hp) return 0;
+       if (!hp->func_table->check) return 0;
+       return hp->func_table->check(hp->func_data) != 0;
+}
+
+#define BUFSIZE 500
+
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+       struct pvr2_i2c_client *cp;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+               memset(vtp,0,sizeof(*vtp));
+               list_for_each_entry(cp, &hdw->i2c_clients, list) {
+                       if (!cp->detected_flag) continue;
+                       if (!cp->status_poll) continue;
+                       cp->status_poll(cp);
+               }
+               hdw->tuner_signal_stale = 0;
+               pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+                          " type=%u strength=%u audio=0x%x cap=0x%x"
+                          " low=%u hi=%u",
+                          vtp->type,
+                          vtp->signal,vtp->rxsubchans,vtp->capability,
+                          vtp->rangelow,vtp->rangehigh);
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+   state stored in this driver. */
+void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
+{
+       unsigned long msk;
+       unsigned int idx;
+       struct pvr2_i2c_client *cp, *ncp;
+
+       if (!hdw->i2c_linked) return;
+       if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
+               return;
+       }
+       mutex_lock(&hdw->i2c_list_lock); do {
+               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
+                       /* One or more I2C clients have attached since we
+                          last synced.  So scan the list and identify the
+                          new clients. */
+                       char *buf;
+                       unsigned int cnt;
+                       unsigned long amask = 0;
+                       buf = kmalloc(BUFSIZE,GFP_KERNEL);
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
+                       list_for_each_entry(cp, &hdw->i2c_clients, list) {
+                               if (!cp->detected_flag) {
+                                       cp->ctl_mask = 0;
+                                       pvr2_i2c_probe(hdw,cp);
+                                       cp->detected_flag = !0;
+                                       msk = cp->ctl_mask;
+                                       cnt = 0;
+                                       if (buf) {
+                                               cnt = pvr2_i2c_client_describe(
+                                                       cp,
+                                                       PVR2_I2C_DETAIL_ALL,
+                                                       buf,BUFSIZE);
+                                       }
+                                       trace_i2c("Probed: %.*s",cnt,buf);
+                                       if (handler_check(cp)) {
+                                               hdw->i2c_pend_types |=
+                                                       PVR2_I2C_PEND_CLIENT;
+                                       }
+                                       cp->pend_mask = msk;
+                                       hdw->i2c_pend_mask |= msk;
+                                       hdw->i2c_pend_types |=
+                                               PVR2_I2C_PEND_REFRESH;
+                               }
+                               amask |= cp->ctl_mask;
+                       }
+                       hdw->i2c_active_mask = amask;
+                       if (buf) kfree(buf);
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
+                       /* Need to do one or more global updates.  Arrange
+                          for this to happen. */
+                       unsigned long m2;
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                  "i2c: PEND_STALE (0x%lx)",
+                                  hdw->i2c_stale_mask);
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
+                       list_for_each_entry(cp, &hdw->i2c_clients, list) {
+                               m2 = hdw->i2c_stale_mask;
+                               m2 &= cp->ctl_mask;
+                               m2 &= ~cp->pend_mask;
+                               if (m2) {
+                                       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                                  "i2c: cp=%p setting 0x%lx",
+                                                  cp,m2);
+                                       cp->pend_mask |= m2;
+                               }
+                       }
+                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+                       hdw->i2c_stale_mask = 0;
+                       hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
+                       /* One or more client handlers are asking for an
+                          update.  Run through the list of known clients
+                          and update each one. */
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
+                       list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
+                                                list) {
+                               if (!cp->handler) continue;
+                               if (!cp->handler->func_table->update) continue;
+                               pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                          "i2c: cp=%p update",cp);
+                               mutex_unlock(&hdw->i2c_list_lock);
+                               cp->handler->func_table->update(
+                                       cp->handler->func_data);
+                               mutex_lock(&hdw->i2c_list_lock);
+                               /* If client's update function set some
+                                  additional pending bits, account for that
+                                  here. */
+                               if (cp->pend_mask & ~hdw->i2c_pend_mask) {
+                                       hdw->i2c_pend_mask |= cp->pend_mask;
+                                       hdw->i2c_pend_types |=
+                                               PVR2_I2C_PEND_REFRESH;
+                               }
+                       }
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
+                       const struct pvr2_i2c_op *opf;
+                       unsigned long pm;
+                       /* Some actual updates are pending.  Walk through
+                          each update type and perform it. */
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
+                                  " (0x%lx)",hdw->i2c_pend_mask);
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
+                       pm = hdw->i2c_pend_mask;
+                       hdw->i2c_pend_mask = 0;
+                       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+                               if (!(pm & msk)) continue;
+                               pm &= ~msk;
+                               list_for_each_entry(cp, &hdw->i2c_clients,
+                                                   list) {
+                                       if (cp->pend_mask & msk) {
+                                               cp->pend_mask &= ~msk;
+                                               cp->recv_enable = !0;
+                                       } else {
+                                               cp->recv_enable = 0;
+                                       }
+                               }
+                               opf = pvr2_i2c_get_op(idx);
+                               if (!opf) continue;
+                               mutex_unlock(&hdw->i2c_list_lock);
+                               opf->update(hdw);
+                               mutex_lock(&hdw->i2c_list_lock);
+                       }
+               }
+               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
+{
+       unsigned long msk,sm,pm;
+       unsigned int idx;
+       const struct pvr2_i2c_op *opf;
+       struct pvr2_i2c_client *cp;
+       unsigned int pt = 0;
+
+       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
+
+       pm = hdw->i2c_active_mask;
+       sm = 0;
+       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+               if (!(msk & pm)) continue;
+               pm &= ~msk;
+               opf = pvr2_i2c_get_op(idx);
+               if (!(opf && opf->check)) continue;
+               if (opf->check(hdw)) {
+                       sm |= msk;
+               }
+       }
+       if (sm) pt |= PVR2_I2C_PEND_STALE;
+
+       list_for_each_entry(cp, &hdw->i2c_clients, list)
+               if (handler_check(cp))
+                       pt |= PVR2_I2C_PEND_CLIENT;
+
+       if (pt) {
+               mutex_lock(&hdw->i2c_list_lock); do {
+                       hdw->i2c_pend_types |= pt;
+                       hdw->i2c_stale_mask |= sm;
+                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+               } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       }
+
+       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                  "i2c: types=0x%x stale=0x%lx pend=0x%lx",
+                  hdw->i2c_pend_types,
+                  hdw->i2c_stale_mask,
+                  hdw->i2c_pend_mask);
+       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
+
+       return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
+}
+
+static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+                                            unsigned int detail,
+                                            char *buf,unsigned int maxlen)
+{
+       unsigned int ccnt,bcnt;
+       int spcfl = 0;
+       const struct pvr2_i2c_op *opf;
+
+       ccnt = 0;
+       if (detail & PVR2_I2C_DETAIL_DEBUG) {
+               bcnt = scnprintf(buf,maxlen,
+                                "ctxt=%p ctl_mask=0x%lx",
+                                cp,cp->ctl_mask);
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               spcfl = !0;
+       }
+       bcnt = scnprintf(buf,maxlen,
+                        "%s%s @ 0x%x",
+                        (spcfl ? " " : ""),
+                        cp->client->name,
+                        cp->client->addr);
+       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
+           cp->handler && cp->handler->func_table->describe) {
+               bcnt = scnprintf(buf,maxlen," (");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               bcnt = cp->handler->func_table->describe(
+                       cp->handler->func_data,buf,maxlen);
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               bcnt = scnprintf(buf,maxlen,")");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       }
+       if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
+               unsigned int idx;
+               unsigned long msk,sm;
+
+               bcnt = scnprintf(buf,maxlen," [");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               sm = 0;
+               spcfl = 0;
+               for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
+                       if (!(cp->ctl_mask & msk)) continue;
+                       opf = pvr2_i2c_get_op(idx);
+                       if (opf) {
+                               bcnt = scnprintf(buf,maxlen,"%s%s",
+                                                spcfl ? " " : "",
+                                                opf->name);
+                               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+                               spcfl = !0;
+                       } else {
+                               sm |= msk;
+                       }
+               }
+               if (sm) {
+                       bcnt = scnprintf(buf,maxlen,"%s%lx",
+                                        idx != 0 ? " " : "",sm);
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               }
+               bcnt = scnprintf(buf,maxlen,"]");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       }
+       return ccnt;
+}
+
+unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
+                            char *buf,unsigned int maxlen)
+{
+       unsigned int ccnt,bcnt;
+       struct pvr2_i2c_client *cp;
+       ccnt = 0;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_for_each_entry(cp, &hdw->i2c_clients, list) {
+                       bcnt = pvr2_i2c_client_describe(
+                               cp,
+                               (PVR2_I2C_DETAIL_HANDLER|
+                                PVR2_I2C_DETAIL_CTLMASK),
+                               buf,maxlen);
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+                       bcnt = scnprintf(buf,maxlen,"\n");
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               }
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       return ccnt;
+}
+
+void pvr2_i2c_track_attach_inform(struct i2c_client *client)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+       struct pvr2_i2c_client *cp;
+       int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
+       cp = kzalloc(sizeof(*cp),GFP_KERNEL);
+       trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
+                 client->name,
+                 client->addr,cp);
+       if (!cp) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                       "Unable to allocate tracking memory for incoming"
+                          " i2c module; ignoring module.  This is likely"
+                          " going to be a problem.");
+               return;
+       }
+       cp->hdw = hdw;
+       INIT_LIST_HEAD(&cp->list);
+       cp->client = client;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               hdw->cropcap_stale = !0;
+               list_add_tail(&cp->list,&hdw->i2c_clients);
+               hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
+}
+
+void pvr2_i2c_track_detach_inform(struct i2c_client *client)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+       struct pvr2_i2c_client *cp, *ncp;
+       unsigned long amask = 0;
+       int foundfl = 0;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               hdw->cropcap_stale = !0;
+               list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
+                       if (cp->client == client) {
+                               trace_i2c("pvr2_i2c_detach"
+                                         " [client=%s @ 0x%x ctxt=%p]",
+                                         client->name,
+                                         client->addr,cp);
+                               if (cp->handler &&
+                                   cp->handler->func_table->detach) {
+                                       cp->handler->func_table->detach(
+                                               cp->handler->func_data);
+                               }
+                               list_del(&cp->list);
+                               kfree(cp);
+                               foundfl = !0;
+                               continue;
+                       }
+                       amask |= cp->ctl_mask;
+               }
+               hdw->i2c_active_mask = amask;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       if (!foundfl) {
+               trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
+                         client->name,
+                         client->addr);
+       }
+}
+
+void pvr2_i2c_track_init(struct pvr2_hdw *hdw)
+{
+       hdw->i2c_pend_mask = 0;
+       hdw->i2c_stale_mask = 0;
+       hdw->i2c_active_mask = 0;
+       INIT_LIST_HEAD(&hdw->i2c_clients);
+       mutex_init(&hdw->i2c_list_lock);
+}
+
+void pvr2_i2c_track_done(struct pvr2_hdw *hdw)
+{
+       /* Empty for now */
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h
new file mode 100644 (file)
index 0000000..7d0e4fb
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_I2C_TRACK_H
+#define __PVRUSB2_I2C_TRACK_H
+
+#include <linux/list.h>
+#include <linux/i2c.h>
+
+struct pvr2_hdw;
+struct pvr2_i2c_client;
+struct pvr2_i2c_handler;
+struct pvr2_i2c_handler_functions;
+struct pvr2_i2c_op;
+struct pvr2_i2c_op_functions;
+
+struct pvr2_i2c_client {
+       struct i2c_client *client;
+       struct pvr2_i2c_handler *handler;
+       struct list_head list;
+       struct pvr2_hdw *hdw;
+       int detected_flag;
+       int recv_enable;
+       unsigned long pend_mask;
+       unsigned long ctl_mask;
+       void (*status_poll)(struct pvr2_i2c_client *);
+};
+
+struct pvr2_i2c_handler {
+       void *func_data;
+       const struct pvr2_i2c_handler_functions *func_table;
+};
+
+struct pvr2_i2c_handler_functions {
+       void (*detach)(void *);
+       int (*check)(void *);
+       void (*update)(void *);
+       unsigned int (*describe)(void *,char *,unsigned int);
+};
+
+struct pvr2_i2c_op {
+       int (*check)(struct pvr2_hdw *);
+       void (*update)(struct pvr2_hdw *);
+       const char *name;
+};
+
+void pvr2_i2c_track_init(struct pvr2_hdw *);
+void pvr2_i2c_track_done(struct pvr2_hdw *);
+void pvr2_i2c_track_attach_inform(struct i2c_client *);
+void pvr2_i2c_track_detach_inform(struct i2c_client *);
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
+int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
+void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
+unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
+#define PVR2_I2C_DETAIL_DEBUG   0x0001
+#define PVR2_I2C_DETAIL_HANDLER 0x0002
+#define PVR2_I2C_DETAIL_CTLMASK 0x0004
+#define PVR2_I2C_DETAIL_ALL (\
+       PVR2_I2C_DETAIL_DEBUG |\
+       PVR2_I2C_DETAIL_HANDLER |\
+       PVR2_I2C_DETAIL_CTLMASK)
+
+void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
+
+#endif /* __PVRUSB2_I2C_CORE_H */
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
index ef4afaf..3643e2c 100644 (file)
@@ -20,7 +20,7 @@
 #ifndef __PVRUSB2_TUNER_H
 #define __PVRUSB2_TUNER_H
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
 
index 4ff5b89..b2cd387 100644 (file)
@@ -33,7 +33,7 @@
 
 
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
 
index 8070909..5b2cb61 100644 (file)
@@ -34,7 +34,7 @@
 
 
 
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-i2c-track.h"
 
 int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);