diff options
-rw-r--r-- | drivers/media/radio/radio-maestro.c | 266 |
1 files changed, 143 insertions, 123 deletions
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index e67b7f258029..11f80cacd6ed 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c | |||
@@ -75,8 +75,6 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
75 | static int radio_nr = -1; | 75 | static int radio_nr = -1; |
76 | module_param(radio_nr, int, 0); | 76 | module_param(radio_nr, int, 0); |
77 | 77 | ||
78 | static int radio_ioctl(struct inode *inode, struct file *file, | ||
79 | unsigned int cmd, unsigned long arg); | ||
80 | static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | 78 | static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); |
81 | static void maestro_remove(struct pci_dev *pdev); | 79 | static void maestro_remove(struct pci_dev *pdev); |
82 | 80 | ||
@@ -102,18 +100,11 @@ static const struct file_operations maestro_fops = { | |||
102 | .owner = THIS_MODULE, | 100 | .owner = THIS_MODULE, |
103 | .open = video_exclusive_open, | 101 | .open = video_exclusive_open, |
104 | .release = video_exclusive_release, | 102 | .release = video_exclusive_release, |
105 | .ioctl = radio_ioctl, | 103 | .ioctl = video_ioctl2, |
106 | .compat_ioctl = v4l_compat_ioctl32, | 104 | .compat_ioctl = v4l_compat_ioctl32, |
107 | .llseek = no_llseek, | 105 | .llseek = no_llseek, |
108 | }; | 106 | }; |
109 | 107 | ||
110 | static struct video_device maestro_radio = { | ||
111 | .name = "Maestro radio", | ||
112 | .type = VID_TYPE_TUNER, | ||
113 | .hardware = 0, | ||
114 | .fops = &maestro_fops, | ||
115 | }; | ||
116 | |||
117 | struct radio_device { | 108 | struct radio_device { |
118 | u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ | 109 | u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ |
119 | muted, /* VIDEO_AUDIO_MUTE */ | 110 | muted, /* VIDEO_AUDIO_MUTE */ |
@@ -190,142 +181,153 @@ static void radio_bits_set(struct radio_device *dev, u32 data) | |||
190 | msleep(125); | 181 | msleep(125); |
191 | } | 182 | } |
192 | 183 | ||
193 | static inline int radio_function(struct inode *inode, struct file *file, | 184 | static int vidioc_querycap(struct file *file, void *priv, |
194 | unsigned int cmd, void *arg) | 185 | struct v4l2_capability *v) |
186 | { | ||
187 | strlcpy(v->driver, "radio-maestro", sizeof(v->driver)); | ||
188 | strlcpy(v->card, "Maestro Radio", sizeof(v->card)); | ||
189 | sprintf(v->bus_info, "PCI"); | ||
190 | v->version = RADIO_VERSION; | ||
191 | v->capabilities = V4L2_CAP_TUNER; | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
196 | struct v4l2_tuner *v) | ||
195 | { | 197 | { |
196 | struct video_device *dev = video_devdata(file); | 198 | struct video_device *dev = video_devdata(file); |
197 | struct radio_device *card = video_get_drvdata(dev); | 199 | struct radio_device *card = video_get_drvdata(dev); |
198 | 200 | ||
199 | switch (cmd) { | 201 | if (v->index > 0) |
200 | case VIDIOC_QUERYCAP: | 202 | return -EINVAL; |
201 | { | 203 | |
202 | struct v4l2_capability *v = arg; | 204 | (void)radio_bits_get(card); |
203 | memset(v,0,sizeof(*v)); | 205 | |
204 | strlcpy(v->driver, "radio-maestro", sizeof (v->driver)); | 206 | strcpy(v->name, "FM"); |
205 | strlcpy(v->card, "Maestro Radio", sizeof (v->card)); | 207 | v->type = V4L2_TUNER_RADIO; |
206 | sprintf(v->bus_info,"PCI"); | 208 | v->rangelow = FREQ_LO; |
207 | v->version = RADIO_VERSION; | 209 | v->rangehigh = FREQ_HI; |
208 | v->capabilities = V4L2_CAP_TUNER; | 210 | v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; |
209 | 211 | v->capability = V4L2_TUNER_CAP_LOW; | |
210 | return 0; | 212 | if(card->stereo) |
211 | } | 213 | v->audmode = V4L2_TUNER_MODE_STEREO; |
212 | case VIDIOC_G_TUNER: | 214 | else |
213 | { | 215 | v->audmode = V4L2_TUNER_MODE_MONO; |
214 | struct v4l2_tuner *v = arg; | 216 | v->signal = card->tuned; |
215 | 217 | return 0; | |
216 | if (v->index > 0) | 218 | } |
217 | return -EINVAL; | ||
218 | |||
219 | (void)radio_bits_get(card); | ||
220 | 219 | ||
221 | memset(v,0,sizeof(*v)); | 220 | static int vidioc_s_tuner(struct file *file, void *priv, |
222 | strcpy(v->name, "FM"); | 221 | struct v4l2_tuner *v) |
223 | v->type = V4L2_TUNER_RADIO; | 222 | { |
223 | if (v->index > 0) | ||
224 | return -EINVAL; | ||
225 | return 0; | ||
226 | } | ||
224 | 227 | ||
225 | v->rangelow = FREQ_LO; | 228 | static int vidioc_s_frequency(struct file *file, void *priv, |
226 | v->rangehigh = FREQ_HI; | 229 | struct v4l2_frequency *f) |
227 | v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; | 230 | { |
228 | v->capability=V4L2_TUNER_CAP_LOW; | 231 | struct video_device *dev = video_devdata(file); |
229 | if(card->stereo) | 232 | struct radio_device *card = video_get_drvdata(dev); |
230 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
231 | else | ||
232 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
233 | v->signal=card->tuned; | ||
234 | 233 | ||
235 | return 0; | 234 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) |
236 | } | 235 | return -EINVAL; |
237 | case VIDIOC_S_TUNER: | 236 | radio_bits_set(card, FREQ2BITS(f->frequency)); |
238 | { | 237 | return 0; |
239 | struct v4l2_tuner *v = arg; | 238 | } |
240 | 239 | ||
241 | if (v->index > 0) | 240 | static int vidioc_g_frequency(struct file *file, void *priv, |
242 | return -EINVAL; | 241 | struct v4l2_frequency *f) |
242 | { | ||
243 | struct video_device *dev = video_devdata(file); | ||
244 | struct radio_device *card = video_get_drvdata(dev); | ||
243 | 245 | ||
244 | return 0; | 246 | f->type = V4L2_TUNER_RADIO; |
245 | } | 247 | f->frequency = BITS2FREQ(radio_bits_get(card)); |
246 | case VIDIOC_S_FREQUENCY: | 248 | return 0; |
247 | { | 249 | } |
248 | struct v4l2_frequency *f = arg; | ||
249 | 250 | ||
250 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) | 251 | static int vidioc_queryctrl(struct file *file, void *priv, |
251 | return -EINVAL; | 252 | struct v4l2_queryctrl *qc) |
252 | radio_bits_set(card, FREQ2BITS(f->frequency)); | 253 | { |
254 | int i; | ||
253 | 255 | ||
256 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
257 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
258 | memcpy(qc, &(radio_qctrl[i]), | ||
259 | sizeof(*qc)); | ||
254 | return 0; | 260 | return 0; |
255 | } | 261 | } |
256 | case VIDIOC_G_FREQUENCY: | 262 | } |
257 | { | 263 | return -EINVAL; |
258 | struct v4l2_frequency *f = arg; | 264 | } |
259 | 265 | ||
260 | f->type = V4L2_TUNER_RADIO; | 266 | static int vidioc_g_ctrl(struct file *file, void *priv, |
261 | f->frequency = BITS2FREQ(radio_bits_get(card)); | 267 | struct v4l2_control *ctrl) |
268 | { | ||
269 | struct video_device *dev = video_devdata(file); | ||
270 | struct radio_device *card = video_get_drvdata(dev); | ||
262 | 271 | ||
263 | return 0; | 272 | switch (ctrl->id) { |
264 | } | 273 | case V4L2_CID_AUDIO_MUTE: |
265 | case VIDIOC_QUERYCTRL: | 274 | ctrl->value = card->muted; |
266 | { | 275 | return 0; |
267 | struct v4l2_queryctrl *qc = arg; | ||
268 | int i; | ||
269 | |||
270 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
271 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
272 | memcpy(qc, &(radio_qctrl[i]), | ||
273 | sizeof(*qc)); | ||
274 | return (0); | ||
275 | } | ||
276 | } | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | case VIDIOC_G_CTRL: | ||
280 | { | ||
281 | struct v4l2_control *ctrl= arg; | ||
282 | |||
283 | switch (ctrl->id) { | ||
284 | case V4L2_CID_AUDIO_MUTE: | ||
285 | ctrl->value=card->muted; | ||
286 | return (0); | ||
287 | } | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | case VIDIOC_S_CTRL: | ||
291 | { | ||
292 | struct v4l2_control *ctrl= arg; | ||
293 | |||
294 | switch (ctrl->id) { | ||
295 | case V4L2_CID_AUDIO_MUTE: | ||
296 | { | ||
297 | register u16 io = card->io; | ||
298 | register u16 omask = inw(io + IO_MASK); | ||
299 | outw(~STR_WREN, io + IO_MASK); | ||
300 | outw((card->muted = ctrl->value ) ? | ||
301 | STR_WREN : 0, io); | ||
302 | udelay(4); | ||
303 | outw(omask, io + IO_MASK); | ||
304 | msleep(125); | ||
305 | |||
306 | return (0); | ||
307 | } | ||
308 | } | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | default: | ||
312 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
313 | radio_function); | ||
314 | } | 276 | } |
277 | return -EINVAL; | ||
315 | } | 278 | } |
316 | 279 | ||
317 | static int radio_ioctl(struct inode *inode, struct file *file, | 280 | static int vidioc_s_ctrl(struct file *file, void *priv, |
318 | unsigned int cmd, unsigned long arg) | 281 | struct v4l2_control *ctrl) |
319 | { | 282 | { |
320 | struct video_device *dev = video_devdata(file); | 283 | struct video_device *dev = video_devdata(file); |
321 | struct radio_device *card = video_get_drvdata(dev); | 284 | struct radio_device *card = video_get_drvdata(dev); |
322 | int ret; | 285 | register u16 io = card->io; |
286 | register u16 omask = inw(io + IO_MASK); | ||
287 | |||
288 | switch (ctrl->id) { | ||
289 | case V4L2_CID_AUDIO_MUTE: | ||
290 | outw(~STR_WREN, io + IO_MASK); | ||
291 | outw((card->muted = ctrl->value ) ? | ||
292 | STR_WREN : 0, io); | ||
293 | udelay(4); | ||
294 | outw(omask, io + IO_MASK); | ||
295 | msleep(125); | ||
296 | return 0; | ||
297 | } | ||
298 | return -EINVAL; | ||
299 | } | ||
323 | 300 | ||
324 | mutex_lock(&card->lock); | 301 | static int vidioc_g_audio(struct file *file, void *priv, |
325 | ret = video_usercopy(inode, file, cmd, arg, radio_function); | 302 | struct v4l2_audio *a) |
326 | mutex_unlock(&card->lock); | 303 | { |
304 | if (a->index > 1) | ||
305 | return -EINVAL; | ||
327 | 306 | ||
328 | return ret; | 307 | strcpy(a->name, "Radio"); |
308 | a->capability = V4L2_AUDCAP_STEREO; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
313 | { | ||
314 | *i = 0; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
319 | { | ||
320 | if (i != 0) | ||
321 | return -EINVAL; | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int vidioc_s_audio(struct file *file, void *priv, | ||
326 | struct v4l2_audio *a) | ||
327 | { | ||
328 | if (a->index != 0) | ||
329 | return -EINVAL; | ||
330 | return 0; | ||
329 | } | 331 | } |
330 | 332 | ||
331 | static u16 __devinit radio_power_on(struct radio_device *dev) | 333 | static u16 __devinit radio_power_on(struct radio_device *dev) |
@@ -352,6 +354,24 @@ static u16 __devinit radio_power_on(struct radio_device *dev) | |||
352 | return (ofreq == radio_bits_get(dev)); | 354 | return (ofreq == radio_bits_get(dev)); |
353 | } | 355 | } |
354 | 356 | ||
357 | static struct video_device maestro_radio = { | ||
358 | .name = "Maestro radio", | ||
359 | .type = VID_TYPE_TUNER, | ||
360 | .fops = &maestro_fops, | ||
361 | .vidioc_querycap = vidioc_querycap, | ||
362 | .vidioc_g_tuner = vidioc_g_tuner, | ||
363 | .vidioc_s_tuner = vidioc_s_tuner, | ||
364 | .vidioc_g_audio = vidioc_g_audio, | ||
365 | .vidioc_s_audio = vidioc_s_audio, | ||
366 | .vidioc_g_input = vidioc_g_input, | ||
367 | .vidioc_s_input = vidioc_s_input, | ||
368 | .vidioc_g_frequency = vidioc_g_frequency, | ||
369 | .vidioc_s_frequency = vidioc_s_frequency, | ||
370 | .vidioc_queryctrl = vidioc_queryctrl, | ||
371 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
372 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
373 | }; | ||
374 | |||
355 | static int __devinit maestro_probe(struct pci_dev *pdev, | 375 | static int __devinit maestro_probe(struct pci_dev *pdev, |
356 | const struct pci_device_id *ent) | 376 | const struct pci_device_id *ent) |
357 | { | 377 | { |