Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[pandora-kernel.git] / drivers / media / video / pvrusb2 / pvrusb2-i2c-core.c
index d6a3540..9464862 100644 (file)
@@ -18,6 +18,7 @@
  *
  */
 
+#include <linux/i2c.h>
 #include "pvrusb2-i2c-core.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
@@ -29,8 +30,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 +42,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 +520,13 @@ 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) 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);
        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);
-       }
        return 0;
 }
 
@@ -942,7 +537,7 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
 
 static struct i2c_adapter pvr2_i2c_adap_template = {
        .owner         = THIS_MODULE,
-       .class     = I2C_CLASS_TV_ANALOG,
+       .class         = 0,
        .id            = I2C_HW_B_BT848,
        .client_register = pvr2_i2c_attach_inform,
        .client_unregister = pvr2_i2c_detach_inform,
@@ -1009,12 +604,8 @@ 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_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
        i2c_add_adapter(&hdw->i2c_adap);
        if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
                /* Probe for a different type of IR receiver on this