V4L/DVB (6731): ivtv: Remove a invalid shadow-variable
[deliverable/linux.git] / drivers / media / radio / dsbr100.c
CommitLineData
1da177e4
LT
1/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs
2 into both the USB and an analog audio input, so this thing
3 only deals with initialisation and frequency setting, the
4 audio data has to be handled by a sound driver.
5
6 Major issue: I can't find out where the device reports the signal
7 strength, and indeed the windows software appearantly just looks
8 at the stereo indicator as well. So, scanning will only find
9 stereo stations. Sad, but I can't help it.
10
11 Also, the windows program sends oodles of messages over to the
12 device, and I couldn't figure out their meaning. My suspicion
13 is that they don't have any:-)
14
15 You might find some interesting stuff about this module at
16 http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
17
18 Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
19
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 2 of the License, or
23 (at your option) any later version.
24
25 This program is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33
34 History:
35
7002a4f3
DL
36 Version 0.42:
37 Converted dsbr100 to use video_ioctl2
38 by Douglas Landgraf <dougsland@gmail.com>
39
5aff308c
AC
40 Version 0.41-ac1:
41 Alan Cox: Some cleanups and fixes
42
43 Version 0.41:
44 Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
45
1da177e4 46 Version 0.40:
5aff308c 47 Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
1da177e4
LT
48
49 Version 0.30:
d56410e0 50 Markus: Updates for 2.5.x kernel and more ISO compliant source
1da177e4
LT
51
52 Version 0.25:
d56410e0 53 PSL and Markus: Cleanup, radio now doesn't stop on device close
1da177e4
LT
54
55 Version 0.24:
d56410e0 56 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
1da177e4
LT
57 right. Some minor cleanup, improved standalone compilation
58
59 Version 0.23:
d56410e0 60 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
1da177e4
LT
61
62 Version 0.22:
d56410e0 63 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
1da177e4
LT
64 thanks to Mike Cox for pointing the problem out.
65
66 Version 0.21:
d56410e0 67 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
1da177e4
LT
68 to adhere to Documentation/CodingStyle
69
d56410e0
MCC
70 Version 0.2:
71 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
1da177e4
LT
72 Markus: Copyright clarification
73
74 Version 0.01: Markus: initial release
75
76*/
77
1da177e4
LT
78#include <linux/kernel.h>
79#include <linux/module.h>
80#include <linux/init.h>
81#include <linux/slab.h>
82#include <linux/input.h>
5aff308c 83#include <linux/videodev2.h>
5e87efa3 84#include <media/v4l2-common.h>
1da177e4 85#include <linux/usb.h>
1da177e4
LT
86
87/*
88 * Version Information
89 */
5aff308c
AC
90#include <linux/version.h> /* for KERNEL_VERSION MACRO */
91
92#define DRIVER_VERSION "v0.41"
93#define RADIO_VERSION KERNEL_VERSION(0,4,1)
94
95static struct v4l2_queryctrl radio_qctrl[] = {
96 {
97 .id = V4L2_CID_AUDIO_MUTE,
98 .name = "Mute",
99 .minimum = 0,
100 .maximum = 1,
101 .default_value = 1,
102 .type = V4L2_CTRL_TYPE_BOOLEAN,
103 }
104};
105
1da177e4
LT
106#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
107#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
108
109#define DSB100_VENDOR 0x04b4
110#define DSB100_PRODUCT 0x1002
111
112/* Commands the device appears to understand */
113#define DSB100_TUNE 1
114#define DSB100_ONOFF 2
115
116#define TB_LEN 16
117
118/* Frequency limits in MHz -- these are European values. For Japanese
119devices, that would be 76 and 91. */
120#define FREQ_MIN 87.5
121#define FREQ_MAX 108.0
122#define FREQ_MUL 16000
123
124
125static int usb_dsbr100_probe(struct usb_interface *intf,
126 const struct usb_device_id *id);
127static void usb_dsbr100_disconnect(struct usb_interface *intf);
1da177e4
LT
128static int usb_dsbr100_open(struct inode *inode, struct file *file);
129static int usb_dsbr100_close(struct inode *inode, struct file *file);
130
131static int radio_nr = -1;
132module_param(radio_nr, int, 0);
133
134/* Data for one (physical) device */
5aff308c 135struct dsbr100_device {
1da177e4
LT
136 struct usb_device *usbdev;
137 struct video_device *videodev;
138 unsigned char transfer_buffer[TB_LEN];
139 int curfreq;
140 int stereo;
141 int users;
142 int removed;
5aff308c
AC
143 int muted;
144};
1da177e4
LT
145
146
1da177e4
LT
147static struct usb_device_id usb_dsbr100_device_table [] = {
148 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
149 { } /* Terminating entry */
150};
151
152MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
153
154/* USB subsystem interface */
155static struct usb_driver usb_dsbr100_driver = {
1da177e4
LT
156 .name = "dsbr100",
157 .probe = usb_dsbr100_probe,
158 .disconnect = usb_dsbr100_disconnect,
159 .id_table = usb_dsbr100_device_table,
160};
161
162/* Low-level device interface begins here */
163
164/* switch on radio */
5aff308c 165static int dsbr100_start(struct dsbr100_device *radio)
1da177e4
LT
166{
167 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 168 USB_REQ_GET_STATUS,
1da177e4
LT
169 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
170 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
171 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 172 DSB100_ONOFF,
1da177e4
LT
173 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
174 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
175 return -1;
5aff308c 176 radio->muted=0;
1da177e4
LT
177 return (radio->transfer_buffer)[0];
178}
179
180
181/* switch off radio */
5aff308c 182static int dsbr100_stop(struct dsbr100_device *radio)
1da177e4
LT
183{
184 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 185 USB_REQ_GET_STATUS,
1da177e4
LT
186 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
187 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
188 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 189 DSB100_ONOFF,
1da177e4
LT
190 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
191 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
192 return -1;
5aff308c 193 radio->muted=1;
1da177e4
LT
194 return (radio->transfer_buffer)[0];
195}
196
197/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
5aff308c 198static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
1da177e4
LT
199{
200 freq = (freq/16*80)/1000+856;
201 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 202 DSB100_TUNE,
1da177e4 203 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
d56410e0 204 (freq>>8)&0x00ff, freq&0xff,
1da177e4
LT
205 radio->transfer_buffer, 8, 300)<0 ||
206 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 207 USB_REQ_GET_STATUS,
1da177e4
LT
208 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
209 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
210 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 211 USB_REQ_GET_STATUS,
1da177e4
LT
212 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
213 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
214 radio->stereo = -1;
215 return -1;
216 }
217 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
218 return (radio->transfer_buffer)[0];
219}
220
221/* return the device status. This is, in effect, just whether it
222sees a stereo signal or not. Pity. */
5aff308c 223static void dsbr100_getstat(struct dsbr100_device *radio)
1da177e4
LT
224{
225 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 226 USB_REQ_GET_STATUS,
1da177e4
LT
227 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
228 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
229 radio->stereo = -1;
230 else
231 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
232}
233
234
235/* USB subsystem interface begins here */
236
1da177e4
LT
237/* handle unplugging of the device, release data structures
238if nothing keeps us from doing it. If something is still
239keeping us busy, the release callback of v4l will take care
240of releasing it. stv680.c does not relase its private
241data, so I don't do this here either. Checking out the
242code I'd expect I better did that, but if there's a memory
243leak here it's tiny (~50 bytes per disconnect) */
244static void usb_dsbr100_disconnect(struct usb_interface *intf)
245{
5aff308c 246 struct dsbr100_device *radio = usb_get_intfdata(intf);
1da177e4
LT
247
248 usb_set_intfdata (intf, NULL);
249 if (radio) {
250 video_unregister_device(radio->videodev);
251 radio->videodev = NULL;
252 if (radio->users) {
253 kfree(radio);
254 } else {
255 radio->removed = 1;
256 }
257 }
258}
259
260
7002a4f3
DL
261static int vidioc_querycap(struct file *file, void *priv,
262 struct v4l2_capability *v)
263{
264 strlcpy(v->driver, "dsbr100", sizeof(v->driver));
265 strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
266 sprintf(v->bus_info, "ISA");
267 v->version = RADIO_VERSION;
268 v->capabilities = V4L2_CAP_TUNER;
269 return 0;
270}
1da177e4 271
7002a4f3
DL
272static int vidioc_g_tuner(struct file *file, void *priv,
273 struct v4l2_tuner *v)
1da177e4 274{
7002a4f3
DL
275 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
276
277 if (v->index > 0)
278 return -EINVAL;
279
280 dsbr100_getstat(radio);
281 strcpy(v->name, "FM");
282 v->type = V4L2_TUNER_RADIO;
283 v->rangelow = FREQ_MIN*FREQ_MUL;
284 v->rangehigh = FREQ_MAX*FREQ_MUL;
285 v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
286 v->capability = V4L2_TUNER_CAP_LOW;
287 if(radio->stereo)
288 v->audmode = V4L2_TUNER_MODE_STEREO;
289 else
290 v->audmode = V4L2_TUNER_MODE_MONO;
291 v->signal = 0xffff; /* We can't get the signal strength */
292 return 0;
293}
1da177e4 294
7002a4f3
DL
295static int vidioc_s_tuner(struct file *file, void *priv,
296 struct v4l2_tuner *v)
297{
298 if (v->index > 0)
299 return -EINVAL;
1da177e4 300
7002a4f3
DL
301 return 0;
302}
5aff308c 303
7002a4f3
DL
304static int vidioc_s_frequency(struct file *file, void *priv,
305 struct v4l2_frequency *f)
306{
307 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
1da177e4 308
7002a4f3
DL
309 radio->curfreq = f->frequency;
310 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
311 warn("Set frequency failed");
312 return 0;
313}
5aff308c 314
7002a4f3
DL
315static int vidioc_g_frequency(struct file *file, void *priv,
316 struct v4l2_frequency *f)
317{
318 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
5aff308c 319
7002a4f3
DL
320 f->type = V4L2_TUNER_RADIO;
321 f->frequency = radio->curfreq;
322 return 0;
323}
5aff308c 324
7002a4f3
DL
325static int vidioc_queryctrl(struct file *file, void *priv,
326 struct v4l2_queryctrl *qc)
327{
328 int i;
1da177e4 329
7002a4f3
DL
330 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
331 if (qc->id && qc->id == radio_qctrl[i].id) {
332 memcpy(qc, &(radio_qctrl[i]),
333 sizeof(*qc));
1da177e4
LT
334 return 0;
335 }
7002a4f3
DL
336 }
337 return -EINVAL;
338}
5aff308c 339
7002a4f3
DL
340static int vidioc_g_ctrl(struct file *file, void *priv,
341 struct v4l2_control *ctrl)
342{
343 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
1da177e4 344
7002a4f3
DL
345 switch (ctrl->id) {
346 case V4L2_CID_AUDIO_MUTE:
347 ctrl->value = radio->muted;
348 return 0;
349 }
350 return -EINVAL;
351}
5aff308c 352
7002a4f3
DL
353static int vidioc_s_ctrl(struct file *file, void *priv,
354 struct v4l2_control *ctrl)
355{
356 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
5aff308c 357
7002a4f3
DL
358 switch (ctrl->id) {
359 case V4L2_CID_AUDIO_MUTE:
360 if (ctrl->value) {
361 if (dsbr100_stop(radio)==-1)
362 warn("Radio did not respond properly");
363 } else {
364 if (dsbr100_start(radio)==-1)
365 warn("Radio did not respond properly");
1da177e4 366 }
7002a4f3 367 return 0;
1da177e4 368 }
7002a4f3 369 return -EINVAL;
1da177e4
LT
370}
371
7002a4f3
DL
372static int vidioc_g_audio(struct file *file, void *priv,
373 struct v4l2_audio *a)
1da177e4 374{
7002a4f3
DL
375 if (a->index > 1)
376 return -EINVAL;
377
378 strcpy(a->name, "Radio");
379 a->capability = V4L2_AUDCAP_STEREO;
380 return 0;
381}
382
383static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
384{
385 *i = 0;
386 return 0;
387}
388
389static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
390{
391 if (i != 0)
392 return -EINVAL;
393 return 0;
394}
395
396static int vidioc_s_audio(struct file *file, void *priv,
397 struct v4l2_audio *a)
398{
399 if (a->index != 0)
400 return -EINVAL;
401 return 0;
1da177e4
LT
402}
403
404static int usb_dsbr100_open(struct inode *inode, struct file *file)
405{
5aff308c 406 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
1da177e4
LT
407
408 radio->users = 1;
5aff308c
AC
409 radio->muted = 1;
410
1da177e4
LT
411 if (dsbr100_start(radio)<0) {
412 warn("Radio did not start up properly");
413 radio->users = 0;
414 return -EIO;
415 }
416 dsbr100_setfreq(radio, radio->curfreq);
417 return 0;
418}
419
420static int usb_dsbr100_close(struct inode *inode, struct file *file)
421{
5aff308c 422 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
1da177e4
LT
423
424 if (!radio)
425 return -ENODEV;
426 radio->users = 0;
427 if (radio->removed) {
428 kfree(radio);
429 }
430 return 0;
431}
432
7002a4f3
DL
433/* File system interface */
434static const struct file_operations usb_dsbr100_fops = {
435 .owner = THIS_MODULE,
436 .open = usb_dsbr100_open,
437 .release = usb_dsbr100_close,
438 .ioctl = video_ioctl2,
439 .compat_ioctl = v4l_compat_ioctl32,
440 .llseek = no_llseek,
441};
442
443/* V4L2 interface */
444static struct video_device dsbr100_videodev_template =
445{
446 .owner = THIS_MODULE,
447 .name = "D-Link DSB-R 100",
448 .type = VID_TYPE_TUNER,
449 .fops = &usb_dsbr100_fops,
450 .release = video_device_release,
451 .vidioc_querycap = vidioc_querycap,
452 .vidioc_g_tuner = vidioc_g_tuner,
453 .vidioc_s_tuner = vidioc_s_tuner,
454 .vidioc_g_frequency = vidioc_g_frequency,
455 .vidioc_s_frequency = vidioc_s_frequency,
456 .vidioc_queryctrl = vidioc_queryctrl,
457 .vidioc_g_ctrl = vidioc_g_ctrl,
458 .vidioc_s_ctrl = vidioc_s_ctrl,
459 .vidioc_g_audio = vidioc_g_audio,
460 .vidioc_s_audio = vidioc_s_audio,
461 .vidioc_g_input = vidioc_g_input,
462 .vidioc_s_input = vidioc_s_input,
463};
464
465/* check if the device is present and register with v4l and
466usb if it is */
467static int usb_dsbr100_probe(struct usb_interface *intf,
468 const struct usb_device_id *id)
469{
470 struct dsbr100_device *radio;
471
472 if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
473 return -ENOMEM;
474 if (!(radio->videodev = video_device_alloc())) {
475 kfree(radio);
476 return -ENOMEM;
477 }
478 memcpy(radio->videodev, &dsbr100_videodev_template,
479 sizeof(dsbr100_videodev_template));
480 radio->removed = 0;
481 radio->users = 0;
482 radio->usbdev = interface_to_usbdev(intf);
483 radio->curfreq = FREQ_MIN*FREQ_MUL;
484 video_set_drvdata(radio->videodev, radio);
485 if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
486 warn("Could not register video device");
487 video_device_release(radio->videodev);
488 kfree(radio);
489 return -EIO;
490 }
491 usb_set_intfdata(intf, radio);
492 return 0;
493}
494
1da177e4
LT
495static int __init dsbr100_init(void)
496{
497 int retval = usb_register(&usb_dsbr100_driver);
498 info(DRIVER_VERSION ":" DRIVER_DESC);
499 return retval;
500}
501
502static void __exit dsbr100_exit(void)
503{
504 usb_deregister(&usb_dsbr100_driver);
505}
506
507module_init (dsbr100_init);
508module_exit (dsbr100_exit);
509
510MODULE_AUTHOR( DRIVER_AUTHOR );
511MODULE_DESCRIPTION( DRIVER_DESC );
512MODULE_LICENSE("GPL");
This page took 0.323755 seconds and 5 git commands to generate.