V4L/DVB (5622): Radio-zoltrix.c cleanup
[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
5aff308c
AC
36 Version 0.41-ac1:
37 Alan Cox: Some cleanups and fixes
38
39 Version 0.41:
40 Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
41
1da177e4 42 Version 0.40:
5aff308c 43 Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
1da177e4
LT
44
45 Version 0.30:
d56410e0 46 Markus: Updates for 2.5.x kernel and more ISO compliant source
1da177e4
LT
47
48 Version 0.25:
d56410e0 49 PSL and Markus: Cleanup, radio now doesn't stop on device close
1da177e4
LT
50
51 Version 0.24:
d56410e0 52 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
1da177e4
LT
53 right. Some minor cleanup, improved standalone compilation
54
55 Version 0.23:
d56410e0 56 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
1da177e4
LT
57
58 Version 0.22:
d56410e0 59 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
1da177e4
LT
60 thanks to Mike Cox for pointing the problem out.
61
62 Version 0.21:
d56410e0 63 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
1da177e4
LT
64 to adhere to Documentation/CodingStyle
65
d56410e0
MCC
66 Version 0.2:
67 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
1da177e4
LT
68 Markus: Copyright clarification
69
70 Version 0.01: Markus: initial release
71
72*/
73
1da177e4
LT
74#include <linux/kernel.h>
75#include <linux/module.h>
76#include <linux/init.h>
77#include <linux/slab.h>
78#include <linux/input.h>
5aff308c 79#include <linux/videodev2.h>
5e87efa3 80#include <media/v4l2-common.h>
1da177e4 81#include <linux/usb.h>
1da177e4
LT
82
83/*
84 * Version Information
85 */
5aff308c
AC
86#include <linux/version.h> /* for KERNEL_VERSION MACRO */
87
88#define DRIVER_VERSION "v0.41"
89#define RADIO_VERSION KERNEL_VERSION(0,4,1)
90
91static struct v4l2_queryctrl radio_qctrl[] = {
92 {
93 .id = V4L2_CID_AUDIO_MUTE,
94 .name = "Mute",
95 .minimum = 0,
96 .maximum = 1,
97 .default_value = 1,
98 .type = V4L2_CTRL_TYPE_BOOLEAN,
99 }
100};
101
1da177e4
LT
102#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
103#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
104
105#define DSB100_VENDOR 0x04b4
106#define DSB100_PRODUCT 0x1002
107
108/* Commands the device appears to understand */
109#define DSB100_TUNE 1
110#define DSB100_ONOFF 2
111
112#define TB_LEN 16
113
114/* Frequency limits in MHz -- these are European values. For Japanese
115devices, that would be 76 and 91. */
116#define FREQ_MIN 87.5
117#define FREQ_MAX 108.0
118#define FREQ_MUL 16000
119
120
121static int usb_dsbr100_probe(struct usb_interface *intf,
122 const struct usb_device_id *id);
123static void usb_dsbr100_disconnect(struct usb_interface *intf);
124static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
125 unsigned int cmd, unsigned long arg);
126static int usb_dsbr100_open(struct inode *inode, struct file *file);
127static int usb_dsbr100_close(struct inode *inode, struct file *file);
128
129static int radio_nr = -1;
130module_param(radio_nr, int, 0);
131
132/* Data for one (physical) device */
5aff308c 133struct dsbr100_device {
1da177e4
LT
134 struct usb_device *usbdev;
135 struct video_device *videodev;
136 unsigned char transfer_buffer[TB_LEN];
137 int curfreq;
138 int stereo;
139 int users;
140 int removed;
5aff308c
AC
141 int muted;
142};
1da177e4
LT
143
144
145/* File system interface */
fa027c2a 146static const struct file_operations usb_dsbr100_fops = {
1da177e4
LT
147 .owner = THIS_MODULE,
148 .open = usb_dsbr100_open,
149 .release = usb_dsbr100_close,
150 .ioctl = usb_dsbr100_ioctl,
0d0fbf81 151 .compat_ioctl = v4l_compat_ioctl32,
1da177e4
LT
152 .llseek = no_llseek,
153};
154
155/* V4L interface */
156static struct video_device dsbr100_videodev_template=
157{
158 .owner = THIS_MODULE,
159 .name = "D-Link DSB-R 100",
160 .type = VID_TYPE_TUNER,
1da177e4
LT
161 .fops = &usb_dsbr100_fops,
162 .release = video_device_release,
163};
164
165static struct usb_device_id usb_dsbr100_device_table [] = {
166 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
167 { } /* Terminating entry */
168};
169
170MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
171
172/* USB subsystem interface */
173static struct usb_driver usb_dsbr100_driver = {
1da177e4
LT
174 .name = "dsbr100",
175 .probe = usb_dsbr100_probe,
176 .disconnect = usb_dsbr100_disconnect,
177 .id_table = usb_dsbr100_device_table,
178};
179
180/* Low-level device interface begins here */
181
182/* switch on radio */
5aff308c 183static int dsbr100_start(struct dsbr100_device *radio)
1da177e4
LT
184{
185 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 186 USB_REQ_GET_STATUS,
1da177e4
LT
187 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
188 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
189 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 190 DSB100_ONOFF,
1da177e4
LT
191 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
192 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
193 return -1;
5aff308c 194 radio->muted=0;
1da177e4
LT
195 return (radio->transfer_buffer)[0];
196}
197
198
199/* switch off radio */
5aff308c 200static int dsbr100_stop(struct dsbr100_device *radio)
1da177e4
LT
201{
202 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 203 USB_REQ_GET_STATUS,
1da177e4
LT
204 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
205 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
206 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 207 DSB100_ONOFF,
1da177e4
LT
208 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
209 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
210 return -1;
5aff308c 211 radio->muted=1;
1da177e4
LT
212 return (radio->transfer_buffer)[0];
213}
214
215/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
5aff308c 216static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
1da177e4
LT
217{
218 freq = (freq/16*80)/1000+856;
219 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 220 DSB100_TUNE,
1da177e4 221 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
d56410e0 222 (freq>>8)&0x00ff, freq&0xff,
1da177e4
LT
223 radio->transfer_buffer, 8, 300)<0 ||
224 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 225 USB_REQ_GET_STATUS,
1da177e4
LT
226 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
227 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
228 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 229 USB_REQ_GET_STATUS,
1da177e4
LT
230 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
231 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
232 radio->stereo = -1;
233 return -1;
234 }
235 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
236 return (radio->transfer_buffer)[0];
237}
238
239/* return the device status. This is, in effect, just whether it
240sees a stereo signal or not. Pity. */
5aff308c 241static void dsbr100_getstat(struct dsbr100_device *radio)
1da177e4
LT
242{
243 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0 244 USB_REQ_GET_STATUS,
1da177e4
LT
245 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
246 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
247 radio->stereo = -1;
248 else
249 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
250}
251
252
253/* USB subsystem interface begins here */
254
255/* check if the device is present and register with v4l and
256usb if it is */
d56410e0 257static int usb_dsbr100_probe(struct usb_interface *intf,
1da177e4
LT
258 const struct usb_device_id *id)
259{
5aff308c 260 struct dsbr100_device *radio;
1da177e4 261
5aff308c 262 if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
1da177e4
LT
263 return -ENOMEM;
264 if (!(radio->videodev = video_device_alloc())) {
265 kfree(radio);
266 return -ENOMEM;
267 }
d56410e0 268 memcpy(radio->videodev, &dsbr100_videodev_template,
1da177e4
LT
269 sizeof(dsbr100_videodev_template));
270 radio->removed = 0;
271 radio->users = 0;
272 radio->usbdev = interface_to_usbdev(intf);
273 radio->curfreq = FREQ_MIN*FREQ_MUL;
274 video_set_drvdata(radio->videodev, radio);
275 if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
276 radio_nr)) {
277 warn("Could not register video device");
278 video_device_release(radio->videodev);
279 kfree(radio);
280 return -EIO;
281 }
282 usb_set_intfdata(intf, radio);
283 return 0;
284}
285
286/* handle unplugging of the device, release data structures
287if nothing keeps us from doing it. If something is still
288keeping us busy, the release callback of v4l will take care
289of releasing it. stv680.c does not relase its private
290data, so I don't do this here either. Checking out the
291code I'd expect I better did that, but if there's a memory
292leak here it's tiny (~50 bytes per disconnect) */
293static void usb_dsbr100_disconnect(struct usb_interface *intf)
294{
5aff308c 295 struct dsbr100_device *radio = usb_get_intfdata(intf);
1da177e4
LT
296
297 usb_set_intfdata (intf, NULL);
298 if (radio) {
299 video_unregister_device(radio->videodev);
300 radio->videodev = NULL;
301 if (radio->users) {
302 kfree(radio);
303 } else {
304 radio->removed = 1;
305 }
306 }
307}
308
309
310/* Video for Linux interface */
311
312static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
313 unsigned int cmd, void *arg)
314{
5aff308c 315 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
1da177e4
LT
316
317 if (!radio)
318 return -EIO;
319
320 switch(cmd) {
5aff308c
AC
321 case VIDIOC_QUERYCAP:
322 {
323 struct v4l2_capability *v = arg;
324 memset(v,0,sizeof(*v));
325 strlcpy(v->driver, "dsbr100", sizeof (v->driver));
326 strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof (v->card));
327 sprintf(v->bus_info,"ISA");
328 v->version = RADIO_VERSION;
329 v->capabilities = V4L2_CAP_TUNER;
330
1da177e4
LT
331 return 0;
332 }
5aff308c
AC
333 case VIDIOC_G_TUNER:
334 {
335 struct v4l2_tuner *v = arg;
1da177e4 336
5aff308c 337 if (v->index > 0)
1da177e4 338 return -EINVAL;
5aff308c
AC
339
340 dsbr100_getstat(radio);
341
342 memset(v,0,sizeof(*v));
343 strcpy(v->name, "FM");
344 v->type = V4L2_TUNER_RADIO;
345
1da177e4
LT
346 v->rangelow = FREQ_MIN*FREQ_MUL;
347 v->rangehigh = FREQ_MAX*FREQ_MUL;
5aff308c
AC
348 v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
349 v->capability=V4L2_TUNER_CAP_LOW;
350 if(radio->stereo)
351 v->audmode = V4L2_TUNER_MODE_STEREO;
352 else
353 v->audmode = V4L2_TUNER_MODE_MONO;
354 v->signal = 0xFFFF; /* We can't get the signal strength */
1da177e4 355
1da177e4
LT
356 return 0;
357 }
5aff308c
AC
358 case VIDIOC_S_TUNER:
359 {
360 struct v4l2_tuner *v = arg;
1da177e4 361
5aff308c 362 if (v->index > 0)
1da177e4 363 return -EINVAL;
5aff308c 364
1da177e4
LT
365 return 0;
366 }
5aff308c
AC
367 case VIDIOC_S_FREQUENCY:
368 {
369 struct v4l2_frequency *f = arg;
1da177e4 370
5aff308c 371 radio->curfreq = f->frequency;
1da177e4
LT
372 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
373 warn("Set frequency failed");
374 return 0;
375 }
5aff308c
AC
376 case VIDIOC_G_FREQUENCY:
377 {
378 struct v4l2_frequency *f = arg;
379
380 f->type = V4L2_TUNER_RADIO;
381 f->frequency = radio->curfreq;
382
d56410e0 383 return 0;
1da177e4 384 }
5aff308c
AC
385 case VIDIOC_QUERYCTRL:
386 {
387 struct v4l2_queryctrl *qc = arg;
388 int i;
389
390 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
391 if (qc->id && qc->id == radio_qctrl[i].id) {
392 memcpy(qc, &(radio_qctrl[i]),
393 sizeof(*qc));
394 return 0;
395 }
1da177e4 396 }
5aff308c
AC
397 return -EINVAL;
398 }
399 case VIDIOC_G_CTRL:
400 {
401 struct v4l2_control *ctrl= arg;
402
403 switch (ctrl->id) {
404 case V4L2_CID_AUDIO_MUTE:
405 ctrl->value=radio->muted;
406 return 0;
407 }
408 return -EINVAL;
409 }
410 case VIDIOC_S_CTRL:
411 {
412 struct v4l2_control *ctrl= arg;
413
414 switch (ctrl->id) {
415 case V4L2_CID_AUDIO_MUTE:
416 if (ctrl->value) {
417 if (dsbr100_stop(radio)==-1)
418 warn("Radio did not respond properly");
419 } else {
420 if (dsbr100_start(radio)==-1)
421 warn("Radio did not respond properly");
422 }
423 return 0;
424 }
425 return -EINVAL;
1da177e4
LT
426 }
427 default:
5aff308c
AC
428 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
429 usb_dsbr100_do_ioctl);
1da177e4
LT
430 }
431}
432
433static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
434 unsigned int cmd, unsigned long arg)
435{
436 return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
437}
438
439static int usb_dsbr100_open(struct inode *inode, struct file *file)
440{
5aff308c 441 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
1da177e4
LT
442
443 radio->users = 1;
5aff308c
AC
444 radio->muted = 1;
445
1da177e4
LT
446 if (dsbr100_start(radio)<0) {
447 warn("Radio did not start up properly");
448 radio->users = 0;
449 return -EIO;
450 }
451 dsbr100_setfreq(radio, radio->curfreq);
452 return 0;
453}
454
455static int usb_dsbr100_close(struct inode *inode, struct file *file)
456{
5aff308c 457 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
1da177e4
LT
458
459 if (!radio)
460 return -ENODEV;
461 radio->users = 0;
462 if (radio->removed) {
463 kfree(radio);
464 }
465 return 0;
466}
467
468static int __init dsbr100_init(void)
469{
470 int retval = usb_register(&usb_dsbr100_driver);
471 info(DRIVER_VERSION ":" DRIVER_DESC);
472 return retval;
473}
474
475static void __exit dsbr100_exit(void)
476{
477 usb_deregister(&usb_dsbr100_driver);
478}
479
480module_init (dsbr100_init);
481module_exit (dsbr100_exit);
482
483MODULE_AUTHOR( DRIVER_AUTHOR );
484MODULE_DESCRIPTION( DRIVER_DESC );
485MODULE_LICENSE("GPL");
This page took 0.240542 seconds and 5 git commands to generate.