aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2009-03-07 01:06:09 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:32 -0400
commit59af33679592dd6e7bc7aa955098389724684a74 (patch)
tree312143dad3860f45b489fdb4e0f370edcef824c3
parentc457377a3a18117aa99653f3715d81960a1c6bda (diff)
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>
-rw-r--r--drivers/media/video/pvrusb2/Makefile1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c417
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.h57
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-track.c480
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-track.h97
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-tuner.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-wm8775.h2
14 files changed, 595 insertions, 476 deletions
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 4fda2de69ab7..931d9d1a0b4b 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -3,6 +3,7 @@ obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
3obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o 3obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
4 4
5pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ 5pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
6 pvrusb2-i2c-track.o \
6 pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \ 7 pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
7 pvrusb2-encoder.o pvrusb2-video-v4l.o \ 8 pvrusb2-encoder.o pvrusb2-video-v4l.o \
8 pvrusb2-eeprom.o pvrusb2-tuner.o \ 9 pvrusb2-eeprom.o pvrusb2-tuner.o \
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h
index ac54eed3721b..f7f0a408a9b4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.h
@@ -22,7 +22,7 @@
22#ifndef __PVRUSB2_AUDIO_H 22#ifndef __PVRUSB2_AUDIO_H
23#define __PVRUSB2_AUDIO_H 23#define __PVRUSB2_AUDIO_H
24 24
25#include "pvrusb2-i2c-core.h" 25#include "pvrusb2-i2c-track.h"
26 26
27int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); 27int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
28 28
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
index 66abf77f51fd..f664f5942002 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -34,7 +34,7 @@
34 34
35 35
36 36
37#include "pvrusb2-i2c-core.h" 37#include "pvrusb2-i2c-track.h"
38 38
39int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); 39int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
40 40
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index ca892fb78a5b..cc4ef891b5b6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -23,7 +23,7 @@
23#include "pvrusb2-debugifc.h" 23#include "pvrusb2-debugifc.h"
24#include "pvrusb2-hdw.h" 24#include "pvrusb2-hdw.h"
25#include "pvrusb2-debug.h" 25#include "pvrusb2-debug.h"
26#include "pvrusb2-i2c-core.h" 26#include "pvrusb2-i2c-track.h"
27 27
28struct debugifc_mask_item { 28struct debugifc_mask_item {
29 const char *name; 29 const char *name;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index ed8a4561e086..9441bcc37bc3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -29,6 +29,7 @@
29#include "pvrusb2-util.h" 29#include "pvrusb2-util.h"
30#include "pvrusb2-hdw.h" 30#include "pvrusb2-hdw.h"
31#include "pvrusb2-i2c-core.h" 31#include "pvrusb2-i2c-core.h"
32#include "pvrusb2-i2c-track.h"
32#include "pvrusb2-tuner.h" 33#include "pvrusb2-tuner.h"
33#include "pvrusb2-eeprom.h" 34#include "pvrusb2-eeprom.h"
34#include "pvrusb2-hdw-internal.h" 35#include "pvrusb2-hdw-internal.h"
@@ -1990,6 +1991,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
1990 } 1991 }
1991 1992
1992 // This step MUST happen after the earlier powerup step. 1993 // This step MUST happen after the earlier powerup step.
1994 pvr2_i2c_track_init(hdw);
1993 pvr2_i2c_core_init(hdw); 1995 pvr2_i2c_core_init(hdw);
1994 if (!pvr2_hdw_dev_ok(hdw)) return; 1996 if (!pvr2_hdw_dev_ok(hdw)) return;
1995 1997
@@ -2501,6 +2503,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
2501 hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt); 2503 hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
2502 } 2504 }
2503 pvr2_i2c_core_done(hdw); 2505 pvr2_i2c_core_done(hdw);
2506 pvr2_i2c_track_done(hdw);
2504 pvr2_hdw_remove_usb_stuff(hdw); 2507 pvr2_hdw_remove_usb_stuff(hdw);
2505 mutex_lock(&pvr2_unit_mtx); do { 2508 mutex_lock(&pvr2_unit_mtx); do {
2506 if ((hdw->unit_number >= 0) && 2509 if ((hdw->unit_number >= 0) &&
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 4cf980c49d01..8f32c2edb49a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include "pvrusb2-i2c-core.h" 22#include "pvrusb2-i2c-track.h"
23#include "pvrusb2-hdw-internal.h" 23#include "pvrusb2-hdw-internal.h"
24#include "pvrusb2-debug.h" 24#include "pvrusb2-debug.h"
25#include "pvrusb2-i2c-cmd-v4l2.h" 25#include "pvrusb2-i2c-cmd-v4l2.h"
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index 69a63f2a8a7b..8472637e48eb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -22,7 +22,7 @@
22#ifndef __PVRUSB2_CMD_V4L2_H 22#ifndef __PVRUSB2_CMD_V4L2_H
23#define __PVRUSB2_CMD_V4L2_H 23#define __PVRUSB2_CMD_V4L2_H
24 24
25#include "pvrusb2-i2c-core.h" 25#include "pvrusb2-i2c-track.h"
26 26
27extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init; 27extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init;
28extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard; 28extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 57a024737722..2ba429f1bc8e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -18,7 +18,9 @@
18 * 18 *
19 */ 19 */
20 20
21#include <linux/i2c.h>
21#include "pvrusb2-i2c-core.h" 22#include "pvrusb2-i2c-core.h"
23#include "pvrusb2-i2c-track.h"
22#include "pvrusb2-hdw-internal.h" 24#include "pvrusb2-hdw-internal.h"
23#include "pvrusb2-debug.h" 25#include "pvrusb2-debug.h"
24#include "pvrusb2-fx2-cmd.h" 26#include "pvrusb2-fx2-cmd.h"
@@ -29,8 +31,7 @@
29/* 31/*
30 32
31 This module attempts to implement a compliant I2C adapter for the pvrusb2 33 This module attempts to implement a compliant I2C adapter for the pvrusb2
32 device. By doing this we can then make use of existing functionality in 34 device.
33 V4L (e.g. tuner.c) rather than rolling our own.
34 35
35*/ 36*/
36 37
@@ -42,10 +43,6 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
42module_param_array(ir_mode, int, NULL, 0444); 43module_param_array(ir_mode, int, NULL, 0444);
43MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR"); 44MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
44 45
45static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
46 unsigned int detail,
47 char *buf,unsigned int maxlen);
48
49static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ 46static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
50 u8 i2c_addr, /* I2C address we're talking to */ 47 u8 i2c_addr, /* I2C address we're talking to */
51 u8 *data, /* Data to write */ 48 u8 *data, /* Data to write */
@@ -524,414 +521,15 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
524 return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; 521 return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
525} 522}
526 523
527static int pvr2_i2c_core_singleton(struct i2c_client *cp,
528 unsigned int cmd,void *arg)
529{
530 int stat;
531 if (!cp) return -EINVAL;
532 if (!(cp->driver)) return -EINVAL;
533 if (!(cp->driver->command)) return -EINVAL;
534 if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
535 stat = cp->driver->command(cp,cmd,arg);
536 module_put(cp->driver->driver.owner);
537 return stat;
538}
539
540int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
541{
542 int stat;
543 if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
544 char buf[100];
545 unsigned int cnt;
546 cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
547 buf,sizeof(buf));
548 pvr2_trace(PVR2_TRACE_I2C_CMD,
549 "i2c COMMAND (code=%u 0x%x) to %.*s",
550 cmd,cmd,cnt,buf);
551 }
552 stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
553 if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
554 char buf[100];
555 unsigned int cnt;
556 cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
557 buf,sizeof(buf));
558 pvr2_trace(PVR2_TRACE_I2C_CMD,
559 "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
560 }
561 return stat;
562}
563
564int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
565{
566 struct pvr2_i2c_client *cp, *ncp;
567 int stat = -EINVAL;
568
569 if (!hdw) return stat;
570
571 mutex_lock(&hdw->i2c_list_lock);
572 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
573 if (!cp->recv_enable) continue;
574 mutex_unlock(&hdw->i2c_list_lock);
575 stat = pvr2_i2c_client_cmd(cp,cmd,arg);
576 mutex_lock(&hdw->i2c_list_lock);
577 }
578 mutex_unlock(&hdw->i2c_list_lock);
579 return stat;
580}
581
582
583static int handler_check(struct pvr2_i2c_client *cp)
584{
585 struct pvr2_i2c_handler *hp = cp->handler;
586 if (!hp) return 0;
587 if (!hp->func_table->check) return 0;
588 return hp->func_table->check(hp->func_data) != 0;
589}
590
591#define BUFSIZE 500
592
593
594void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
595{
596 struct pvr2_i2c_client *cp;
597 mutex_lock(&hdw->i2c_list_lock); do {
598 struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
599 memset(vtp,0,sizeof(*vtp));
600 list_for_each_entry(cp, &hdw->i2c_clients, list) {
601 if (!cp->detected_flag) continue;
602 if (!cp->status_poll) continue;
603 cp->status_poll(cp);
604 }
605 hdw->tuner_signal_stale = 0;
606 pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
607 " type=%u strength=%u audio=0x%x cap=0x%x"
608 " low=%u hi=%u",
609 vtp->type,
610 vtp->signal,vtp->rxsubchans,vtp->capability,
611 vtp->rangelow,vtp->rangehigh);
612 } while (0); mutex_unlock(&hdw->i2c_list_lock);
613}
614
615
616/* Issue various I2C operations to bring chip-level drivers into sync with
617 state stored in this driver. */
618void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
619{
620 unsigned long msk;
621 unsigned int idx;
622 struct pvr2_i2c_client *cp, *ncp;
623
624 if (!hdw->i2c_linked) return;
625 if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
626 return;
627 }
628 mutex_lock(&hdw->i2c_list_lock); do {
629 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
630 if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
631 /* One or more I2C clients have attached since we
632 last synced. So scan the list and identify the
633 new clients. */
634 char *buf;
635 unsigned int cnt;
636 unsigned long amask = 0;
637 buf = kmalloc(BUFSIZE,GFP_KERNEL);
638 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
639 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
640 list_for_each_entry(cp, &hdw->i2c_clients, list) {
641 if (!cp->detected_flag) {
642 cp->ctl_mask = 0;
643 pvr2_i2c_probe(hdw,cp);
644 cp->detected_flag = !0;
645 msk = cp->ctl_mask;
646 cnt = 0;
647 if (buf) {
648 cnt = pvr2_i2c_client_describe(
649 cp,
650 PVR2_I2C_DETAIL_ALL,
651 buf,BUFSIZE);
652 }
653 trace_i2c("Probed: %.*s",cnt,buf);
654 if (handler_check(cp)) {
655 hdw->i2c_pend_types |=
656 PVR2_I2C_PEND_CLIENT;
657 }
658 cp->pend_mask = msk;
659 hdw->i2c_pend_mask |= msk;
660 hdw->i2c_pend_types |=
661 PVR2_I2C_PEND_REFRESH;
662 }
663 amask |= cp->ctl_mask;
664 }
665 hdw->i2c_active_mask = amask;
666 if (buf) kfree(buf);
667 }
668 if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
669 /* Need to do one or more global updates. Arrange
670 for this to happen. */
671 unsigned long m2;
672 pvr2_trace(PVR2_TRACE_I2C_CORE,
673 "i2c: PEND_STALE (0x%lx)",
674 hdw->i2c_stale_mask);
675 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
676 list_for_each_entry(cp, &hdw->i2c_clients, list) {
677 m2 = hdw->i2c_stale_mask;
678 m2 &= cp->ctl_mask;
679 m2 &= ~cp->pend_mask;
680 if (m2) {
681 pvr2_trace(PVR2_TRACE_I2C_CORE,
682 "i2c: cp=%p setting 0x%lx",
683 cp,m2);
684 cp->pend_mask |= m2;
685 }
686 }
687 hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
688 hdw->i2c_stale_mask = 0;
689 hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
690 }
691 if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
692 /* One or more client handlers are asking for an
693 update. Run through the list of known clients
694 and update each one. */
695 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
696 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
697 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
698 list) {
699 if (!cp->handler) continue;
700 if (!cp->handler->func_table->update) continue;
701 pvr2_trace(PVR2_TRACE_I2C_CORE,
702 "i2c: cp=%p update",cp);
703 mutex_unlock(&hdw->i2c_list_lock);
704 cp->handler->func_table->update(
705 cp->handler->func_data);
706 mutex_lock(&hdw->i2c_list_lock);
707 /* If client's update function set some
708 additional pending bits, account for that
709 here. */
710 if (cp->pend_mask & ~hdw->i2c_pend_mask) {
711 hdw->i2c_pend_mask |= cp->pend_mask;
712 hdw->i2c_pend_types |=
713 PVR2_I2C_PEND_REFRESH;
714 }
715 }
716 }
717 if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
718 const struct pvr2_i2c_op *opf;
719 unsigned long pm;
720 /* Some actual updates are pending. Walk through
721 each update type and perform it. */
722 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
723 " (0x%lx)",hdw->i2c_pend_mask);
724 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
725 pm = hdw->i2c_pend_mask;
726 hdw->i2c_pend_mask = 0;
727 for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
728 if (!(pm & msk)) continue;
729 pm &= ~msk;
730 list_for_each_entry(cp, &hdw->i2c_clients,
731 list) {
732 if (cp->pend_mask & msk) {
733 cp->pend_mask &= ~msk;
734 cp->recv_enable = !0;
735 } else {
736 cp->recv_enable = 0;
737 }
738 }
739 opf = pvr2_i2c_get_op(idx);
740 if (!opf) continue;
741 mutex_unlock(&hdw->i2c_list_lock);
742 opf->update(hdw);
743 mutex_lock(&hdw->i2c_list_lock);
744 }
745 }
746 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
747 } while (0); mutex_unlock(&hdw->i2c_list_lock);
748}
749
750int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
751{
752 unsigned long msk,sm,pm;
753 unsigned int idx;
754 const struct pvr2_i2c_op *opf;
755 struct pvr2_i2c_client *cp;
756 unsigned int pt = 0;
757
758 pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
759
760 pm = hdw->i2c_active_mask;
761 sm = 0;
762 for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
763 if (!(msk & pm)) continue;
764 pm &= ~msk;
765 opf = pvr2_i2c_get_op(idx);
766 if (!(opf && opf->check)) continue;
767 if (opf->check(hdw)) {
768 sm |= msk;
769 }
770 }
771 if (sm) pt |= PVR2_I2C_PEND_STALE;
772
773 list_for_each_entry(cp, &hdw->i2c_clients, list)
774 if (handler_check(cp))
775 pt |= PVR2_I2C_PEND_CLIENT;
776
777 if (pt) {
778 mutex_lock(&hdw->i2c_list_lock); do {
779 hdw->i2c_pend_types |= pt;
780 hdw->i2c_stale_mask |= sm;
781 hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
782 } while (0); mutex_unlock(&hdw->i2c_list_lock);
783 }
784
785 pvr2_trace(PVR2_TRACE_I2C_CORE,
786 "i2c: types=0x%x stale=0x%lx pend=0x%lx",
787 hdw->i2c_pend_types,
788 hdw->i2c_stale_mask,
789 hdw->i2c_pend_mask);
790 pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
791
792 return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
793}
794
795static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
796 unsigned int detail,
797 char *buf,unsigned int maxlen)
798{
799 unsigned int ccnt,bcnt;
800 int spcfl = 0;
801 const struct pvr2_i2c_op *opf;
802
803 ccnt = 0;
804 if (detail & PVR2_I2C_DETAIL_DEBUG) {
805 bcnt = scnprintf(buf,maxlen,
806 "ctxt=%p ctl_mask=0x%lx",
807 cp,cp->ctl_mask);
808 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
809 spcfl = !0;
810 }
811 bcnt = scnprintf(buf,maxlen,
812 "%s%s @ 0x%x",
813 (spcfl ? " " : ""),
814 cp->client->name,
815 cp->client->addr);
816 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
817 if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
818 cp->handler && cp->handler->func_table->describe) {
819 bcnt = scnprintf(buf,maxlen," (");
820 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
821 bcnt = cp->handler->func_table->describe(
822 cp->handler->func_data,buf,maxlen);
823 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
824 bcnt = scnprintf(buf,maxlen,")");
825 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
826 }
827 if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
828 unsigned int idx;
829 unsigned long msk,sm;
830
831 bcnt = scnprintf(buf,maxlen," [");
832 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
833 sm = 0;
834 spcfl = 0;
835 for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
836 if (!(cp->ctl_mask & msk)) continue;
837 opf = pvr2_i2c_get_op(idx);
838 if (opf) {
839 bcnt = scnprintf(buf,maxlen,"%s%s",
840 spcfl ? " " : "",
841 opf->name);
842 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
843 spcfl = !0;
844 } else {
845 sm |= msk;
846 }
847 }
848 if (sm) {
849 bcnt = scnprintf(buf,maxlen,"%s%lx",
850 idx != 0 ? " " : "",sm);
851 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
852 }
853 bcnt = scnprintf(buf,maxlen,"]");
854 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
855 }
856 return ccnt;
857}
858
859unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
860 char *buf,unsigned int maxlen)
861{
862 unsigned int ccnt,bcnt;
863 struct pvr2_i2c_client *cp;
864 ccnt = 0;
865 mutex_lock(&hdw->i2c_list_lock); do {
866 list_for_each_entry(cp, &hdw->i2c_clients, list) {
867 bcnt = pvr2_i2c_client_describe(
868 cp,
869 (PVR2_I2C_DETAIL_HANDLER|
870 PVR2_I2C_DETAIL_CTLMASK),
871 buf,maxlen);
872 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
873 bcnt = scnprintf(buf,maxlen,"\n");
874 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
875 }
876 } while (0); mutex_unlock(&hdw->i2c_list_lock);
877 return ccnt;
878}
879
880static int pvr2_i2c_attach_inform(struct i2c_client *client) 524static int pvr2_i2c_attach_inform(struct i2c_client *client)
881{ 525{
882 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); 526 pvr2_i2c_track_attach_inform(client);
883 struct pvr2_i2c_client *cp;
884 int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
885 cp = kzalloc(sizeof(*cp),GFP_KERNEL);
886 trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
887 client->name,
888 client->addr,cp);
889 if (!cp) return -ENOMEM;
890 cp->hdw = hdw;
891 INIT_LIST_HEAD(&cp->list);
892 cp->client = client;
893 mutex_lock(&hdw->i2c_list_lock); do {
894 hdw->cropcap_stale = !0;
895 list_add_tail(&cp->list,&hdw->i2c_clients);
896 hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
897 } while (0); mutex_unlock(&hdw->i2c_list_lock);
898 if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
899 return 0; 527 return 0;
900} 528}
901 529
902static int pvr2_i2c_detach_inform(struct i2c_client *client) 530static int pvr2_i2c_detach_inform(struct i2c_client *client)
903{ 531{
904 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); 532 pvr2_i2c_track_detach_inform(client);
905 struct pvr2_i2c_client *cp, *ncp;
906 unsigned long amask = 0;
907 int foundfl = 0;
908 mutex_lock(&hdw->i2c_list_lock); do {
909 hdw->cropcap_stale = !0;
910 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
911 if (cp->client == client) {
912 trace_i2c("pvr2_i2c_detach"
913 " [client=%s @ 0x%x ctxt=%p]",
914 client->name,
915 client->addr,cp);
916 if (cp->handler &&
917 cp->handler->func_table->detach) {
918 cp->handler->func_table->detach(
919 cp->handler->func_data);
920 }
921 list_del(&cp->list);
922 kfree(cp);
923 foundfl = !0;
924 continue;
925 }
926 amask |= cp->ctl_mask;
927 }
928 hdw->i2c_active_mask = amask;
929 } while (0); mutex_unlock(&hdw->i2c_list_lock);
930 if (!foundfl) {
931 trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
932 client->name,
933 client->addr);
934 }
935 return 0; 533 return 0;
936} 534}
937 535
@@ -1009,11 +607,6 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
1009 hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev; 607 hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
1010 hdw->i2c_adap.algo = &hdw->i2c_algo; 608 hdw->i2c_adap.algo = &hdw->i2c_algo;
1011 hdw->i2c_adap.algo_data = hdw; 609 hdw->i2c_adap.algo_data = hdw;
1012 hdw->i2c_pend_mask = 0;
1013 hdw->i2c_stale_mask = 0;
1014 hdw->i2c_active_mask = 0;
1015 INIT_LIST_HEAD(&hdw->i2c_clients);
1016 mutex_init(&hdw->i2c_list_lock);
1017 hdw->i2c_linked = !0; 610 hdw->i2c_linked = !0;
1018 i2c_add_adapter(&hdw->i2c_adap); 611 i2c_add_adapter(&hdw->i2c_adap);
1019 if (hdw->i2c_func[0x18] == i2c_24xxx_ir) { 612 if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index 6ef7a1c0e935..6a75769200bd 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -20,68 +20,13 @@
20#ifndef __PVRUSB2_I2C_CORE_H 20#ifndef __PVRUSB2_I2C_CORE_H
21#define __PVRUSB2_I2C_CORE_H 21#define __PVRUSB2_I2C_CORE_H
22 22
23#include <linux/list.h>
24#include <linux/i2c.h>
25
26struct pvr2_hdw; 23struct pvr2_hdw;
27struct pvr2_i2c_client;
28struct pvr2_i2c_handler;
29struct pvr2_i2c_handler_functions;
30struct pvr2_i2c_op;
31struct pvr2_i2c_op_functions;
32
33struct pvr2_i2c_client {
34 struct i2c_client *client;
35 struct pvr2_i2c_handler *handler;
36 struct list_head list;
37 struct pvr2_hdw *hdw;
38 int detected_flag;
39 int recv_enable;
40 unsigned long pend_mask;
41 unsigned long ctl_mask;
42 void (*status_poll)(struct pvr2_i2c_client *);
43};
44
45struct pvr2_i2c_handler {
46 void *func_data;
47 const struct pvr2_i2c_handler_functions *func_table;
48};
49
50struct pvr2_i2c_handler_functions {
51 void (*detach)(void *);
52 int (*check)(void *);
53 void (*update)(void *);
54 unsigned int (*describe)(void *,char *,unsigned int);
55};
56
57struct pvr2_i2c_op {
58 int (*check)(struct pvr2_hdw *);
59 void (*update)(struct pvr2_hdw *);
60 const char *name;
61};
62 24
63void pvr2_i2c_core_init(struct pvr2_hdw *); 25void pvr2_i2c_core_init(struct pvr2_hdw *);
64void pvr2_i2c_core_done(struct pvr2_hdw *); 26void pvr2_i2c_core_done(struct pvr2_hdw *);
65 27
66int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
67int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
68
69int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
70void pvr2_i2c_core_sync(struct pvr2_hdw *);
71void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
72unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
73#define PVR2_I2C_DETAIL_DEBUG 0x0001
74#define PVR2_I2C_DETAIL_HANDLER 0x0002
75#define PVR2_I2C_DETAIL_CTLMASK 0x0004
76#define PVR2_I2C_DETAIL_ALL (\
77 PVR2_I2C_DETAIL_DEBUG |\
78 PVR2_I2C_DETAIL_HANDLER |\
79 PVR2_I2C_DETAIL_CTLMASK)
80
81void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
82const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
83 28
84#endif /* __PVRUSB2_I2C_CORE_H */ 29#endif /* __PVRUSB2_I2C_ADAPTER_H */
85 30
86 31
87/* 32/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
new file mode 100644
index 000000000000..48cffa4a1b6a
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
@@ -0,0 +1,480 @@
1/*
2 *
3 *
4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "pvrusb2-i2c-track.h"
22#include "pvrusb2-hdw-internal.h"
23#include "pvrusb2-debug.h"
24#include "pvrusb2-fx2-cmd.h"
25#include "pvrusb2.h"
26
27#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
28
29/*
30
31 This module implements the foundation of a rather large architecture for
32 tracking state in all the various V4L I2C modules. This is obsolete with
33 kernels later than roughly 2.6.24, but it is still present in the
34 standalone pvrusb2 driver to allow continued operation with older
35 kernel.
36
37*/
38
39static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
40 unsigned int detail,
41 char *buf,unsigned int maxlen);
42
43static int pvr2_i2c_core_singleton(struct i2c_client *cp,
44 unsigned int cmd,void *arg)
45{
46 int stat;
47 if (!cp) return -EINVAL;
48 if (!(cp->driver)) return -EINVAL;
49 if (!(cp->driver->command)) return -EINVAL;
50 if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
51 stat = cp->driver->command(cp,cmd,arg);
52 module_put(cp->driver->driver.owner);
53 return stat;
54}
55
56int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
57{
58 int stat;
59 if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
60 char buf[100];
61 unsigned int cnt;
62 cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
63 buf,sizeof(buf));
64 pvr2_trace(PVR2_TRACE_I2C_CMD,
65 "i2c COMMAND (code=%u 0x%x) to %.*s",
66 cmd,cmd,cnt,buf);
67 }
68 stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
69 if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
70 char buf[100];
71 unsigned int cnt;
72 cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
73 buf,sizeof(buf));
74 pvr2_trace(PVR2_TRACE_I2C_CMD,
75 "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
76 }
77 return stat;
78}
79
80int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
81{
82 struct pvr2_i2c_client *cp, *ncp;
83 int stat = -EINVAL;
84
85 if (!hdw) return stat;
86
87 mutex_lock(&hdw->i2c_list_lock);
88 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
89 if (!cp->recv_enable) continue;
90 mutex_unlock(&hdw->i2c_list_lock);
91 stat = pvr2_i2c_client_cmd(cp,cmd,arg);
92 mutex_lock(&hdw->i2c_list_lock);
93 }
94 mutex_unlock(&hdw->i2c_list_lock);
95 return stat;
96}
97
98
99static int handler_check(struct pvr2_i2c_client *cp)
100{
101 struct pvr2_i2c_handler *hp = cp->handler;
102 if (!hp) return 0;
103 if (!hp->func_table->check) return 0;
104 return hp->func_table->check(hp->func_data) != 0;
105}
106
107#define BUFSIZE 500
108
109
110void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
111{
112 struct pvr2_i2c_client *cp;
113 mutex_lock(&hdw->i2c_list_lock); do {
114 struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
115 memset(vtp,0,sizeof(*vtp));
116 list_for_each_entry(cp, &hdw->i2c_clients, list) {
117 if (!cp->detected_flag) continue;
118 if (!cp->status_poll) continue;
119 cp->status_poll(cp);
120 }
121 hdw->tuner_signal_stale = 0;
122 pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
123 " type=%u strength=%u audio=0x%x cap=0x%x"
124 " low=%u hi=%u",
125 vtp->type,
126 vtp->signal,vtp->rxsubchans,vtp->capability,
127 vtp->rangelow,vtp->rangehigh);
128 } while (0); mutex_unlock(&hdw->i2c_list_lock);
129}
130
131
132/* Issue various I2C operations to bring chip-level drivers into sync with
133 state stored in this driver. */
134void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
135{
136 unsigned long msk;
137 unsigned int idx;
138 struct pvr2_i2c_client *cp, *ncp;
139
140 if (!hdw->i2c_linked) return;
141 if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
142 return;
143 }
144 mutex_lock(&hdw->i2c_list_lock); do {
145 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
146 if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
147 /* One or more I2C clients have attached since we
148 last synced. So scan the list and identify the
149 new clients. */
150 char *buf;
151 unsigned int cnt;
152 unsigned long amask = 0;
153 buf = kmalloc(BUFSIZE,GFP_KERNEL);
154 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
155 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
156 list_for_each_entry(cp, &hdw->i2c_clients, list) {
157 if (!cp->detected_flag) {
158 cp->ctl_mask = 0;
159 pvr2_i2c_probe(hdw,cp);
160 cp->detected_flag = !0;
161 msk = cp->ctl_mask;
162 cnt = 0;
163 if (buf) {
164 cnt = pvr2_i2c_client_describe(
165 cp,
166 PVR2_I2C_DETAIL_ALL,
167 buf,BUFSIZE);
168 }
169 trace_i2c("Probed: %.*s",cnt,buf);
170 if (handler_check(cp)) {
171 hdw->i2c_pend_types |=
172 PVR2_I2C_PEND_CLIENT;
173 }
174 cp->pend_mask = msk;
175 hdw->i2c_pend_mask |= msk;
176 hdw->i2c_pend_types |=
177 PVR2_I2C_PEND_REFRESH;
178 }
179 amask |= cp->ctl_mask;
180 }
181 hdw->i2c_active_mask = amask;
182 if (buf) kfree(buf);
183 }
184 if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
185 /* Need to do one or more global updates. Arrange
186 for this to happen. */
187 unsigned long m2;
188 pvr2_trace(PVR2_TRACE_I2C_CORE,
189 "i2c: PEND_STALE (0x%lx)",
190 hdw->i2c_stale_mask);
191 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
192 list_for_each_entry(cp, &hdw->i2c_clients, list) {
193 m2 = hdw->i2c_stale_mask;
194 m2 &= cp->ctl_mask;
195 m2 &= ~cp->pend_mask;
196 if (m2) {
197 pvr2_trace(PVR2_TRACE_I2C_CORE,
198 "i2c: cp=%p setting 0x%lx",
199 cp,m2);
200 cp->pend_mask |= m2;
201 }
202 }
203 hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
204 hdw->i2c_stale_mask = 0;
205 hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
206 }
207 if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
208 /* One or more client handlers are asking for an
209 update. Run through the list of known clients
210 and update each one. */
211 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
212 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
213 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
214 list) {
215 if (!cp->handler) continue;
216 if (!cp->handler->func_table->update) continue;
217 pvr2_trace(PVR2_TRACE_I2C_CORE,
218 "i2c: cp=%p update",cp);
219 mutex_unlock(&hdw->i2c_list_lock);
220 cp->handler->func_table->update(
221 cp->handler->func_data);
222 mutex_lock(&hdw->i2c_list_lock);
223 /* If client's update function set some
224 additional pending bits, account for that
225 here. */
226 if (cp->pend_mask & ~hdw->i2c_pend_mask) {
227 hdw->i2c_pend_mask |= cp->pend_mask;
228 hdw->i2c_pend_types |=
229 PVR2_I2C_PEND_REFRESH;
230 }
231 }
232 }
233 if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
234 const struct pvr2_i2c_op *opf;
235 unsigned long pm;
236 /* Some actual updates are pending. Walk through
237 each update type and perform it. */
238 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
239 " (0x%lx)",hdw->i2c_pend_mask);
240 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
241 pm = hdw->i2c_pend_mask;
242 hdw->i2c_pend_mask = 0;
243 for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
244 if (!(pm & msk)) continue;
245 pm &= ~msk;
246 list_for_each_entry(cp, &hdw->i2c_clients,
247 list) {
248 if (cp->pend_mask & msk) {
249 cp->pend_mask &= ~msk;
250 cp->recv_enable = !0;
251 } else {
252 cp->recv_enable = 0;
253 }
254 }
255 opf = pvr2_i2c_get_op(idx);
256 if (!opf) continue;
257 mutex_unlock(&hdw->i2c_list_lock);
258 opf->update(hdw);
259 mutex_lock(&hdw->i2c_list_lock);
260 }
261 }
262 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
263 } while (0); mutex_unlock(&hdw->i2c_list_lock);
264}
265
266int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
267{
268 unsigned long msk,sm,pm;
269 unsigned int idx;
270 const struct pvr2_i2c_op *opf;
271 struct pvr2_i2c_client *cp;
272 unsigned int pt = 0;
273
274 pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
275
276 pm = hdw->i2c_active_mask;
277 sm = 0;
278 for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
279 if (!(msk & pm)) continue;
280 pm &= ~msk;
281 opf = pvr2_i2c_get_op(idx);
282 if (!(opf && opf->check)) continue;
283 if (opf->check(hdw)) {
284 sm |= msk;
285 }
286 }
287 if (sm) pt |= PVR2_I2C_PEND_STALE;
288
289 list_for_each_entry(cp, &hdw->i2c_clients, list)
290 if (handler_check(cp))
291 pt |= PVR2_I2C_PEND_CLIENT;
292
293 if (pt) {
294 mutex_lock(&hdw->i2c_list_lock); do {
295 hdw->i2c_pend_types |= pt;
296 hdw->i2c_stale_mask |= sm;
297 hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
298 } while (0); mutex_unlock(&hdw->i2c_list_lock);
299 }
300
301 pvr2_trace(PVR2_TRACE_I2C_CORE,
302 "i2c: types=0x%x stale=0x%lx pend=0x%lx",
303 hdw->i2c_pend_types,
304 hdw->i2c_stale_mask,
305 hdw->i2c_pend_mask);
306 pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
307
308 return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
309}
310
311static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
312 unsigned int detail,
313 char *buf,unsigned int maxlen)
314{
315 unsigned int ccnt,bcnt;
316 int spcfl = 0;
317 const struct pvr2_i2c_op *opf;
318
319 ccnt = 0;
320 if (detail & PVR2_I2C_DETAIL_DEBUG) {
321 bcnt = scnprintf(buf,maxlen,
322 "ctxt=%p ctl_mask=0x%lx",
323 cp,cp->ctl_mask);
324 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
325 spcfl = !0;
326 }
327 bcnt = scnprintf(buf,maxlen,
328 "%s%s @ 0x%x",
329 (spcfl ? " " : ""),
330 cp->client->name,
331 cp->client->addr);
332 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
333 if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
334 cp->handler && cp->handler->func_table->describe) {
335 bcnt = scnprintf(buf,maxlen," (");
336 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
337 bcnt = cp->handler->func_table->describe(
338 cp->handler->func_data,buf,maxlen);
339 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
340 bcnt = scnprintf(buf,maxlen,")");
341 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
342 }
343 if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
344 unsigned int idx;
345 unsigned long msk,sm;
346
347 bcnt = scnprintf(buf,maxlen," [");
348 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
349 sm = 0;
350 spcfl = 0;
351 for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
352 if (!(cp->ctl_mask & msk)) continue;
353 opf = pvr2_i2c_get_op(idx);
354 if (opf) {
355 bcnt = scnprintf(buf,maxlen,"%s%s",
356 spcfl ? " " : "",
357 opf->name);
358 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
359 spcfl = !0;
360 } else {
361 sm |= msk;
362 }
363 }
364 if (sm) {
365 bcnt = scnprintf(buf,maxlen,"%s%lx",
366 idx != 0 ? " " : "",sm);
367 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
368 }
369 bcnt = scnprintf(buf,maxlen,"]");
370 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
371 }
372 return ccnt;
373}
374
375unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
376 char *buf,unsigned int maxlen)
377{
378 unsigned int ccnt,bcnt;
379 struct pvr2_i2c_client *cp;
380 ccnt = 0;
381 mutex_lock(&hdw->i2c_list_lock); do {
382 list_for_each_entry(cp, &hdw->i2c_clients, list) {
383 bcnt = pvr2_i2c_client_describe(
384 cp,
385 (PVR2_I2C_DETAIL_HANDLER|
386 PVR2_I2C_DETAIL_CTLMASK),
387 buf,maxlen);
388 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
389 bcnt = scnprintf(buf,maxlen,"\n");
390 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
391 }
392 } while (0); mutex_unlock(&hdw->i2c_list_lock);
393 return ccnt;
394}
395
396void pvr2_i2c_track_attach_inform(struct i2c_client *client)
397{
398 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
399 struct pvr2_i2c_client *cp;
400 int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
401 cp = kzalloc(sizeof(*cp),GFP_KERNEL);
402 trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
403 client->name,
404 client->addr,cp);
405 if (!cp) {
406 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
407 "Unable to allocate tracking memory for incoming"
408 " i2c module; ignoring module. This is likely"
409 " going to be a problem.");
410 return;
411 }
412 cp->hdw = hdw;
413 INIT_LIST_HEAD(&cp->list);
414 cp->client = client;
415 mutex_lock(&hdw->i2c_list_lock); do {
416 hdw->cropcap_stale = !0;
417 list_add_tail(&cp->list,&hdw->i2c_clients);
418 hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
419 } while (0); mutex_unlock(&hdw->i2c_list_lock);
420 if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
421}
422
423void pvr2_i2c_track_detach_inform(struct i2c_client *client)
424{
425 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
426 struct pvr2_i2c_client *cp, *ncp;
427 unsigned long amask = 0;
428 int foundfl = 0;
429 mutex_lock(&hdw->i2c_list_lock); do {
430 hdw->cropcap_stale = !0;
431 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
432 if (cp->client == client) {
433 trace_i2c("pvr2_i2c_detach"
434 " [client=%s @ 0x%x ctxt=%p]",
435 client->name,
436 client->addr,cp);
437 if (cp->handler &&
438 cp->handler->func_table->detach) {
439 cp->handler->func_table->detach(
440 cp->handler->func_data);
441 }
442 list_del(&cp->list);
443 kfree(cp);
444 foundfl = !0;
445 continue;
446 }
447 amask |= cp->ctl_mask;
448 }
449 hdw->i2c_active_mask = amask;
450 } while (0); mutex_unlock(&hdw->i2c_list_lock);
451 if (!foundfl) {
452 trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
453 client->name,
454 client->addr);
455 }
456}
457
458void pvr2_i2c_track_init(struct pvr2_hdw *hdw)
459{
460 hdw->i2c_pend_mask = 0;
461 hdw->i2c_stale_mask = 0;
462 hdw->i2c_active_mask = 0;
463 INIT_LIST_HEAD(&hdw->i2c_clients);
464 mutex_init(&hdw->i2c_list_lock);
465}
466
467void pvr2_i2c_track_done(struct pvr2_hdw *hdw)
468{
469 /* Empty for now */
470}
471
472/*
473 Stuff for Emacs to see, in order to encourage consistent editing style:
474 *** Local Variables: ***
475 *** mode: c ***
476 *** fill-column: 75 ***
477 *** tab-width: 8 ***
478 *** c-basic-offset: 8 ***
479 *** End: ***
480 */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h
new file mode 100644
index 000000000000..7d0e4fb63785
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.h
@@ -0,0 +1,97 @@
1/*
2 *
3 *
4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20#ifndef __PVRUSB2_I2C_TRACK_H
21#define __PVRUSB2_I2C_TRACK_H
22
23#include <linux/list.h>
24#include <linux/i2c.h>
25
26struct pvr2_hdw;
27struct pvr2_i2c_client;
28struct pvr2_i2c_handler;
29struct pvr2_i2c_handler_functions;
30struct pvr2_i2c_op;
31struct pvr2_i2c_op_functions;
32
33struct pvr2_i2c_client {
34 struct i2c_client *client;
35 struct pvr2_i2c_handler *handler;
36 struct list_head list;
37 struct pvr2_hdw *hdw;
38 int detected_flag;
39 int recv_enable;
40 unsigned long pend_mask;
41 unsigned long ctl_mask;
42 void (*status_poll)(struct pvr2_i2c_client *);
43};
44
45struct pvr2_i2c_handler {
46 void *func_data;
47 const struct pvr2_i2c_handler_functions *func_table;
48};
49
50struct pvr2_i2c_handler_functions {
51 void (*detach)(void *);
52 int (*check)(void *);
53 void (*update)(void *);
54 unsigned int (*describe)(void *,char *,unsigned int);
55};
56
57struct pvr2_i2c_op {
58 int (*check)(struct pvr2_hdw *);
59 void (*update)(struct pvr2_hdw *);
60 const char *name;
61};
62
63void pvr2_i2c_track_init(struct pvr2_hdw *);
64void pvr2_i2c_track_done(struct pvr2_hdw *);
65void pvr2_i2c_track_attach_inform(struct i2c_client *);
66void pvr2_i2c_track_detach_inform(struct i2c_client *);
67
68int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
69int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
70
71int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
72void pvr2_i2c_core_sync(struct pvr2_hdw *);
73void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
74unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
75#define PVR2_I2C_DETAIL_DEBUG 0x0001
76#define PVR2_I2C_DETAIL_HANDLER 0x0002
77#define PVR2_I2C_DETAIL_CTLMASK 0x0004
78#define PVR2_I2C_DETAIL_ALL (\
79 PVR2_I2C_DETAIL_DEBUG |\
80 PVR2_I2C_DETAIL_HANDLER |\
81 PVR2_I2C_DETAIL_CTLMASK)
82
83void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
84const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
85
86#endif /* __PVRUSB2_I2C_CORE_H */
87
88
89/*
90 Stuff for Emacs to see, in order to encourage consistent editing style:
91 *** Local Variables: ***
92 *** mode: c ***
93 *** fill-column: 75 ***
94 *** tab-width: 8 ***
95 *** c-basic-offset: 8 ***
96 *** End: ***
97 */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
index ef4afaf37b0a..3643e2c7880f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
@@ -20,7 +20,7 @@
20#ifndef __PVRUSB2_TUNER_H 20#ifndef __PVRUSB2_TUNER_H
21#define __PVRUSB2_TUNER_H 21#define __PVRUSB2_TUNER_H
22 22
23#include "pvrusb2-i2c-core.h" 23#include "pvrusb2-i2c-track.h"
24 24
25int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); 25int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
26 26
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
index 4ff5b892b303..b2cd3875bb5b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
@@ -33,7 +33,7 @@
33 33
34 34
35 35
36#include "pvrusb2-i2c-core.h" 36#include "pvrusb2-i2c-track.h"
37 37
38int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); 38int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
39 39
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
index 807090961255..5b2cb6183576 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
@@ -34,7 +34,7 @@
34 34
35 35
36 36
37#include "pvrusb2-i2c-core.h" 37#include "pvrusb2-i2c-track.h"
38 38
39int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); 39int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
40 40