diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-11-24 16:21:40 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:41 -0500 |
commit | e8a4a9e79b169317e698a0fdc469545d93ef304b (patch) | |
tree | 7407517874c2bf35d448d2dd5b66a926e75d3970 | |
parent | 27760fc4b9b71d04568580fd44b38ac708731b28 (diff) |
V4L/DVB (9829): tuner: convert to v4l2_subdev.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/tuner-core.c | 391 |
1 files changed, 229 insertions, 162 deletions
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 4a7735c6c1a6..1fca9de04fd6 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/videodev.h> | 18 | #include <linux/videodev.h> |
19 | #include <media/tuner.h> | 19 | #include <media/tuner.h> |
20 | #include <media/tuner-types.h> | 20 | #include <media/tuner-types.h> |
21 | #include <media/v4l2-common.h> | 21 | #include <media/v4l2-device.h> |
22 | #include <media/v4l2-ioctl.h> | 22 | #include <media/v4l2-ioctl.h> |
23 | #include <media/v4l2-i2c-drv-legacy.h> | 23 | #include <media/v4l2-i2c-drv-legacy.h> |
24 | #include "mt20xx.h" | 24 | #include "mt20xx.h" |
@@ -78,6 +78,7 @@ struct tuner { | |||
78 | /* device */ | 78 | /* device */ |
79 | struct dvb_frontend fe; | 79 | struct dvb_frontend fe; |
80 | struct i2c_client *i2c; | 80 | struct i2c_client *i2c; |
81 | struct v4l2_subdev sd; | ||
81 | struct list_head list; | 82 | struct list_head list; |
82 | unsigned int using_v4l2:1; | 83 | unsigned int using_v4l2:1; |
83 | 84 | ||
@@ -95,6 +96,11 @@ struct tuner { | |||
95 | const char *name; | 96 | const char *name; |
96 | }; | 97 | }; |
97 | 98 | ||
99 | static inline struct tuner *to_tuner(struct v4l2_subdev *sd) | ||
100 | { | ||
101 | return container_of(sd, struct tuner, sd); | ||
102 | } | ||
103 | |||
98 | /* standard i2c insmod options */ | 104 | /* standard i2c insmod options */ |
99 | static unsigned short normal_i2c[] = { | 105 | static unsigned short normal_i2c[] = { |
100 | #if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) | 106 | #if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) |
@@ -213,7 +219,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) | |||
213 | 219 | ||
214 | static void tuner_status(struct dvb_frontend *fe); | 220 | static void tuner_status(struct dvb_frontend *fe); |
215 | 221 | ||
216 | static struct analog_demod_ops tuner_core_ops = { | 222 | static struct analog_demod_ops tuner_analog_ops = { |
217 | .set_params = fe_set_params, | 223 | .set_params = fe_set_params, |
218 | .standby = fe_standby, | 224 | .standby = fe_standby, |
219 | .has_signal = fe_has_signal, | 225 | .has_signal = fe_has_signal, |
@@ -224,7 +230,7 @@ static struct analog_demod_ops tuner_core_ops = { | |||
224 | /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ | 230 | /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ |
225 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) | 231 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) |
226 | { | 232 | { |
227 | struct tuner *t = i2c_get_clientdata(c); | 233 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
228 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | 234 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; |
229 | 235 | ||
230 | struct analog_parameters params = { | 236 | struct analog_parameters params = { |
@@ -259,7 +265,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) | |||
259 | 265 | ||
260 | static void set_radio_freq(struct i2c_client *c, unsigned int freq) | 266 | static void set_radio_freq(struct i2c_client *c, unsigned int freq) |
261 | { | 267 | { |
262 | struct tuner *t = i2c_get_clientdata(c); | 268 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
263 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | 269 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; |
264 | 270 | ||
265 | struct analog_parameters params = { | 271 | struct analog_parameters params = { |
@@ -294,7 +300,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) | |||
294 | 300 | ||
295 | static void set_freq(struct i2c_client *c, unsigned long freq) | 301 | static void set_freq(struct i2c_client *c, unsigned long freq) |
296 | { | 302 | { |
297 | struct tuner *t = i2c_get_clientdata(c); | 303 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
298 | 304 | ||
299 | switch (t->mode) { | 305 | switch (t->mode) { |
300 | case V4L2_TUNER_RADIO: | 306 | case V4L2_TUNER_RADIO: |
@@ -347,7 +353,7 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
347 | unsigned int new_mode_mask, unsigned int new_config, | 353 | unsigned int new_mode_mask, unsigned int new_config, |
348 | int (*tuner_callback) (void *dev, int component, int cmd, int arg)) | 354 | int (*tuner_callback) (void *dev, int component, int cmd, int arg)) |
349 | { | 355 | { |
350 | struct tuner *t = i2c_get_clientdata(c); | 356 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
351 | struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; | 357 | struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; |
352 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | 358 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; |
353 | unsigned char buffer[4]; | 359 | unsigned char buffer[4]; |
@@ -470,7 +476,7 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
470 | t->name = fe_tuner_ops->info.name; | 476 | t->name = fe_tuner_ops->info.name; |
471 | 477 | ||
472 | t->fe.analog_demod_priv = t; | 478 | t->fe.analog_demod_priv = t; |
473 | memcpy(analog_ops, &tuner_core_ops, | 479 | memcpy(analog_ops, &tuner_analog_ops, |
474 | sizeof(struct analog_demod_ops)); | 480 | sizeof(struct analog_demod_ops)); |
475 | 481 | ||
476 | } else { | 482 | } else { |
@@ -515,7 +521,7 @@ attach_failed: | |||
515 | 521 | ||
516 | static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) | 522 | static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) |
517 | { | 523 | { |
518 | struct tuner *t = i2c_get_clientdata(c); | 524 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
519 | 525 | ||
520 | if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && | 526 | if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && |
521 | (t->mode_mask & tun_setup->mode_mask))) || | 527 | (t->mode_mask & tun_setup->mode_mask))) || |
@@ -748,43 +754,56 @@ static inline int check_v4l2(struct tuner *t) | |||
748 | return 0; | 754 | return 0; |
749 | } | 755 | } |
750 | 756 | ||
751 | static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | 757 | static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type) |
752 | { | 758 | { |
753 | struct tuner *t = i2c_get_clientdata(client); | 759 | struct tuner *t = to_tuner(sd); |
754 | struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; | 760 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
761 | |||
762 | tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", | ||
763 | type->type, | ||
764 | type->addr, | ||
765 | type->mode_mask, | ||
766 | type->config); | ||
767 | |||
768 | set_addr(client, type); | ||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | static int tuner_s_radio(struct v4l2_subdev *sd) | ||
773 | { | ||
774 | struct tuner *t = to_tuner(sd); | ||
775 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
776 | |||
777 | if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO") | ||
778 | == -EINVAL) | ||
779 | return 0; | ||
780 | if (t->radio_freq) | ||
781 | set_freq(client, t->radio_freq); | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby) | ||
786 | { | ||
787 | struct tuner *t = to_tuner(sd); | ||
755 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | 788 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; |
756 | 789 | ||
757 | if (tuner_debug > 1) { | 790 | if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL) |
758 | v4l_i2c_print_ioctl(client,cmd); | 791 | return 0; |
759 | printk("\n"); | 792 | t->mode = T_STANDBY; |
760 | } | 793 | if (analog_ops->standby) |
794 | analog_ops->standby(&t->fe); | ||
795 | return 0; | ||
796 | } | ||
761 | 797 | ||
762 | switch (cmd) { | ||
763 | /* --- configuration --- */ | ||
764 | case TUNER_SET_TYPE_ADDR: | ||
765 | tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", | ||
766 | ((struct tuner_setup *)arg)->type, | ||
767 | ((struct tuner_setup *)arg)->addr, | ||
768 | ((struct tuner_setup *)arg)->mode_mask, | ||
769 | ((struct tuner_setup *)arg)->config); | ||
770 | |||
771 | set_addr(client, (struct tuner_setup *)arg); | ||
772 | break; | ||
773 | case AUDC_SET_RADIO: | ||
774 | if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO") | ||
775 | == -EINVAL) | ||
776 | return 0; | ||
777 | if (t->radio_freq) | ||
778 | set_freq(client, t->radio_freq); | ||
779 | break; | ||
780 | case TUNER_SET_STANDBY: | ||
781 | if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL) | ||
782 | return 0; | ||
783 | t->mode = T_STANDBY; | ||
784 | if (analog_ops->standby) | ||
785 | analog_ops->standby(&t->fe); | ||
786 | break; | ||
787 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 | 798 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 |
799 | static int tuner_ioctl(struct v4l2_subdev *sd, int cmd, void *arg) | ||
800 | { | ||
801 | struct tuner *t = to_tuner(sd); | ||
802 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
803 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | ||
804 | struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; | ||
805 | |||
806 | switch (cmd) { | ||
788 | case VIDIOCSAUDIO: | 807 | case VIDIOCSAUDIO: |
789 | if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL) | 808 | if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL) |
790 | return 0; | 809 | return 0; |
@@ -897,149 +916,172 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
897 | } | 916 | } |
898 | return 0; | 917 | return 0; |
899 | } | 918 | } |
919 | } | ||
920 | return -ENOIOCTLCMD; | ||
921 | } | ||
900 | #endif | 922 | #endif |
901 | case TUNER_SET_CONFIG: | ||
902 | { | ||
903 | struct v4l2_priv_tun_config *cfg = arg; | ||
904 | 923 | ||
905 | if (t->type != cfg->tuner) | 924 | static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg) |
906 | break; | 925 | { |
926 | struct tuner *t = to_tuner(sd); | ||
927 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | ||
907 | 928 | ||
908 | if (analog_ops->set_config) { | 929 | if (t->type != cfg->tuner) |
909 | analog_ops->set_config(&t->fe, cfg->priv); | 930 | return 0; |
910 | break; | ||
911 | } | ||
912 | 931 | ||
913 | tuner_dbg("Tuner frontend module has no way to set config\n"); | 932 | if (analog_ops->set_config) { |
914 | break; | 933 | analog_ops->set_config(&t->fe, cfg->priv); |
934 | return 0; | ||
915 | } | 935 | } |
916 | /* --- v4l ioctls --- */ | ||
917 | /* take care: bttv does userspace copying, we'll get a | ||
918 | kernel pointer here... */ | ||
919 | case VIDIOC_S_STD: | ||
920 | { | ||
921 | v4l2_std_id *id = arg; | ||
922 | 936 | ||
923 | if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD") | 937 | tuner_dbg("Tuner frontend module has no way to set config\n"); |
924 | == -EINVAL) | 938 | return 0; |
925 | return 0; | 939 | } |
926 | 940 | ||
927 | switch_v4l2(); | 941 | /* --- v4l ioctls --- */ |
942 | /* take care: bttv does userspace copying, we'll get a | ||
943 | kernel pointer here... */ | ||
944 | static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | ||
945 | { | ||
946 | struct tuner *t = to_tuner(sd); | ||
947 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
928 | 948 | ||
929 | t->std = *id; | 949 | if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD") |
930 | tuner_fixup_std(t); | 950 | == -EINVAL) |
931 | if (t->tv_freq) | 951 | return 0; |
932 | set_freq(client, t->tv_freq); | ||
933 | break; | ||
934 | } | ||
935 | case VIDIOC_S_FREQUENCY: | ||
936 | { | ||
937 | struct v4l2_frequency *f = arg; | ||
938 | 952 | ||
939 | if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") | 953 | switch_v4l2(); |
940 | == -EINVAL) | ||
941 | return 0; | ||
942 | switch_v4l2(); | ||
943 | set_freq(client,f->frequency); | ||
944 | 954 | ||
945 | break; | 955 | t->std = std; |
946 | } | 956 | tuner_fixup_std(t); |
947 | case VIDIOC_G_FREQUENCY: | 957 | if (t->tv_freq) |
948 | { | 958 | set_freq(client, t->tv_freq); |
949 | struct v4l2_frequency *f = arg; | 959 | return 0; |
960 | } | ||
950 | 961 | ||
951 | if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL) | 962 | static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) |
952 | return 0; | 963 | { |
953 | switch_v4l2(); | 964 | struct tuner *t = to_tuner(sd); |
954 | f->type = t->mode; | 965 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
955 | if (fe_tuner_ops->get_frequency) { | ||
956 | u32 abs_freq; | ||
957 | |||
958 | fe_tuner_ops->get_frequency(&t->fe, &abs_freq); | ||
959 | f->frequency = (V4L2_TUNER_RADIO == t->mode) ? | ||
960 | (abs_freq * 2 + 125/2) / 125 : | ||
961 | (abs_freq + 62500/2) / 62500; | ||
962 | break; | ||
963 | } | ||
964 | f->frequency = (V4L2_TUNER_RADIO == t->mode) ? | ||
965 | t->radio_freq : t->tv_freq; | ||
966 | break; | ||
967 | } | ||
968 | case VIDIOC_G_TUNER: | ||
969 | { | ||
970 | struct v4l2_tuner *tuner = arg; | ||
971 | 966 | ||
972 | if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL) | 967 | if (set_mode(client, t, f->type, "VIDIOC_S_FREQUENCY") |
973 | return 0; | 968 | == -EINVAL) |
974 | switch_v4l2(); | 969 | return 0; |
975 | 970 | switch_v4l2(); | |
976 | tuner->type = t->mode; | 971 | set_freq(client, f->frequency); |
977 | if (analog_ops->get_afc) | ||
978 | tuner->afc = analog_ops->get_afc(&t->fe); | ||
979 | if (t->mode == V4L2_TUNER_ANALOG_TV) | ||
980 | tuner->capability |= V4L2_TUNER_CAP_NORM; | ||
981 | if (t->mode != V4L2_TUNER_RADIO) { | ||
982 | tuner->rangelow = tv_range[0] * 16; | ||
983 | tuner->rangehigh = tv_range[1] * 16; | ||
984 | break; | ||
985 | } | ||
986 | 972 | ||
987 | /* radio mode */ | 973 | return 0; |
988 | tuner->rxsubchans = | 974 | } |
989 | V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
990 | if (fe_tuner_ops->get_status) { | ||
991 | u32 tuner_status; | ||
992 | |||
993 | fe_tuner_ops->get_status(&t->fe, &tuner_status); | ||
994 | tuner->rxsubchans = | ||
995 | (tuner_status & TUNER_STATUS_STEREO) ? | ||
996 | V4L2_TUNER_SUB_STEREO : | ||
997 | V4L2_TUNER_SUB_MONO; | ||
998 | } else { | ||
999 | if (analog_ops->is_stereo) { | ||
1000 | tuner->rxsubchans = | ||
1001 | analog_ops->is_stereo(&t->fe) ? | ||
1002 | V4L2_TUNER_SUB_STEREO : | ||
1003 | V4L2_TUNER_SUB_MONO; | ||
1004 | } | ||
1005 | } | ||
1006 | if (analog_ops->has_signal) | ||
1007 | tuner->signal = analog_ops->has_signal(&t->fe); | ||
1008 | tuner->capability |= | ||
1009 | V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
1010 | tuner->audmode = t->audmode; | ||
1011 | tuner->rangelow = radio_range[0] * 16000; | ||
1012 | tuner->rangehigh = radio_range[1] * 16000; | ||
1013 | break; | ||
1014 | } | ||
1015 | case VIDIOC_S_TUNER: | ||
1016 | { | ||
1017 | struct v4l2_tuner *tuner = arg; | ||
1018 | 975 | ||
1019 | if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL) | 976 | static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) |
1020 | return 0; | 977 | { |
978 | struct tuner *t = to_tuner(sd); | ||
979 | struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; | ||
1021 | 980 | ||
1022 | switch_v4l2(); | 981 | if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL) |
982 | return 0; | ||
983 | switch_v4l2(); | ||
984 | f->type = t->mode; | ||
985 | if (fe_tuner_ops->get_frequency) { | ||
986 | u32 abs_freq; | ||
987 | |||
988 | fe_tuner_ops->get_frequency(&t->fe, &abs_freq); | ||
989 | f->frequency = (V4L2_TUNER_RADIO == t->mode) ? | ||
990 | (abs_freq * 2 + 125/2) / 125 : | ||
991 | (abs_freq + 62500/2) / 62500; | ||
992 | return 0; | ||
993 | } | ||
994 | f->frequency = (V4L2_TUNER_RADIO == t->mode) ? | ||
995 | t->radio_freq : t->tv_freq; | ||
996 | return 0; | ||
997 | } | ||
1023 | 998 | ||
1024 | /* do nothing unless we're a radio tuner */ | 999 | static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
1025 | if (t->mode != V4L2_TUNER_RADIO) | 1000 | { |
1026 | break; | 1001 | struct tuner *t = to_tuner(sd); |
1027 | t->audmode = tuner->audmode; | 1002 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; |
1028 | set_radio_freq(client, t->radio_freq); | 1003 | struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; |
1029 | break; | 1004 | |
1005 | if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL) | ||
1006 | return 0; | ||
1007 | switch_v4l2(); | ||
1008 | |||
1009 | vt->type = t->mode; | ||
1010 | if (analog_ops->get_afc) | ||
1011 | vt->afc = analog_ops->get_afc(&t->fe); | ||
1012 | if (t->mode == V4L2_TUNER_ANALOG_TV) | ||
1013 | vt->capability |= V4L2_TUNER_CAP_NORM; | ||
1014 | if (t->mode != V4L2_TUNER_RADIO) { | ||
1015 | vt->rangelow = tv_range[0] * 16; | ||
1016 | vt->rangehigh = tv_range[1] * 16; | ||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | /* radio mode */ | ||
1021 | vt->rxsubchans = | ||
1022 | V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
1023 | if (fe_tuner_ops->get_status) { | ||
1024 | u32 tuner_status; | ||
1025 | |||
1026 | fe_tuner_ops->get_status(&t->fe, &tuner_status); | ||
1027 | vt->rxsubchans = | ||
1028 | (tuner_status & TUNER_STATUS_STEREO) ? | ||
1029 | V4L2_TUNER_SUB_STEREO : | ||
1030 | V4L2_TUNER_SUB_MONO; | ||
1031 | } else { | ||
1032 | if (analog_ops->is_stereo) { | ||
1033 | vt->rxsubchans = | ||
1034 | analog_ops->is_stereo(&t->fe) ? | ||
1035 | V4L2_TUNER_SUB_STEREO : | ||
1036 | V4L2_TUNER_SUB_MONO; | ||
1030 | } | 1037 | } |
1031 | case VIDIOC_LOG_STATUS: | ||
1032 | if (analog_ops->tuner_status) | ||
1033 | analog_ops->tuner_status(&t->fe); | ||
1034 | break; | ||
1035 | } | 1038 | } |
1039 | if (analog_ops->has_signal) | ||
1040 | vt->signal = analog_ops->has_signal(&t->fe); | ||
1041 | vt->capability |= | ||
1042 | V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
1043 | vt->audmode = t->audmode; | ||
1044 | vt->rangelow = radio_range[0] * 16000; | ||
1045 | vt->rangehigh = radio_range[1] * 16000; | ||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | ||
1050 | { | ||
1051 | struct tuner *t = to_tuner(sd); | ||
1052 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1053 | |||
1054 | if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL) | ||
1055 | return 0; | ||
1056 | |||
1057 | switch_v4l2(); | ||
1058 | |||
1059 | /* do nothing unless we're a radio tuner */ | ||
1060 | if (t->mode != V4L2_TUNER_RADIO) | ||
1061 | return 0; | ||
1062 | t->audmode = vt->audmode; | ||
1063 | set_radio_freq(client, t->radio_freq); | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static int tuner_log_status(struct v4l2_subdev *sd) | ||
1068 | { | ||
1069 | struct tuner *t = to_tuner(sd); | ||
1070 | struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; | ||
1036 | 1071 | ||
1072 | if (analog_ops->tuner_status) | ||
1073 | analog_ops->tuner_status(&t->fe); | ||
1037 | return 0; | 1074 | return 0; |
1038 | } | 1075 | } |
1039 | 1076 | ||
1077 | static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg) | ||
1078 | { | ||
1079 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
1080 | } | ||
1081 | |||
1040 | static int tuner_suspend(struct i2c_client *c, pm_message_t state) | 1082 | static int tuner_suspend(struct i2c_client *c, pm_message_t state) |
1041 | { | 1083 | { |
1042 | struct tuner *t = i2c_get_clientdata(c); | 1084 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
1043 | 1085 | ||
1044 | tuner_dbg("suspend\n"); | 1086 | tuner_dbg("suspend\n"); |
1045 | /* FIXME: power down ??? */ | 1087 | /* FIXME: power down ??? */ |
@@ -1048,7 +1090,7 @@ static int tuner_suspend(struct i2c_client *c, pm_message_t state) | |||
1048 | 1090 | ||
1049 | static int tuner_resume(struct i2c_client *c) | 1091 | static int tuner_resume(struct i2c_client *c) |
1050 | { | 1092 | { |
1051 | struct tuner *t = i2c_get_clientdata(c); | 1093 | struct tuner *t = to_tuner(i2c_get_clientdata(c)); |
1052 | 1094 | ||
1053 | tuner_dbg("resume\n"); | 1095 | tuner_dbg("resume\n"); |
1054 | if (V4L2_TUNER_RADIO == t->mode) { | 1096 | if (V4L2_TUNER_RADIO == t->mode) { |
@@ -1061,6 +1103,30 @@ static int tuner_resume(struct i2c_client *c) | |||
1061 | return 0; | 1103 | return 0; |
1062 | } | 1104 | } |
1063 | 1105 | ||
1106 | /* ----------------------------------------------------------------------- */ | ||
1107 | |||
1108 | static const struct v4l2_subdev_core_ops tuner_core_ops = { | ||
1109 | .log_status = tuner_log_status, | ||
1110 | .s_standby = tuner_s_standby, | ||
1111 | .ioctl = tuner_ioctl, | ||
1112 | }; | ||
1113 | |||
1114 | static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = { | ||
1115 | .s_std = tuner_s_std, | ||
1116 | .s_radio = tuner_s_radio, | ||
1117 | .g_tuner = tuner_g_tuner, | ||
1118 | .s_tuner = tuner_s_tuner, | ||
1119 | .s_frequency = tuner_s_frequency, | ||
1120 | .g_frequency = tuner_g_frequency, | ||
1121 | .s_type_addr = tuner_s_type_addr, | ||
1122 | .s_config = tuner_s_config, | ||
1123 | }; | ||
1124 | |||
1125 | static const struct v4l2_subdev_ops tuner_ops = { | ||
1126 | .core = &tuner_core_ops, | ||
1127 | .tuner = &tuner_tuner_ops, | ||
1128 | }; | ||
1129 | |||
1064 | /* ---------------------------------------------------------------------- */ | 1130 | /* ---------------------------------------------------------------------- */ |
1065 | 1131 | ||
1066 | static LIST_HEAD(tuner_list); | 1132 | static LIST_HEAD(tuner_list); |
@@ -1109,9 +1175,9 @@ static int tuner_probe(struct i2c_client *client, | |||
1109 | t = kzalloc(sizeof(struct tuner), GFP_KERNEL); | 1175 | t = kzalloc(sizeof(struct tuner), GFP_KERNEL); |
1110 | if (NULL == t) | 1176 | if (NULL == t) |
1111 | return -ENOMEM; | 1177 | return -ENOMEM; |
1178 | v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops); | ||
1112 | t->i2c = client; | 1179 | t->i2c = client; |
1113 | t->name = "(tuner unset)"; | 1180 | t->name = "(tuner unset)"; |
1114 | i2c_set_clientdata(client, t); | ||
1115 | t->type = UNSET; | 1181 | t->type = UNSET; |
1116 | t->audmode = V4L2_TUNER_MODE_STEREO; | 1182 | t->audmode = V4L2_TUNER_MODE_STEREO; |
1117 | t->mode_mask = T_UNINITIALIZED; | 1183 | t->mode_mask = T_UNINITIALIZED; |
@@ -1261,8 +1327,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) | |||
1261 | 1327 | ||
1262 | static int tuner_remove(struct i2c_client *client) | 1328 | static int tuner_remove(struct i2c_client *client) |
1263 | { | 1329 | { |
1264 | struct tuner *t = i2c_get_clientdata(client); | 1330 | struct tuner *t = to_tuner(i2c_get_clientdata(client)); |
1265 | 1331 | ||
1332 | v4l2_device_unregister_subdev(&t->sd); | ||
1266 | tuner_detach(&t->fe); | 1333 | tuner_detach(&t->fe); |
1267 | t->fe.analog_demod_priv = NULL; | 1334 | t->fe.analog_demod_priv = NULL; |
1268 | 1335 | ||