pcmcia: CompactFlash driver for PA Semi Electra boards
[pv_ops_mirror.git] / drivers / media / radio / dsbr100.c
blob3bd07f7e377489198ca539deee8e3401ffa5056a
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.
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.
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:-)
15 You might find some interesting stuff about this module at
16 http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
18 Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
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.
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.
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
34 History:
36 Version 0.42:
37 Converted dsbr100 to use video_ioctl2
38 by Douglas Landgraf <dougsland@gmail.com>
40 Version 0.41-ac1:
41 Alan Cox: Some cleanups and fixes
43 Version 0.41:
44 Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
46 Version 0.40:
47 Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
49 Version 0.30:
50 Markus: Updates for 2.5.x kernel and more ISO compliant source
52 Version 0.25:
53 PSL and Markus: Cleanup, radio now doesn't stop on device close
55 Version 0.24:
56 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
57 right. Some minor cleanup, improved standalone compilation
59 Version 0.23:
60 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
62 Version 0.22:
63 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
64 thanks to Mike Cox for pointing the problem out.
66 Version 0.21:
67 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
68 to adhere to Documentation/CodingStyle
70 Version 0.2:
71 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
72 Markus: Copyright clarification
74 Version 0.01: Markus: initial release
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>
83 #include <linux/videodev2.h>
84 #include <media/v4l2-common.h>
85 #include <linux/usb.h>
88 * Version Information
90 #include <linux/version.h> /* for KERNEL_VERSION MACRO */
92 #define DRIVER_VERSION "v0.41"
93 #define RADIO_VERSION KERNEL_VERSION(0,4,1)
95 static struct v4l2_queryctrl radio_qctrl[] = {
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,
106 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
107 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
109 #define DSB100_VENDOR 0x04b4
110 #define DSB100_PRODUCT 0x1002
112 /* Commands the device appears to understand */
113 #define DSB100_TUNE 1
114 #define DSB100_ONOFF 2
116 #define TB_LEN 16
118 /* Frequency limits in MHz -- these are European values. For Japanese
119 devices, that would be 76 and 91. */
120 #define FREQ_MIN 87.5
121 #define FREQ_MAX 108.0
122 #define FREQ_MUL 16000
125 static int usb_dsbr100_probe(struct usb_interface *intf,
126 const struct usb_device_id *id);
127 static void usb_dsbr100_disconnect(struct usb_interface *intf);
128 static int usb_dsbr100_open(struct inode *inode, struct file *file);
129 static int usb_dsbr100_close(struct inode *inode, struct file *file);
131 static int radio_nr = -1;
132 module_param(radio_nr, int, 0);
134 /* Data for one (physical) device */
135 struct dsbr100_device {
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;
143 int muted;
147 static struct usb_device_id usb_dsbr100_device_table [] = {
148 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
149 { } /* Terminating entry */
152 MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
154 /* USB subsystem interface */
155 static struct usb_driver usb_dsbr100_driver = {
156 .name = "dsbr100",
157 .probe = usb_dsbr100_probe,
158 .disconnect = usb_dsbr100_disconnect,
159 .id_table = usb_dsbr100_device_table,
162 /* Low-level device interface begins here */
164 /* switch on radio */
165 static int dsbr100_start(struct dsbr100_device *radio)
167 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
168 USB_REQ_GET_STATUS,
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),
172 DSB100_ONOFF,
173 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
174 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
175 return -1;
176 radio->muted=0;
177 return (radio->transfer_buffer)[0];
181 /* switch off radio */
182 static int dsbr100_stop(struct dsbr100_device *radio)
184 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
185 USB_REQ_GET_STATUS,
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),
189 DSB100_ONOFF,
190 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
191 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
192 return -1;
193 radio->muted=1;
194 return (radio->transfer_buffer)[0];
197 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
198 static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
200 freq = (freq/16*80)/1000+856;
201 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
202 DSB100_TUNE,
203 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
204 (freq>>8)&0x00ff, freq&0xff,
205 radio->transfer_buffer, 8, 300)<0 ||
206 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
207 USB_REQ_GET_STATUS,
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),
211 USB_REQ_GET_STATUS,
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;
217 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
218 return (radio->transfer_buffer)[0];
221 /* return the device status. This is, in effect, just whether it
222 sees a stereo signal or not. Pity. */
223 static void dsbr100_getstat(struct dsbr100_device *radio)
225 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
226 USB_REQ_GET_STATUS,
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);
235 /* USB subsystem interface begins here */
237 /* handle unplugging of the device, release data structures
238 if nothing keeps us from doing it. If something is still
239 keeping us busy, the release callback of v4l will take care
240 of releasing it. stv680.c does not relase its private
241 data, so I don't do this here either. Checking out the
242 code I'd expect I better did that, but if there's a memory
243 leak here it's tiny (~50 bytes per disconnect) */
244 static void usb_dsbr100_disconnect(struct usb_interface *intf)
246 struct dsbr100_device *radio = usb_get_intfdata(intf);
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;
261 static int vidioc_querycap(struct file *file, void *priv,
262 struct v4l2_capability *v)
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;
272 static int vidioc_g_tuner(struct file *file, void *priv,
273 struct v4l2_tuner *v)
275 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
277 if (v->index > 0)
278 return -EINVAL;
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;
295 static int vidioc_s_tuner(struct file *file, void *priv,
296 struct v4l2_tuner *v)
298 if (v->index > 0)
299 return -EINVAL;
301 return 0;
304 static int vidioc_s_frequency(struct file *file, void *priv,
305 struct v4l2_frequency *f)
307 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
309 radio->curfreq = f->frequency;
310 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
311 warn("Set frequency failed");
312 return 0;
315 static int vidioc_g_frequency(struct file *file, void *priv,
316 struct v4l2_frequency *f)
318 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
320 f->type = V4L2_TUNER_RADIO;
321 f->frequency = radio->curfreq;
322 return 0;
325 static int vidioc_queryctrl(struct file *file, void *priv,
326 struct v4l2_queryctrl *qc)
328 int i;
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));
334 return 0;
337 return -EINVAL;
340 static int vidioc_g_ctrl(struct file *file, void *priv,
341 struct v4l2_control *ctrl)
343 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
345 switch (ctrl->id) {
346 case V4L2_CID_AUDIO_MUTE:
347 ctrl->value = radio->muted;
348 return 0;
350 return -EINVAL;
353 static int vidioc_s_ctrl(struct file *file, void *priv,
354 struct v4l2_control *ctrl)
356 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
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");
367 return 0;
369 return -EINVAL;
372 static int vidioc_g_audio(struct file *file, void *priv,
373 struct v4l2_audio *a)
375 if (a->index > 1)
376 return -EINVAL;
378 strcpy(a->name, "Radio");
379 a->capability = V4L2_AUDCAP_STEREO;
380 return 0;
383 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
385 *i = 0;
386 return 0;
389 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
391 if (i != 0)
392 return -EINVAL;
393 return 0;
396 static int vidioc_s_audio(struct file *file, void *priv,
397 struct v4l2_audio *a)
399 if (a->index != 0)
400 return -EINVAL;
401 return 0;
404 static int usb_dsbr100_open(struct inode *inode, struct file *file)
406 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
408 radio->users = 1;
409 radio->muted = 1;
411 if (dsbr100_start(radio)<0) {
412 warn("Radio did not start up properly");
413 radio->users = 0;
414 return -EIO;
416 dsbr100_setfreq(radio, radio->curfreq);
417 return 0;
420 static int usb_dsbr100_close(struct inode *inode, struct file *file)
422 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
424 if (!radio)
425 return -ENODEV;
426 radio->users = 0;
427 if (radio->removed) {
428 kfree(radio);
430 return 0;
433 /* File system interface */
434 static 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,
443 /* V4L2 interface */
444 static struct video_device dsbr100_videodev_template =
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,
465 /* check if the device is present and register with v4l and
466 usb if it is */
467 static int usb_dsbr100_probe(struct usb_interface *intf,
468 const struct usb_device_id *id)
470 struct dsbr100_device *radio;
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;
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;
491 usb_set_intfdata(intf, radio);
492 return 0;
495 static int __init dsbr100_init(void)
497 int retval = usb_register(&usb_dsbr100_driver);
498 info(DRIVER_VERSION ":" DRIVER_DESC);
499 return retval;
502 static void __exit dsbr100_exit(void)
504 usb_deregister(&usb_dsbr100_driver);
507 module_init (dsbr100_init);
508 module_exit (dsbr100_exit);
510 MODULE_AUTHOR( DRIVER_AUTHOR );
511 MODULE_DESCRIPTION( DRIVER_DESC );
512 MODULE_LICENSE("GPL");