summaryrefslogtreecommitdiff
path: root/v4l_experimental/pvrusb2/pvrusb2-i2c-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'v4l_experimental/pvrusb2/pvrusb2-i2c-core.c')
-rw-r--r--v4l_experimental/pvrusb2/pvrusb2-i2c-core.c769
1 files changed, 0 insertions, 769 deletions
diff --git a/v4l_experimental/pvrusb2/pvrusb2-i2c-core.c b/v4l_experimental/pvrusb2/pvrusb2-i2c-core.c
deleted file mode 100644
index b45463a2d..000000000
--- a/v4l_experimental/pvrusb2/pvrusb2-i2c-core.c
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- *
- * $Id: pvrusb2-i2c-core.c,v 1.5 2006/01/23 06:58:06 mcisely Exp $
- *
- * 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 "compat.h"
-#include "pvrusb2-i2c-core.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-
-#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
-
-/*
-
- 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.
-
-*/
-
-static unsigned int i2c_scan = 0;
-module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
-
-static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
- u8 i2c_addr, /* I2C address we're talking to */
- u8 *data, /* Data to write */
- u16 length) /* Size of data to write */
-{
- /* Return value - default 0 means success */
- int ret;
-
-#ifdef notdef
- trace_i2c("pvr2_i2c_write");
-#endif
-
- if (!data) length = 0;
- if (length > (sizeof(hdw->cmd_buffer) - 3)) return -ENOTSUPP;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- /* Clear the command buffer (likely to be paranoia) */
- memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
-
- /* Set up command buffer for an I2C write */
- hdw->cmd_buffer[0] = 0x08; /* write prefix */
- hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
- hdw->cmd_buffer[2] = length; /* length of what follows */
- if (length) memcpy(hdw->cmd_buffer + 3, data, length);
-
- /* Do the operation */
- ret = pvr2_send_request(hdw,
- hdw->cmd_buffer,
- length + 3,
- hdw->cmd_buffer,
- 1);
- if (!ret) {
- if (hdw->cmd_buffer[0] != 8) {
- ret = -EIO;
- if (hdw->cmd_buffer[0] != 7) {
- trace_i2c("unexpected status"
- " from i2_write[%d]: %d",
- i2c_addr,hdw->cmd_buffer[0]);
- }
- }
- }
-#ifdef notdef
- trace_i2c("i2c_write(%d) len=%d ret=%d stat=%d",i2c_addr,length,ret,
- hdw->cmd_buffer[0]);
-#endif
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
- u8 i2c_addr, /* I2C address we're talking to */
- u8 *data, /* Data to write */
- u16 dlen, /* Size of data to write */
- u8 *res, /* Where to put data we read */
- u16 rlen) /* Amount of data to read */
-{
- /* Return value - default 0 means success */
- int ret;
-
-#ifdef notdef
- trace_i2c("pvr2_i2c_read");
-#endif
-
- if (!data) dlen = 0;
- if (dlen > (sizeof(hdw->cmd_buffer) - 4)) return -ENOTSUPP;
- if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) return -ENOTSUPP;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- /* Clear the command buffer (likely to be paranoia) */
- memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
-
- /* Set up command buffer for an I2C write followed by a read */
- hdw->cmd_buffer[0] = 0x09; /* read prefix */
- hdw->cmd_buffer[1] = dlen; /* arg length */
- hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
- more byte (status). */
- hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */
- if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
-
- /* Do the operation */
- ret = pvr2_send_request(hdw,
- hdw->cmd_buffer,
- 4 + dlen,
- hdw->cmd_buffer,
- rlen + 1);
- if (!ret) {
- if (hdw->cmd_buffer[0] != 8) {
- ret = -EIO;
- if (hdw->cmd_buffer[0] != 7) {
- trace_i2c("unexpected status"
- " from i2_read[%d]: %d",
- i2c_addr,hdw->cmd_buffer[0]);
- }
- }
- }
-
-#ifdef notdef
- trace_i2c("i2c_read(%d) wlen=%d rlen=%d ret=%d stat=%d",
- i2c_addr,dlen,rlen,ret,hdw->cmd_buffer[0]);
-#endif
- /* Copy back the result */
- if (res && rlen) {
- if (ret) {
- /* Error, just blank out the return buffer */
- memset(res, 0, rlen);
- } else {
- memcpy(res, hdw->cmd_buffer + 1, rlen);
- }
- }
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-/* 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,
- struct i2c_msg msgs[],
- int num)
-{
- int ret = -ENOTSUPP;
- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
-
- if ((msgs[0].flags & I2C_M_NOSTART)) {
- trace_i2c("i2c refusing I2C_M_NOSTART");
- goto done;
- }
-
- if (num == 1) {
- if (msgs[0].flags & I2C_M_RD) {
- /* Simple read */
- u16 tcnt,bcnt,offs;
- if (!msgs[0].len) {
- /* Length == 0 read. This is a probe. */
- if (pvr2_i2c_read(hdw,msgs[0].addr,
- 0,0,0,0)) {
- ret = -EIO;
- goto done;
- }
- ret = 1;
- goto done;
- }
- /* If the read is short enough we'll do the whole
- thing atomically. Otherwise we have no choice
- but to break apart the reads. */
- tcnt = msgs[0].len;
- offs = 0;
- while (tcnt) {
- bcnt = tcnt;
- if (bcnt > sizeof(hdw->cmd_buffer)-1) {
- bcnt = sizeof(hdw->cmd_buffer)-1;
- }
- if (pvr2_i2c_read(hdw,msgs[0].addr,
- 0,0,
- msgs[0].buf+offs,bcnt)) {
- ret = -EIO;
- goto done;
- }
- offs += bcnt;
- tcnt -= bcnt;
- }
- ret = 1;
- goto done;
- } else {
- /* Simple write */
- ret = 1;
- if (pvr2_i2c_write(hdw,msgs[0].addr,
- msgs[0].buf,msgs[0].len)) {
- ret = -EIO;
- }
- goto done;
- }
- } else if (num == 2) {
- if ((!((msgs[0].flags & I2C_M_RD))) &&
- (msgs[1].flags & I2C_M_RD)) {
- u16 tcnt,bcnt,wcnt,offs;
- /* Write followed by atomic read. If the read
- portion is short enough we'll do the whole thing
- atomically. Otherwise we have no choice but to
- break apart the reads. */
- tcnt = msgs[1].len;
- wcnt = msgs[0].len;
- offs = 0;
- while (tcnt || wcnt) {
- bcnt = tcnt;
- if (bcnt > sizeof(hdw->cmd_buffer)-1) {
- bcnt = sizeof(hdw->cmd_buffer)-1;
- }
- if (pvr2_i2c_read(hdw,msgs[0].addr,
- msgs[0].buf,wcnt,
- msgs[1].buf+offs,bcnt)) {
- ret = -EIO;
- goto done;
- }
- offs += bcnt;
- tcnt -= bcnt;
- wcnt = 0;
- }
- ret = 2;
- goto done;
- } else {
- trace_i2c("i2c refusing complex transfer"
- " read0=%d read1=%d",
- (msgs[0].flags & I2C_M_RD),
- (msgs[1].flags & I2C_M_RD));
- }
- } else {
- trace_i2c("i2c refusing %d phase transfer",num);
- }
-
- done:
- if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
- unsigned int idx;
- for (idx = 0; idx < num; idx++) {
- printk(KERN_INFO
- "pvrusb2 i2c xfer %u/%u:"
- " addr=0x%x len=%d %s%s",
- idx+1,num,
- msgs[idx].addr,
- msgs[idx].len,
- (msgs[idx].flags & I2C_M_RD ?
- "read" : "write"),
- (msgs[idx].flags & I2C_M_NOSTART ?
- " nostart" : ""));
- if (idx+1 == num) {
- printk(" result=%d",ret);
- }
- printk("\n");
- }
- if (!num) {
- printk(KERN_INFO
- "pvrusb2 i2c xfer null transfer result=%d\n",
- ret);
- }
- }
- return ret;
-}
-
-static int pvr2_i2c_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
-{
- return I2C_FUNC_SMBUS_EMUL;
-}
-
-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 LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
- if (!try_module_get(cp->driver->owner)) return -EAGAIN;
-#else
- if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
-#endif
- stat = cp->driver->command(cp,cmd,arg);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
- module_put(cp->driver->owner);
-#else
- module_put(cp->driver->driver.owner);
-#endif
- return stat;
-}
-
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *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",cnt,buf);
- }
- return pvr2_i2c_core_singleton(cp->client,cmd,arg);
-}
-
-int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
-{
- struct list_head *item,*nc;
- struct pvr2_i2c_client *cp;
- int stat = -EINVAL;
-
- if (!hdw) return stat;
-
- mutex_lock(&hdw->i2c_list_lock);
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,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_sync(struct pvr2_hdw *hdw)
-{
- unsigned long msk;
- unsigned int idx;
- struct list_head *item,*nc;
- struct pvr2_i2c_client *cp;
-
- 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(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- 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(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- 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_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- 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(item,&hdw->i2c_clients) {
- cp = list_entry(item,
- struct pvr2_i2c_client,
- 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 list_head *item;
- 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(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
- if (!handler_check(cp)) continue;
- 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;
-}
-
-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;
- int spcfl;
- 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 list_head *item;
- struct pvr2_i2c_client *cp;
- ccnt = 0;
- mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,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 = kmalloc(sizeof(*cp),GFP_KERNEL);
- trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
- client->name,
- client->addr,cp);
- if (!cp) return -ENOMEM;
- memset(cp,0,sizeof(*cp));
- INIT_LIST_HEAD(&cp->list);
- cp->client = client;
- mutex_lock(&hdw->i2c_list_lock); do {
- 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) pvr2_hdw_poll_trigger_unlocked(hdw);
- 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;
- struct list_head *item,*nc;
- unsigned long amask = 0;
- int foundfl = 0;
- mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,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;
-}
-
-static struct i2c_algorithm pvr2_i2c_algo_template = {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- .id = I2C_ALGO_BIT | I2C_HW_B_BT848,
-#endif
- .master_xfer = pvr2_i2c_xfer,
- .algo_control = pvr2_i2c_control,
- .functionality = pvr2_i2c_functionality,
-};
-
-static struct i2c_adapter pvr2_i2c_adap_template = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_TV_ANALOG,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- .id = I2C_ALGO_BIT | I2C_HW_B_BT848,
-#else
- .id = I2C_HW_B_BT848,
-#endif
- .client_register = pvr2_i2c_attach_inform,
- .client_unregister = pvr2_i2c_detach_inform,
-};
-
-static void do_i2c_scan(struct pvr2_hdw *hdw)
-{
- struct i2c_msg msg[1];
- int i,rc;
- msg[0].addr = 0;
- msg[0].flags = I2C_M_RD;
- msg[0].len = 0;
- msg[0].buf = 0;
- printk("%s: i2c scan beginning\n",hdw->name);
- for (i = 0; i < 128; i++) {
- msg[0].addr = i;
- rc = i2c_transfer(&hdw->i2c_adap,msg,
- sizeof(msg)/sizeof(msg[0]));
- if (rc != 1) continue;
- printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
- }
- printk("%s: i2c scan done.\n",hdw->name);
-}
-
-void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
-{
- memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
- memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
- strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- strlcpy(hdw->i2c_algo.name,hdw->name,sizeof(hdw->i2c_algo.name));
-#endif
- 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 (i2c_scan) do_i2c_scan(hdw);
-}
-
-void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
-{
- if (hdw->i2c_linked) {
- i2c_del_adapter(&hdw->i2c_adap);
- hdw->i2c_linked = 0;
- }
-}
-
-/*
- 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: ***
- */