aboutsummaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-track.c76
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-track.h5
3 files changed, 64 insertions, 23 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index faa94cef2c5..0e0d086bb27 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2020,6 +2020,12 @@ static void pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
i2caddr);
}
+ /* If we have both old and new i2c layers enabled, make sure that
+ old layer isn't also tracking this module. This is a debugging
+ aid, in normal situations there's no reason for both mechanisms
+ to be enabled. */
+ pvr2_i2c_untrack_subdev(hdw, sd);
+
// ?????
/* Based on module ID, we should remember subdev pointers
so that we can send certain custom commands where
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
index 4bb6f9453e0..3387897ed89 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
@@ -421,41 +421,71 @@ void pvr2_i2c_track_attach_inform(struct i2c_client *client)
if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
}
+static void pvr2_i2c_client_disconnect(struct pvr2_i2c_client *cp)
+{
+ if (cp->handler && cp->handler->func_table->detach) {
+ cp->handler->func_table->detach(cp->handler->func_data);
+ }
+ list_del(&cp->list);
+ kfree(cp);
+}
+
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;
+ mutex_lock(&hdw->i2c_list_lock);
+ 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);
+ pvr2_i2c_client_disconnect(cp);
+ foundfl = !0;
+ continue;
}
- hdw->i2c_active_mask = amask;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ amask |= cp->ctl_mask;
+ }
+ hdw->i2c_active_mask = amask;
+ mutex_unlock(&hdw->i2c_list_lock);
if (!foundfl) {
trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
- client->name,
- client->addr);
+ client->name, client->addr);
}
}
+/* This function is used to remove an i2c client from our tracking
+ structure if the client happens to be the specified v4l2 sub-device.
+ The idea here is to ensure that sub-devices are not also tracked with
+ the old tracking mechanism - it's one or the other not both. This is
+ only for debugging. In a "real" environment, only one of these two
+ mechanisms should even be compiled in. But by enabling both we can
+ incrementally test control of each sub-device. */
+void pvr2_i2c_untrack_subdev(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+{
+ struct i2c_client *client;
+ struct pvr2_i2c_client *cp, *ncp;
+ unsigned long amask = 0;
+ mutex_lock(&hdw->i2c_list_lock);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
+ client = cp->client;
+ if (i2c_get_clientdata(client) == sd) {
+ trace_i2c("pvr2_i2c_detach (subdev active)"
+ " [client=%s @ 0x%x ctxt=%p]",
+ client->name, client->addr, cp);
+ pvr2_i2c_client_disconnect(cp);
+ continue;
+ }
+ amask |= cp->ctl_mask;
+ }
+ hdw->i2c_active_mask = amask;
+ mutex_unlock(&hdw->i2c_list_lock);
+}
+
void pvr2_i2c_track_init(struct pvr2_hdw *hdw)
{
hdw->i2c_pend_mask = 0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h
index 7d0e4fb6378..eba48e4c958 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h
@@ -22,6 +22,8 @@
#include <linux/list.h>
#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+
struct pvr2_hdw;
struct pvr2_i2c_client;
@@ -83,6 +85,9 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
+void pvr2_i2c_untrack_subdev(struct pvr2_hdw *, struct v4l2_subdev *sd);
+
+
#endif /* __PVRUSB2_I2C_CORE_H */