aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-02-14 00:32:39 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:01 -0400
commit1a2670465ec94029e5df62e3decca9e2f7aea075 (patch)
tree23b2984c9d92089a726da305a13f53388d7c348c
parenta0beec8f6fd37fc1418970ab6a574fabedd9e324 (diff)
V4L/DVB (10755): cx18: Convert the integrated A/V decoder core interface to a v4l2_subdev
This is the next step in converting the cx18 driver to use the v4l2_device/ v4l2_subdevice framework. This is a straightforward conversion of the cx18_av_*[ch] files. It compiles, but leaves the driver in an unlinkable state at the moment. Note, the cx18 integrated A/V digitizer will now make a host match at address 1, as far as v4l2-dbg is concerned. That means it identifies itself as a separate "chip", and acts as an alias to the integrated A/V decoder registers that are also available with the host match at address 0. Signed-off-by: Andy Walls <awalls@radix.net> [mchehab@redhat.com: fix merge conflicts due to the removal of v4l2_ctrl_query_fill_std()] Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c583
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h13
2 files changed, 336 insertions, 260 deletions
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index fc576cf1a8b5..9b30f77b5205 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -22,8 +22,10 @@
22 * 02110-1301, USA. 22 * 02110-1301, USA.
23 */ 23 */
24 24
25#include <media/v4l2-chip-ident.h>
25#include "cx18-driver.h" 26#include "cx18-driver.h"
26#include "cx18-io.h" 27#include "cx18-io.h"
28#include "cx18-cards.h"
27 29
28int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) 30int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
29{ 31{
@@ -97,15 +99,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
97 or_value); 99 or_value);
98} 100}
99 101
100/* ----------------------------------------------------------------------- */
101
102static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
103 enum cx18_av_audio_input aud_input);
104static void log_audio_status(struct cx18 *cx);
105static void log_video_status(struct cx18 *cx);
106
107/* ----------------------------------------------------------------------- */
108
109static void cx18_av_initialize(struct cx18 *cx) 102static void cx18_av_initialize(struct cx18 *cx)
110{ 103{
111 struct cx18_av_state *state = &cx->av_state; 104 struct cx18_av_state *state = &cx->av_state;
@@ -200,7 +193,26 @@ static void cx18_av_initialize(struct cx18 *cx)
200 state->default_volume = ((state->default_volume / 2) + 23) << 9; 193 state->default_volume = ((state->default_volume / 2) + 23) << 9;
201} 194}
202 195
203/* ----------------------------------------------------------------------- */ 196static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
197{
198 struct cx18 *cx = v4l2_get_subdevdata(sd);
199
200 cx18_av_initialize(cx);
201 return 0;
202}
203
204static int cx18_av_init_hardware(struct v4l2_subdev *sd, u32 val)
205{
206 struct cx18_av_state *state = to_cx18_av_state(sd);
207 struct cx18 *cx = v4l2_get_subdevdata(sd);
208
209 if (!state->is_initialized) {
210 /* initialize on first use */
211 state->is_initialized = 1;
212 cx18_av_initialize(cx);
213 }
214 return 0;
215}
204 216
205void cx18_av_std_setup(struct cx18 *cx) 217void cx18_av_std_setup(struct cx18 *cx)
206{ 218{
@@ -362,7 +374,18 @@ void cx18_av_std_setup(struct cx18 *cx)
362 cx18_av_write(cx, 0x47f, state->slicer_line_delay); 374 cx18_av_write(cx, 0x47f, state->slicer_line_delay);
363} 375}
364 376
365/* ----------------------------------------------------------------------- */ 377static int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
378 struct v4l2_decode_vbi_line *vbi_line)
379{
380 struct cx18 *cx = v4l2_get_subdevdata(sd);
381 return cx18_av_vbi(cx, VIDIOC_INT_DECODE_VBI_LINE, vbi_line);
382}
383
384static int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
385{
386 struct cx18 *cx = v4l2_get_subdevdata(sd);
387 return cx18_av_audio(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freq);
388}
366 389
367static void input_change(struct cx18 *cx) 390static void input_change(struct cx18 *cx)
368{ 391{
@@ -409,6 +432,14 @@ static void input_change(struct cx18 *cx)
409 } 432 }
410} 433}
411 434
435static int cx18_av_s_frequency(struct v4l2_subdev *sd,
436 struct v4l2_frequency *freq)
437{
438 struct cx18 *cx = v4l2_get_subdevdata(sd);
439 input_change(cx);
440 return 0;
441}
442
412static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, 443static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
413 enum cx18_av_audio_input aud_input) 444 enum cx18_av_audio_input aud_input)
414{ 445{
@@ -488,14 +519,118 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
488 return 0; 519 return 0;
489} 520}
490 521
491/* ----------------------------------------------------------------------- */ 522static int cx18_av_s_video_routing(struct v4l2_subdev *sd,
523 const struct v4l2_routing *route)
524{
525 struct cx18_av_state *state = to_cx18_av_state(sd);
526 struct cx18 *cx = v4l2_get_subdevdata(sd);
527 return set_input(cx, route->input, state->aud_input);
528}
492 529
493static int set_v4lstd(struct cx18 *cx) 530static int cx18_av_s_audio_routing(struct v4l2_subdev *sd,
531 const struct v4l2_routing *route)
494{ 532{
495 struct cx18_av_state *state = &cx->av_state; 533 struct cx18_av_state *state = to_cx18_av_state(sd);
534 struct cx18 *cx = v4l2_get_subdevdata(sd);
535 return set_input(cx, state->vid_input, route->input);
536}
537
538static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
539{
540 struct cx18_av_state *state = to_cx18_av_state(sd);
541 struct cx18 *cx = v4l2_get_subdevdata(sd);
542 u8 vpres;
543 u8 mode;
544 int val = 0;
545
546 if (state->radio)
547 return 0;
548
549 vpres = cx18_av_read(cx, 0x40e) & 0x20;
550 vt->signal = vpres ? 0xffff : 0x0;
551
552 vt->capability |=
553 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
554 V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
555
556 mode = cx18_av_read(cx, 0x804);
557
558 /* get rxsubchans and audmode */
559 if ((mode & 0xf) == 1)
560 val |= V4L2_TUNER_SUB_STEREO;
561 else
562 val |= V4L2_TUNER_SUB_MONO;
563
564 if (mode == 2 || mode == 4)
565 val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
566
567 if (mode & 0x10)
568 val |= V4L2_TUNER_SUB_SAP;
569
570 vt->rxsubchans = val;
571 vt->audmode = state->audmode;
572 return 0;
573}
574
575static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
576{
577 struct cx18_av_state *state = to_cx18_av_state(sd);
578 struct cx18 *cx = v4l2_get_subdevdata(sd);
579 u8 v;
580
581 if (state->radio)
582 return 0;
583
584 v = cx18_av_read(cx, 0x809);
585 v &= ~0xf;
586
587 switch (vt->audmode) {
588 case V4L2_TUNER_MODE_MONO:
589 /* mono -> mono
590 stereo -> mono
591 bilingual -> lang1 */
592 break;
593 case V4L2_TUNER_MODE_STEREO:
594 case V4L2_TUNER_MODE_LANG1:
595 /* mono -> mono
596 stereo -> stereo
597 bilingual -> lang1 */
598 v |= 0x4;
599 break;
600 case V4L2_TUNER_MODE_LANG1_LANG2:
601 /* mono -> mono
602 stereo -> stereo
603 bilingual -> lang1/lang2 */
604 v |= 0x7;
605 break;
606 case V4L2_TUNER_MODE_LANG2:
607 /* mono -> mono
608 stereo -> stereo
609 bilingual -> lang2 */
610 v |= 0x1;
611 break;
612 default:
613 return -EINVAL;
614 }
615 cx18_av_write_expect(cx, 0x809, v, v, 0xff);
616 state->audmode = vt->audmode;
617 return 0;
618}
619
620static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
621{
622 struct cx18_av_state *state = to_cx18_av_state(sd);
623 struct cx18 *cx = v4l2_get_subdevdata(sd);
624
496 u8 fmt = 0; /* zero is autodetect */ 625 u8 fmt = 0; /* zero is autodetect */
497 u8 pal_m = 0; 626 u8 pal_m = 0;
498 627
628 if (state->radio == 0 && state->std == norm)
629 return 0;
630
631 state->radio = 0;
632 state->std = norm;
633
499 /* First tests should be against specific std */ 634 /* First tests should be against specific std */
500 if (state->std == V4L2_STD_NTSC_M_JP) { 635 if (state->std == V4L2_STD_NTSC_M_JP) {
501 fmt = 0x2; 636 fmt = 0x2;
@@ -538,10 +673,17 @@ static int set_v4lstd(struct cx18 *cx)
538 return 0; 673 return 0;
539} 674}
540 675
541/* ----------------------------------------------------------------------- */ 676static int cx18_av_s_radio(struct v4l2_subdev *sd)
677{
678 struct cx18_av_state *state = to_cx18_av_state(sd);
679 state->radio = 1;
680 return 0;
681}
542 682
543static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) 683static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
544{ 684{
685 struct cx18 *cx = v4l2_get_subdevdata(sd);
686
545 switch (ctrl->id) { 687 switch (ctrl->id) {
546 case V4L2_CID_BRIGHTNESS: 688 case V4L2_CID_BRIGHTNESS:
547 if (ctrl->value < 0 || ctrl->value > 255) { 689 if (ctrl->value < 0 || ctrl->value > 255) {
@@ -593,12 +735,13 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
593 default: 735 default:
594 return -EINVAL; 736 return -EINVAL;
595 } 737 }
596
597 return 0; 738 return 0;
598} 739}
599 740
600static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) 741static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
601{ 742{
743 struct cx18 *cx = v4l2_get_subdevdata(sd);
744
602 switch (ctrl->id) { 745 switch (ctrl->id) {
603 case V4L2_CID_BRIGHTNESS: 746 case V4L2_CID_BRIGHTNESS:
604 ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; 747 ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
@@ -621,27 +764,59 @@ static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
621 default: 764 default:
622 return -EINVAL; 765 return -EINVAL;
623 } 766 }
624
625 return 0; 767 return 0;
626} 768}
627 769
628/* ----------------------------------------------------------------------- */ 770static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
771{
772 struct cx18_av_state *state = to_cx18_av_state(sd);
773
774 switch (qc->id) {
775 case V4L2_CID_BRIGHTNESS:
776 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
777 case V4L2_CID_CONTRAST:
778 case V4L2_CID_SATURATION:
779 return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
780 case V4L2_CID_HUE:
781 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
782 default:
783 break;
784 }
785
786 switch (qc->id) {
787 case V4L2_CID_AUDIO_VOLUME:
788 return v4l2_ctrl_query_fill(qc, 0, 65535,
789 65535 / 100, state->default_volume);
790 case V4L2_CID_AUDIO_MUTE:
791 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
792 case V4L2_CID_AUDIO_BALANCE:
793 case V4L2_CID_AUDIO_BASS:
794 case V4L2_CID_AUDIO_TREBLE:
795 return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
796 default:
797 return -EINVAL;
798 }
799 return -EINVAL;
800}
629 801
630static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) 802static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
631{ 803{
804 struct cx18 *cx = v4l2_get_subdevdata(sd);
805
632 switch (fmt->type) { 806 switch (fmt->type) {
633 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: 807 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
634 return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt); 808 return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
635 default: 809 default:
636 return -EINVAL; 810 return -EINVAL;
637 } 811 }
638
639 return 0; 812 return 0;
640} 813}
641 814
642static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) 815static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
643{ 816{
644 struct cx18_av_state *state = &cx->av_state; 817 struct cx18_av_state *state = to_cx18_av_state(sd);
818 struct cx18 *cx = v4l2_get_subdevdata(sd);
819
645 struct v4l2_pix_format *pix; 820 struct v4l2_pix_format *pix;
646 int HSC, VSC, Vsrc, Hsrc, filter, Vlines; 821 int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
647 int is_50Hz = !(state->std & V4L2_STD_525_60); 822 int is_50Hz = !(state->std & V4L2_STD_525_60);
@@ -701,252 +876,24 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
701 default: 876 default:
702 return -EINVAL; 877 return -EINVAL;
703 } 878 }
704
705 return 0; 879 return 0;
706} 880}
707 881
708/* ----------------------------------------------------------------------- */ 882static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable)
709
710static int valid_av_cmd(unsigned int cmd)
711{ 883{
712 switch (cmd) { 884 struct cx18 *cx = v4l2_get_subdevdata(sd);
713 /* All commands supported by cx18_av_cmd() */
714 case VIDIOC_INT_DECODE_VBI_LINE:
715 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
716 case VIDIOC_STREAMON:
717 case VIDIOC_STREAMOFF:
718 case VIDIOC_LOG_STATUS:
719 case VIDIOC_G_CTRL:
720 case VIDIOC_S_CTRL:
721 case VIDIOC_QUERYCTRL:
722 case VIDIOC_G_STD:
723 case VIDIOC_S_STD:
724 case AUDC_SET_RADIO:
725 case VIDIOC_INT_G_VIDEO_ROUTING:
726 case VIDIOC_INT_S_VIDEO_ROUTING:
727 case VIDIOC_INT_G_AUDIO_ROUTING:
728 case VIDIOC_INT_S_AUDIO_ROUTING:
729 case VIDIOC_S_FREQUENCY:
730 case VIDIOC_G_TUNER:
731 case VIDIOC_S_TUNER:
732 case VIDIOC_G_FMT:
733 case VIDIOC_S_FMT:
734 case VIDIOC_INT_RESET:
735 return 1;
736 default:
737 return 0;
738 }
739 return 0;
740}
741
742int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
743{
744 struct cx18_av_state *state = &cx->av_state;
745 struct v4l2_tuner *vt = arg;
746 struct v4l2_routing *route = arg;
747
748 if (!state->is_initialized && valid_av_cmd(cmd)) {
749 CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
750 /* initialize on first use */
751 state->is_initialized = 1;
752 cx18_av_initialize(cx);
753 }
754
755 switch (cmd) {
756 case VIDIOC_INT_DECODE_VBI_LINE:
757 return cx18_av_vbi(cx, cmd, arg);
758
759 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
760 return cx18_av_audio(cx, cmd, arg);
761 885
762 case VIDIOC_STREAMON: 886 CX18_DEBUG_INFO("%s output\n", enable ? "enable" : "disable");
763 CX18_DEBUG_INFO("enable output\n"); 887 if (enable) {
764 cx18_av_write(cx, 0x115, 0x8c); 888 cx18_av_write(cx, 0x115, 0x8c);
765 cx18_av_write(cx, 0x116, 0x07); 889 cx18_av_write(cx, 0x116, 0x07);
766 break; 890 } else {
767
768 case VIDIOC_STREAMOFF:
769 CX18_DEBUG_INFO("disable output\n");
770 cx18_av_write(cx, 0x115, 0x00); 891 cx18_av_write(cx, 0x115, 0x00);
771 cx18_av_write(cx, 0x116, 0x00); 892 cx18_av_write(cx, 0x116, 0x00);
772 break;
773
774 case VIDIOC_LOG_STATUS:
775 log_video_status(cx);
776 log_audio_status(cx);
777 break;
778
779 case VIDIOC_G_CTRL:
780 return get_v4lctrl(cx, (struct v4l2_control *)arg);
781
782 case VIDIOC_S_CTRL:
783 return set_v4lctrl(cx, (struct v4l2_control *)arg);
784
785 case VIDIOC_QUERYCTRL:
786 {
787 struct v4l2_queryctrl *qc = arg;
788
789 switch (qc->id) {
790 case V4L2_CID_BRIGHTNESS:
791 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
792 case V4L2_CID_CONTRAST:
793 case V4L2_CID_SATURATION:
794 return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
795 case V4L2_CID_HUE:
796 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
797 default:
798 break;
799 }
800
801 switch (qc->id) {
802 case V4L2_CID_AUDIO_VOLUME:
803 return v4l2_ctrl_query_fill(qc, 0, 65535,
804 65535 / 100, state->default_volume);
805 case V4L2_CID_AUDIO_MUTE:
806 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
807 case V4L2_CID_AUDIO_BALANCE:
808 case V4L2_CID_AUDIO_BASS:
809 case V4L2_CID_AUDIO_TREBLE:
810 return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
811 default:
812 return -EINVAL;
813 }
814 return -EINVAL;
815 }
816
817 case VIDIOC_G_STD:
818 *(v4l2_std_id *)arg = state->std;
819 break;
820
821 case VIDIOC_S_STD:
822 if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
823 return 0;
824 state->radio = 0;
825 state->std = *(v4l2_std_id *)arg;
826 return set_v4lstd(cx);
827
828 case AUDC_SET_RADIO:
829 state->radio = 1;
830 break;
831
832 case VIDIOC_INT_G_VIDEO_ROUTING:
833 route->input = state->vid_input;
834 route->output = 0;
835 break;
836
837 case VIDIOC_INT_S_VIDEO_ROUTING:
838 return set_input(cx, route->input, state->aud_input);
839
840 case VIDIOC_INT_G_AUDIO_ROUTING:
841 route->input = state->aud_input;
842 route->output = 0;
843 break;
844
845 case VIDIOC_INT_S_AUDIO_ROUTING:
846 return set_input(cx, state->vid_input, route->input);
847
848 case VIDIOC_S_FREQUENCY:
849 input_change(cx);
850 break;
851
852 case VIDIOC_G_TUNER:
853 {
854 u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
855 u8 mode;
856 int val = 0;
857
858 if (state->radio)
859 break;
860
861 vt->signal = vpres ? 0xffff : 0x0;
862
863 vt->capability |=
864 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
865 V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
866
867 mode = cx18_av_read(cx, 0x804);
868
869 /* get rxsubchans and audmode */
870 if ((mode & 0xf) == 1)
871 val |= V4L2_TUNER_SUB_STEREO;
872 else
873 val |= V4L2_TUNER_SUB_MONO;
874
875 if (mode == 2 || mode == 4)
876 val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
877
878 if (mode & 0x10)
879 val |= V4L2_TUNER_SUB_SAP;
880
881 vt->rxsubchans = val;
882 vt->audmode = state->audmode;
883 break;
884 } 893 }
885
886 case VIDIOC_S_TUNER:
887 {
888 u8 v;
889
890 if (state->radio)
891 break;
892
893 v = cx18_av_read(cx, 0x809);
894 v &= ~0xf;
895
896 switch (vt->audmode) {
897 case V4L2_TUNER_MODE_MONO:
898 /* mono -> mono
899 stereo -> mono
900 bilingual -> lang1 */
901 break;
902 case V4L2_TUNER_MODE_STEREO:
903 case V4L2_TUNER_MODE_LANG1:
904 /* mono -> mono
905 stereo -> stereo
906 bilingual -> lang1 */
907 v |= 0x4;
908 break;
909 case V4L2_TUNER_MODE_LANG1_LANG2:
910 /* mono -> mono
911 stereo -> stereo
912 bilingual -> lang1/lang2 */
913 v |= 0x7;
914 break;
915 case V4L2_TUNER_MODE_LANG2:
916 /* mono -> mono
917 stereo -> stereo
918 bilingual -> lang2 */
919 v |= 0x1;
920 break;
921 default:
922 return -EINVAL;
923 }
924 cx18_av_write_expect(cx, 0x809, v, v, 0xff);
925 state->audmode = vt->audmode;
926 break;
927 }
928
929 case VIDIOC_G_FMT:
930 return get_v4lfmt(cx, (struct v4l2_format *)arg);
931
932 case VIDIOC_S_FMT:
933 return set_v4lfmt(cx, (struct v4l2_format *)arg);
934
935 case VIDIOC_INT_RESET:
936 cx18_av_initialize(cx);
937 break;
938
939 default:
940 return -EINVAL;
941 }
942
943 return 0; 894 return 0;
944} 895}
945 896
946/* ----------------------------------------------------------------------- */
947
948/* ----------------------------------------------------------------------- */
949
950static void log_video_status(struct cx18 *cx) 897static void log_video_status(struct cx18 *cx)
951{ 898{
952 static const char *const fmt_strs[] = { 899 static const char *const fmt_strs[] = {
@@ -984,8 +931,6 @@ static void log_video_status(struct cx18 *cx)
984 CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq); 931 CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
985} 932}
986 933
987/* ----------------------------------------------------------------------- */
988
989static void log_audio_status(struct cx18 *cx) 934static void log_audio_status(struct cx18 *cx)
990{ 935{
991 struct cx18_av_state *state = &cx->av_state; 936 struct cx18_av_state *state = &cx->av_state;
@@ -1133,3 +1078,123 @@ static void log_audio_status(struct cx18 *cx)
1133 CX18_INFO("Selected 45 MHz format: %s\n", p); 1078 CX18_INFO("Selected 45 MHz format: %s\n", p);
1134 } 1079 }
1135} 1080}
1081
1082static int cx18_av_log_status(struct v4l2_subdev *sd)
1083{
1084 struct cx18 *cx = v4l2_get_subdevdata(sd);
1085 log_video_status(cx);
1086 log_audio_status(cx);
1087 return 0;
1088}
1089
1090static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match)
1091{
1092 return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1;
1093}
1094
1095static int cx18_av_g_chip_ident(struct v4l2_subdev *sd,
1096 struct v4l2_dbg_chip_ident *chip)
1097{
1098 if (cx18_av_dbg_match(&chip->match)) {
1099 /*
1100 * Nothing else is going to claim to be this combination,
1101 * and the real host chip revision will be returned by a host
1102 * match on address 0.
1103 */
1104 chip->ident = V4L2_IDENT_CX25843;
1105 chip->revision = V4L2_IDENT_CX23418; /* Why not */
1106 }
1107 return 0;
1108}
1109
1110#ifdef CONFIG_VIDEO_ADV_DEBUG
1111static int cx18_av_g_register(struct v4l2_subdev *sd,
1112 struct v4l2_dbg_register *reg)
1113{
1114 struct cx18 *cx = v4l2_get_subdevdata(sd);
1115
1116 if (!cx18_av_dbg_match(&reg->match))
1117 return -EINVAL;
1118 if ((reg->reg & 0x3) != 0)
1119 return -EINVAL;
1120 if (!capable(CAP_SYS_ADMIN))
1121 return -EPERM;
1122 reg->size = 4;
1123 reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc);
1124 return 0;
1125}
1126
1127static int cx18_av_s_register(struct v4l2_subdev *sd,
1128 struct v4l2_dbg_register *reg)
1129{
1130 struct cx18 *cx = v4l2_get_subdevdata(sd);
1131
1132 if (!cx18_av_dbg_match(&reg->match))
1133 return -EINVAL;
1134 if ((reg->reg & 0x3) != 0)
1135 return -EINVAL;
1136 if (!capable(CAP_SYS_ADMIN))
1137 return -EPERM;
1138 cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val);
1139 return 0;
1140}
1141#endif
1142
1143static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
1144 .g_chip_ident = cx18_av_g_chip_ident,
1145 .log_status = cx18_av_log_status,
1146 .init = cx18_av_init_hardware,
1147 .reset = cx18_av_reset,
1148 .queryctrl = cx18_av_queryctrl,
1149 .g_ctrl = cx18_av_g_ctrl,
1150 .s_ctrl = cx18_av_s_ctrl,
1151#ifdef CONFIG_VIDEO_ADV_DEBUG
1152 .g_register = cx18_av_g_register,
1153 .s_register = cx18_av_s_register,
1154#endif
1155};
1156
1157static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = {
1158 .s_radio = cx18_av_s_radio,
1159 .s_frequency = cx18_av_s_frequency,
1160 .g_tuner = cx18_av_g_tuner,
1161 .s_tuner = cx18_av_s_tuner,
1162 .s_std = cx18_av_s_std,
1163};
1164
1165static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
1166 .s_clock_freq = cx18_av_s_clock_freq,
1167 .s_routing = cx18_av_s_audio_routing,
1168};
1169
1170static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
1171 .s_routing = cx18_av_s_video_routing,
1172 .decode_vbi_line = cx18_av_decode_vbi_line,
1173 .s_stream = cx18_av_s_stream,
1174 .g_fmt = cx18_av_g_fmt,
1175 .s_fmt = cx18_av_s_fmt,
1176};
1177
1178static const struct v4l2_subdev_ops cx18_av_ops = {
1179 .core = &cx18_av_general_ops,
1180 .tuner = &cx18_av_tuner_ops,
1181 .audio = &cx18_av_audio_ops,
1182 .video = &cx18_av_video_ops,
1183};
1184
1185int cx18_av_init(struct cx18 *cx)
1186{
1187 struct v4l2_subdev *sd = &cx->av_state.sd;
1188
1189 v4l2_subdev_init(sd, &cx18_av_ops);
1190 v4l2_set_subdevdata(sd, cx);
1191 snprintf(sd->name, sizeof(sd->name),
1192 "%s-internal A/V decoder", cx->v4l2_dev.name);
1193 sd->grp_id = CX18_HW_CX23418;
1194 return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
1195}
1196
1197void cx18_av_fini(struct cx18 *cx)
1198{
1199 v4l2_device_unregister_subdev(&cx->av_state.sd);
1200}
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index d83760cae540..025100aee4b8 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -25,6 +25,8 @@
25#ifndef _CX18_AV_CORE_H_ 25#ifndef _CX18_AV_CORE_H_
26#define _CX18_AV_CORE_H_ 26#define _CX18_AV_CORE_H_
27 27
28#include <media/v4l2-device.h>
29
28struct cx18; 30struct cx18;
29 31
30enum cx18_av_video_input { 32enum cx18_av_video_input {
@@ -73,6 +75,7 @@ enum cx18_av_audio_input {
73}; 75};
74 76
75struct cx18_av_state { 77struct cx18_av_state {
78 struct v4l2_subdev sd;
76 int radio; 79 int radio;
77 v4l2_std_id std; 80 v4l2_std_id std;
78 enum cx18_av_video_input vid_input; 81 enum cx18_av_video_input vid_input;
@@ -315,6 +318,11 @@ struct cx18_av_state {
315#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ 318#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
316#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ 319#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
317 320
321static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
322{
323 return container_of(sd, struct cx18_av_state, sd);
324}
325
318/* ----------------------------------------------------------------------- */ 326/* ----------------------------------------------------------------------- */
319/* cx18_av-core.c */ 327/* cx18_av-core.c */
320int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); 328int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
@@ -327,9 +335,12 @@ u8 cx18_av_read(struct cx18 *cx, u16 addr);
327u32 cx18_av_read4(struct cx18 *cx, u16 addr); 335u32 cx18_av_read4(struct cx18 *cx, u16 addr);
328int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); 336int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
329int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); 337int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
330int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
331void cx18_av_std_setup(struct cx18 *cx); 338void cx18_av_std_setup(struct cx18 *cx);
332 339
340int cx18_av_cmd(struct cx18 *cx, int cmd, void *arg); /* FIXME - Remove */
341int cx18_av_init(struct cx18 *cx);
342void cx18_av_fini(struct cx18 *cx);
343
333/* ----------------------------------------------------------------------- */ 344/* ----------------------------------------------------------------------- */
334/* cx18_av-firmware.c */ 345/* cx18_av-firmware.c */
335int cx18_av_loadfw(struct cx18 *cx); 346int cx18_av_loadfw(struct cx18 *cx);