diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-01-30 03:55:50 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-05 15:15:33 -0500 |
commit | f5e7cc4af36c631edf7dc73111d80af975f526a6 (patch) | |
tree | fe5c049cb5865dfd4f68970253056edb159708c9 /drivers/media/radio/radio-miropcm20.c | |
parent | f7c096f73561ba9754d4b13a6dc38e964194d784 (diff) |
[media] radio-miropcm20: Fix audmode/tuner/frequency handling
- instead of a mute module option, use audmode as per the spec.
- clamp the frequency before setting it.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio/radio-miropcm20.c')
-rw-r--r-- | drivers/media/radio/radio-miropcm20.c | 52 |
1 files changed, 24 insertions, 28 deletions
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 4ac813c5af17..eb6cd86337a8 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c | |||
@@ -26,44 +26,27 @@ static int radio_nr = -1; | |||
26 | module_param(radio_nr, int, 0); | 26 | module_param(radio_nr, int, 0); |
27 | MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); | 27 | MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); |
28 | 28 | ||
29 | static bool mono; | ||
30 | module_param(mono, bool, 0); | ||
31 | MODULE_PARM_DESC(mono, "Force tuner into mono mode."); | ||
32 | |||
33 | struct pcm20 { | 29 | struct pcm20 { |
34 | struct v4l2_device v4l2_dev; | 30 | struct v4l2_device v4l2_dev; |
35 | struct video_device vdev; | 31 | struct video_device vdev; |
36 | struct v4l2_ctrl_handler ctrl_handler; | 32 | struct v4l2_ctrl_handler ctrl_handler; |
37 | unsigned long freq; | 33 | unsigned long freq; |
38 | int muted; | 34 | u32 audmode; |
39 | struct snd_miro_aci *aci; | 35 | struct snd_miro_aci *aci; |
40 | struct mutex lock; | 36 | struct mutex lock; |
41 | }; | 37 | }; |
42 | 38 | ||
43 | static struct pcm20 pcm20_card = { | 39 | static struct pcm20 pcm20_card = { |
44 | .freq = 87*16000, | 40 | .freq = 87 * 16000, |
45 | .muted = 1, | 41 | .audmode = V4L2_TUNER_MODE_STEREO, |
46 | }; | 42 | }; |
47 | 43 | ||
48 | static int pcm20_mute(struct pcm20 *dev, unsigned char mute) | ||
49 | { | ||
50 | dev->muted = mute; | ||
51 | return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1); | ||
52 | } | ||
53 | |||
54 | static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo) | ||
55 | { | ||
56 | return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1); | ||
57 | } | ||
58 | |||
59 | static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) | 44 | static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) |
60 | { | 45 | { |
61 | unsigned char freql; | 46 | unsigned char freql; |
62 | unsigned char freqh; | 47 | unsigned char freqh; |
63 | struct snd_miro_aci *aci = dev->aci; | 48 | struct snd_miro_aci *aci = dev->aci; |
64 | 49 | ||
65 | dev->freq = freq; | ||
66 | |||
67 | freq /= 160; | 50 | freq /= 160; |
68 | if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0)) | 51 | if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0)) |
69 | freq /= 10; /* I don't know exactly which version | 52 | freq /= 10; /* I don't know exactly which version |
@@ -71,7 +54,6 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) | |||
71 | freql = freq & 0xff; | 54 | freql = freq & 0xff; |
72 | freqh = freq >> 8; | 55 | freqh = freq >> 8; |
73 | 56 | ||
74 | pcm20_stereo(dev, !mono); | ||
75 | return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh); | 57 | return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh); |
76 | } | 58 | } |
77 | 59 | ||
@@ -99,7 +81,9 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
99 | static int vidioc_g_tuner(struct file *file, void *priv, | 81 | static int vidioc_g_tuner(struct file *file, void *priv, |
100 | struct v4l2_tuner *v) | 82 | struct v4l2_tuner *v) |
101 | { | 83 | { |
102 | if (v->index) /* Only 1 tuner */ | 84 | struct pcm20 *dev = video_drvdata(file); |
85 | |||
86 | if (v->index) | ||
103 | return -EINVAL; | 87 | return -EINVAL; |
104 | strlcpy(v->name, "FM", sizeof(v->name)); | 88 | strlcpy(v->name, "FM", sizeof(v->name)); |
105 | v->type = V4L2_TUNER_RADIO; | 89 | v->type = V4L2_TUNER_RADIO; |
@@ -107,15 +91,23 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
107 | v->rangehigh = 108*16000; | 91 | v->rangehigh = 108*16000; |
108 | v->signal = 0xffff; | 92 | v->signal = 0xffff; |
109 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | 93 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; |
110 | v->capability = V4L2_TUNER_CAP_LOW; | 94 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; |
111 | v->audmode = V4L2_TUNER_MODE_MONO; | 95 | v->audmode = dev->audmode; |
112 | return 0; | 96 | return 0; |
113 | } | 97 | } |
114 | 98 | ||
115 | static int vidioc_s_tuner(struct file *file, void *priv, | 99 | static int vidioc_s_tuner(struct file *file, void *priv, |
116 | struct v4l2_tuner *v) | 100 | struct v4l2_tuner *v) |
117 | { | 101 | { |
118 | return v->index ? -EINVAL : 0; | 102 | struct pcm20 *dev = video_drvdata(file); |
103 | |||
104 | if (v->index) | ||
105 | return -EINVAL; | ||
106 | if (v->audmode > V4L2_TUNER_MODE_STEREO) | ||
107 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
108 | snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, | ||
109 | v->audmode == V4L2_TUNER_MODE_MONO, -1); | ||
110 | return 0; | ||
119 | } | 111 | } |
120 | 112 | ||
121 | static int vidioc_g_frequency(struct file *file, void *priv, | 113 | static int vidioc_g_frequency(struct file *file, void *priv, |
@@ -140,8 +132,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
140 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | 132 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) |
141 | return -EINVAL; | 133 | return -EINVAL; |
142 | 134 | ||
143 | dev->freq = f->frequency; | 135 | dev->freq = clamp(f->frequency, 87 * 16000U, 108 * 16000U); |
144 | pcm20_setfreq(dev, f->frequency); | 136 | pcm20_setfreq(dev, dev->freq); |
145 | return 0; | 137 | return 0; |
146 | } | 138 | } |
147 | 139 | ||
@@ -151,7 +143,7 @@ static int pcm20_s_ctrl(struct v4l2_ctrl *ctrl) | |||
151 | 143 | ||
152 | switch (ctrl->id) { | 144 | switch (ctrl->id) { |
153 | case V4L2_CID_AUDIO_MUTE: | 145 | case V4L2_CID_AUDIO_MUTE: |
154 | pcm20_mute(dev, ctrl->val); | 146 | snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, ctrl->val, -1); |
155 | return 0; | 147 | return 0; |
156 | } | 148 | } |
157 | return -EINVAL; | 149 | return -EINVAL; |
@@ -212,6 +204,9 @@ static int __init pcm20_init(void) | |||
212 | dev->vdev.lock = &dev->lock; | 204 | dev->vdev.lock = &dev->lock; |
213 | set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); | 205 | set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); |
214 | video_set_drvdata(&dev->vdev, dev); | 206 | video_set_drvdata(&dev->vdev, dev); |
207 | snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, | ||
208 | dev->audmode == V4L2_TUNER_MODE_MONO, -1); | ||
209 | pcm20_setfreq(dev, dev->freq); | ||
215 | 210 | ||
216 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) | 211 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) |
217 | goto err_hdl; | 212 | goto err_hdl; |
@@ -233,6 +228,7 @@ static void __exit pcm20_cleanup(void) | |||
233 | struct pcm20 *dev = &pcm20_card; | 228 | struct pcm20 *dev = &pcm20_card; |
234 | 229 | ||
235 | video_unregister_device(&dev->vdev); | 230 | video_unregister_device(&dev->vdev); |
231 | snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, 1, -1); | ||
236 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | 232 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
237 | v4l2_device_unregister(&dev->v4l2_dev); | 233 | v4l2_device_unregister(&dev->v4l2_dev); |
238 | } | 234 | } |