Преглед на файлове

V4L/DVB (11154): pvrusb2: Split i2c module handling from i2c adapter

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>
Mike Isely преди 16 години
родител
ревизия
59af336795

+ 1 - 0
drivers/media/video/pvrusb2/Makefile

@@ -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 \

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-audio.h

@@ -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 *);
 

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h

@@ -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 *);
 

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-debugifc.c

@@ -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;

+ 3 - 0
drivers/media/video/pvrusb2/pvrusb2-hdw.c

@@ -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) &&

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c

@@ -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"

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h

@@ -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;

+ 5 - 412
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c

@@ -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) {

+ 1 - 56
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h

@@ -20,68 +20,13 @@
 #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 */
 
 
 /*

+ 480 - 0
drivers/media/video/pvrusb2/pvrusb2-i2c-track.c

@@ -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: ***
+  */

+ 97 - 0
drivers/media/video/pvrusb2/pvrusb2-i2c-track.h

@@ -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: ***
+  */

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-tuner.h

@@ -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 *);
 

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-video-v4l.h

@@ -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 *);
 

+ 1 - 1
drivers/media/video/pvrusb2/pvrusb2-wm8775.h

@@ -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 *);