diff options
author | Mike Isely <isely@pobox.com> | 2009-03-06 21:47:10 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:33 -0400 |
commit | a932f507463d996b6ec1647ee7d4e2fa1e6aeda6 (patch) | |
tree | 00681f6ca29c2ddc052bc2f18c0503aba71d3f5f /drivers/media/video/pvrusb2 | |
parent | e9c64a78dbd7c4f6c4a31c4040f340f732bf4ec5 (diff) |
V4L/DVB (11159): pvrusb2: Providing means to stop tracking an old i2c module
This implements a temporary mechanism to "untrack" an i2c module from
the old i2c layer. The v4l2-subdev related code in the driver will
use this to remove a sub-device from the old i2c layer. In the end,
once the old i2c layer is removed, this will also eventually go away.
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/pvrusb2')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.c | 6 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-i2c-track.c | 76 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-i2c-track.h | 5 |
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 faa94cef2c55..0e0d086bb278 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, | |||
2020 | i2caddr); | 2020 | i2caddr); |
2021 | } | 2021 | } |
2022 | 2022 | ||
2023 | /* If we have both old and new i2c layers enabled, make sure that | ||
2024 | old layer isn't also tracking this module. This is a debugging | ||
2025 | aid, in normal situations there's no reason for both mechanisms | ||
2026 | to be enabled. */ | ||
2027 | pvr2_i2c_untrack_subdev(hdw, sd); | ||
2028 | |||
2023 | // ????? | 2029 | // ????? |
2024 | /* Based on module ID, we should remember subdev pointers | 2030 | /* Based on module ID, we should remember subdev pointers |
2025 | so that we can send certain custom commands where | 2031 | 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 4bb6f9453e0d..3387897ed897 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) | |||
421 | if (fl) queue_work(hdw->workqueue,&hdw->worki2csync); | 421 | if (fl) queue_work(hdw->workqueue,&hdw->worki2csync); |
422 | } | 422 | } |
423 | 423 | ||
424 | static void pvr2_i2c_client_disconnect(struct pvr2_i2c_client *cp) | ||
425 | { | ||
426 | if (cp->handler && cp->handler->func_table->detach) { | ||
427 | cp->handler->func_table->detach(cp->handler->func_data); | ||
428 | } | ||
429 | list_del(&cp->list); | ||
430 | kfree(cp); | ||
431 | } | ||
432 | |||
424 | void pvr2_i2c_track_detach_inform(struct i2c_client *client) | 433 | void pvr2_i2c_track_detach_inform(struct i2c_client *client) |
425 | { | 434 | { |
426 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); | 435 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); |
427 | struct pvr2_i2c_client *cp, *ncp; | 436 | struct pvr2_i2c_client *cp, *ncp; |
428 | unsigned long amask = 0; | 437 | unsigned long amask = 0; |
429 | int foundfl = 0; | 438 | int foundfl = 0; |
430 | mutex_lock(&hdw->i2c_list_lock); do { | 439 | mutex_lock(&hdw->i2c_list_lock); |
431 | hdw->cropcap_stale = !0; | 440 | hdw->cropcap_stale = !0; |
432 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { | 441 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { |
433 | if (cp->client == client) { | 442 | if (cp->client == client) { |
434 | trace_i2c("pvr2_i2c_detach" | 443 | trace_i2c("pvr2_i2c_detach" |
435 | " [client=%s @ 0x%x ctxt=%p]", | 444 | " [client=%s @ 0x%x ctxt=%p]", |
436 | client->name, | 445 | client->name, |
437 | client->addr,cp); | 446 | client->addr, cp); |
438 | if (cp->handler && | 447 | pvr2_i2c_client_disconnect(cp); |
439 | cp->handler->func_table->detach) { | 448 | foundfl = !0; |
440 | cp->handler->func_table->detach( | 449 | continue; |
441 | cp->handler->func_data); | ||
442 | } | ||
443 | list_del(&cp->list); | ||
444 | kfree(cp); | ||
445 | foundfl = !0; | ||
446 | continue; | ||
447 | } | ||
448 | amask |= cp->ctl_mask; | ||
449 | } | 450 | } |
450 | hdw->i2c_active_mask = amask; | 451 | amask |= cp->ctl_mask; |
451 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | 452 | } |
453 | hdw->i2c_active_mask = amask; | ||
454 | mutex_unlock(&hdw->i2c_list_lock); | ||
452 | if (!foundfl) { | 455 | if (!foundfl) { |
453 | trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]", | 456 | trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]", |
454 | client->name, | 457 | client->name, client->addr); |
455 | client->addr); | ||
456 | } | 458 | } |
457 | } | 459 | } |
458 | 460 | ||
461 | /* This function is used to remove an i2c client from our tracking | ||
462 | structure if the client happens to be the specified v4l2 sub-device. | ||
463 | The idea here is to ensure that sub-devices are not also tracked with | ||
464 | the old tracking mechanism - it's one or the other not both. This is | ||
465 | only for debugging. In a "real" environment, only one of these two | ||
466 | mechanisms should even be compiled in. But by enabling both we can | ||
467 | incrementally test control of each sub-device. */ | ||
468 | void pvr2_i2c_untrack_subdev(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) | ||
469 | { | ||
470 | struct i2c_client *client; | ||
471 | struct pvr2_i2c_client *cp, *ncp; | ||
472 | unsigned long amask = 0; | ||
473 | mutex_lock(&hdw->i2c_list_lock); | ||
474 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { | ||
475 | client = cp->client; | ||
476 | if (i2c_get_clientdata(client) == sd) { | ||
477 | trace_i2c("pvr2_i2c_detach (subdev active)" | ||
478 | " [client=%s @ 0x%x ctxt=%p]", | ||
479 | client->name, client->addr, cp); | ||
480 | pvr2_i2c_client_disconnect(cp); | ||
481 | continue; | ||
482 | } | ||
483 | amask |= cp->ctl_mask; | ||
484 | } | ||
485 | hdw->i2c_active_mask = amask; | ||
486 | mutex_unlock(&hdw->i2c_list_lock); | ||
487 | } | ||
488 | |||
459 | void pvr2_i2c_track_init(struct pvr2_hdw *hdw) | 489 | void pvr2_i2c_track_init(struct pvr2_hdw *hdw) |
460 | { | 490 | { |
461 | hdw->i2c_pend_mask = 0; | 491 | 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 7d0e4fb63785..eba48e4c9585 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h | |||
@@ -22,6 +22,8 @@ | |||
22 | 22 | ||
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
25 | #include <media/v4l2-device.h> | ||
26 | |||
25 | 27 | ||
26 | struct pvr2_hdw; | 28 | struct pvr2_hdw; |
27 | struct pvr2_i2c_client; | 29 | struct pvr2_i2c_client; |
@@ -83,6 +85,9 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen); | |||
83 | void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *); | 85 | void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *); |
84 | const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx); | 86 | const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx); |
85 | 87 | ||
88 | void pvr2_i2c_untrack_subdev(struct pvr2_hdw *, struct v4l2_subdev *sd); | ||
89 | |||
90 | |||
86 | #endif /* __PVRUSB2_I2C_CORE_H */ | 91 | #endif /* __PVRUSB2_I2C_CORE_H */ |
87 | 92 | ||
88 | 93 | ||