diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/radio/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/radio/radio-maestro.c | 197 |
2 files changed, 131 insertions, 68 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 9c0839e57f41..a74c91577d3c 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig | |||
@@ -160,7 +160,7 @@ config RADIO_MAXIRADIO | |||
160 | 160 | ||
161 | config RADIO_MAESTRO | 161 | config RADIO_MAESTRO |
162 | tristate "Maestro on board radio" | 162 | tristate "Maestro on board radio" |
163 | depends on VIDEO_V4L1 | 163 | depends on VIDEO_V4L2 && PCI |
164 | ---help--- | 164 | ---help--- |
165 | Say Y here to directly support the on-board radio tuner on the | 165 | Say Y here to directly support the on-board radio tuner on the |
166 | Maestro 2 or 2E sound card. | 166 | Maestro 2 or 2E sound card. |
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index fcfa6c9fe225..e8ce5f75cf12 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c | |||
@@ -14,6 +14,8 @@ | |||
14 | * version 0.04 | 14 | * version 0.04 |
15 | * + code improvements | 15 | * + code improvements |
16 | * + VIDEO_TUNER_LOW is permanent | 16 | * + VIDEO_TUNER_LOW is permanent |
17 | * | ||
18 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | ||
17 | */ | 19 | */ |
18 | 20 | ||
19 | #include <linux/module.h> | 21 | #include <linux/module.h> |
@@ -25,10 +27,23 @@ | |||
25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
26 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
27 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
28 | #include <linux/videodev.h> | 30 | #include <linux/videodev2.h> |
29 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
30 | 32 | ||
31 | #define DRIVER_VERSION "0.05" | 33 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ |
34 | #define RADIO_VERSION KERNEL_VERSION(0,0,6) | ||
35 | #define DRIVER_VERSION "0.06" | ||
36 | |||
37 | static struct v4l2_queryctrl radio_qctrl[] = { | ||
38 | { | ||
39 | .id = V4L2_CID_AUDIO_MUTE, | ||
40 | .name = "Mute", | ||
41 | .minimum = 0, | ||
42 | .maximum = 1, | ||
43 | .default_value = 1, | ||
44 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
45 | } | ||
46 | }; | ||
32 | 47 | ||
33 | #define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */ | 48 | #define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */ |
34 | 49 | ||
@@ -96,7 +111,7 @@ static struct file_operations maestro_fops = { | |||
96 | static struct video_device maestro_radio = { | 111 | static struct video_device maestro_radio = { |
97 | .name = "Maestro radio", | 112 | .name = "Maestro radio", |
98 | .type = VID_TYPE_TUNER, | 113 | .type = VID_TYPE_TUNER, |
99 | .hardware = VID_HARDWARE_SF16MI, | 114 | .hardware = 0, |
100 | .fops = &maestro_fops, | 115 | .fops = &maestro_fops, |
101 | }; | 116 | }; |
102 | 117 | ||
@@ -130,7 +145,7 @@ static u32 radio_bits_get(struct radio_device *dev) | |||
130 | rdata = inw(io); | 145 | rdata = inw(io); |
131 | if(!l) | 146 | if(!l) |
132 | dev->stereo = rdata & STR_MOST ? | 147 | dev->stereo = rdata & STR_MOST ? |
133 | 0 : VIDEO_TUNER_STEREO_ON; | 148 | 0 : 1; |
134 | else | 149 | else |
135 | if(rdata & STR_DATA) | 150 | if(rdata & STR_DATA) |
136 | data++; | 151 | data++; |
@@ -183,72 +198,120 @@ static inline int radio_function(struct inode *inode, struct file *file, | |||
183 | struct radio_device *card = video_get_drvdata(dev); | 198 | struct radio_device *card = video_get_drvdata(dev); |
184 | 199 | ||
185 | switch (cmd) { | 200 | switch (cmd) { |
186 | case VIDIOCGCAP: { | 201 | case VIDIOC_QUERYCAP: |
187 | struct video_capability *v = arg; | 202 | { |
188 | memset(v, 0, sizeof(*v)); | 203 | struct v4l2_capability *v = arg; |
189 | strcpy(v->name, "Maestro radio"); | 204 | memset(v,0,sizeof(*v)); |
190 | v->type = VID_TYPE_TUNER; | 205 | strlcpy(v->driver, "radio-maestro", sizeof (v->driver)); |
191 | v->channels = v->audios = 1; | 206 | strlcpy(v->card, "Maestro Radio", sizeof (v->card)); |
192 | return 0; | 207 | sprintf(v->bus_info,"PCI"); |
193 | } case VIDIOCGTUNER: { | 208 | v->version = RADIO_VERSION; |
194 | struct video_tuner *v = arg; | 209 | v->capabilities = V4L2_CAP_TUNER; |
195 | if (v->tuner) | 210 | |
196 | return -EINVAL; | 211 | return 0; |
197 | (void)radio_bits_get(card); | 212 | } |
198 | v->flags = VIDEO_TUNER_LOW | card->stereo; | 213 | case VIDIOC_G_TUNER: |
199 | v->signal = card->tuned; | 214 | { |
200 | strcpy(v->name, "FM"); | 215 | struct v4l2_tuner *v = arg; |
201 | v->rangelow = FREQ_LO; | 216 | |
202 | v->rangehigh = FREQ_HI; | 217 | if (v->index > 0) |
203 | v->mode = VIDEO_MODE_AUTO; | 218 | return -EINVAL; |
204 | return 0; | 219 | |
205 | } case VIDIOCSTUNER: { | 220 | (void)radio_bits_get(card); |
206 | struct video_tuner *v = arg; | 221 | |
207 | if (v->tuner != 0) | 222 | memset(v,0,sizeof(*v)); |
208 | return -EINVAL; | 223 | strcpy(v->name, "FM"); |
209 | return 0; | 224 | v->type = V4L2_TUNER_RADIO; |
210 | } case VIDIOCGFREQ: { | 225 | |
211 | unsigned long *freq = arg; | 226 | v->rangelow = FREQ_LO; |
212 | *freq = BITS2FREQ(radio_bits_get(card)); | 227 | v->rangehigh = FREQ_HI; |
213 | return 0; | 228 | v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; |
214 | } case VIDIOCSFREQ: { | 229 | v->capability=V4L2_TUNER_CAP_LOW; |
215 | unsigned long *freq = arg; | 230 | if(card->stereo) |
216 | if (*freq < FREQ_LO || *freq > FREQ_HI) | 231 | v->audmode = V4L2_TUNER_MODE_STEREO; |
232 | else | ||
233 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
234 | v->signal=card->tuned; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | case VIDIOC_S_TUNER: | ||
239 | { | ||
240 | struct v4l2_tuner *v = arg; | ||
241 | |||
242 | if (v->index > 0) | ||
243 | return -EINVAL; | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | case VIDIOC_S_FREQUENCY: | ||
248 | { | ||
249 | struct v4l2_frequency *f = arg; | ||
250 | |||
251 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) | ||
252 | return -EINVAL; | ||
253 | radio_bits_set(card, FREQ2BITS(f->frequency)); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | case VIDIOC_G_FREQUENCY: | ||
258 | { | ||
259 | struct v4l2_frequency *f = arg; | ||
260 | |||
261 | f->type = V4L2_TUNER_RADIO; | ||
262 | f->frequency = BITS2FREQ(radio_bits_get(card)); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | case VIDIOC_QUERYCTRL: | ||
267 | { | ||
268 | struct v4l2_queryctrl *qc = arg; | ||
269 | int i; | ||
270 | |||
271 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
272 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
273 | memcpy(qc, &(radio_qctrl[i]), | ||
274 | sizeof(*qc)); | ||
275 | return (0); | ||
276 | } | ||
277 | } | ||
217 | return -EINVAL; | 278 | return -EINVAL; |
218 | radio_bits_set(card, FREQ2BITS(*freq)); | 279 | } |
219 | return 0; | 280 | case VIDIOC_G_CTRL: |
220 | } case VIDIOCGAUDIO: { | 281 | { |
221 | struct video_audio *v = arg; | 282 | struct v4l2_control *ctrl= arg; |
222 | memset(v, 0, sizeof(*v)); | 283 | |
223 | strcpy(v->name, "Radio"); | 284 | switch (ctrl->id) { |
224 | v->flags = VIDEO_AUDIO_MUTABLE | card->muted; | 285 | case V4L2_CID_AUDIO_MUTE: |
225 | v->mode = VIDEO_SOUND_STEREO; | 286 | ctrl->value=card->muted; |
226 | return 0; | 287 | return (0); |
227 | } case VIDIOCSAUDIO: { | 288 | } |
228 | struct video_audio *v = arg; | ||
229 | if (v->audio) | ||
230 | return -EINVAL; | 289 | return -EINVAL; |
290 | } | ||
291 | case VIDIOC_S_CTRL: | ||
231 | { | 292 | { |
232 | register u16 io = card->io; | 293 | struct v4l2_control *ctrl= arg; |
233 | register u16 omask = inw(io + IO_MASK); | 294 | |
234 | outw(~STR_WREN, io + IO_MASK); | 295 | switch (ctrl->id) { |
235 | outw((card->muted = v->flags & VIDEO_AUDIO_MUTE) ? | 296 | case V4L2_CID_AUDIO_MUTE: |
236 | STR_WREN : 0, io); | 297 | { |
237 | udelay(4); | 298 | register u16 io = card->io; |
238 | outw(omask, io + IO_MASK); | 299 | register u16 omask = inw(io + IO_MASK); |
239 | msleep(125); | 300 | outw(~STR_WREN, io + IO_MASK); |
240 | return 0; | 301 | outw((card->muted = ctrl->value ) ? |
302 | STR_WREN : 0, io); | ||
303 | udelay(4); | ||
304 | outw(omask, io + IO_MASK); | ||
305 | msleep(125); | ||
306 | |||
307 | return (0); | ||
308 | } | ||
309 | } | ||
310 | return -EINVAL; | ||
241 | } | 311 | } |
242 | } case VIDIOCGUNIT: { | 312 | default: |
243 | struct video_unit *v = arg; | 313 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, |
244 | v->video = VIDEO_NO_UNIT; | 314 | radio_function); |
245 | v->vbi = VIDEO_NO_UNIT; | ||
246 | v->radio = dev->minor; | ||
247 | v->audio = 0; | ||
248 | v->teletext = VIDEO_NO_UNIT; | ||
249 | return 0; | ||
250 | } default: | ||
251 | return -ENOIOCTLCMD; | ||
252 | } | 315 | } |
253 | } | 316 | } |
254 | 317 | ||
@@ -275,7 +338,7 @@ static u16 __devinit radio_power_on(struct radio_device *dev) | |||
275 | omask = inw(io + IO_MASK); | 338 | omask = inw(io + IO_MASK); |
276 | odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); | 339 | odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); |
277 | outw(odir & ~STR_WREN, io + IO_DIR); | 340 | outw(odir & ~STR_WREN, io + IO_DIR); |
278 | dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE; | 341 | dev->muted = inw(io) & STR_WREN ? 0 : 1; |
279 | outw(odir, io + IO_DIR); | 342 | outw(odir, io + IO_DIR); |
280 | outw(~(STR_WREN | STR_CLK), io + IO_MASK); | 343 | outw(~(STR_WREN | STR_CLK), io + IO_MASK); |
281 | outw(dev->muted ? 0 : STR_WREN, io); | 344 | outw(dev->muted ? 0 : STR_WREN, io); |