blob: 4e3f83e4e48f34f4f2878df5823c00f3f0729bc7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 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
Oliver Neukum863c86d2007-12-03 06:48:43 -030036 Version 0.43:
37 Oliver Neukum: avoided DMA coherency issue
38
Douglas Landgraf7002a4f2007-05-07 16:43:01 -030039 Version 0.42:
40 Converted dsbr100 to use video_ioctl2
41 by Douglas Landgraf <dougsland@gmail.com>
42
Alan Cox5aff3082006-08-08 15:47:50 -030043 Version 0.41-ac1:
44 Alan Cox: Some cleanups and fixes
45
46 Version 0.41:
47 Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 Version 0.40:
Alan Cox5aff3082006-08-08 15:47:50 -030050 Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52 Version 0.30:
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030053 Markus: Updates for 2.5.x kernel and more ISO compliant source
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55 Version 0.25:
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030056 PSL and Markus: Cleanup, radio now doesn't stop on device close
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58 Version 0.24:
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030059 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 right. Some minor cleanup, improved standalone compilation
61
62 Version 0.23:
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030063 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65 Version 0.22:
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030066 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 thanks to Mike Cox for pointing the problem out.
68
69 Version 0.21:
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030070 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 to adhere to Documentation/CodingStyle
72
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030073 Version 0.2:
74 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 Markus: Copyright clarification
76
77 Version 0.01: Markus: initial release
78
79*/
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#include <linux/kernel.h>
82#include <linux/module.h>
83#include <linux/init.h>
84#include <linux/slab.h>
85#include <linux/input.h>
Alan Cox5aff3082006-08-08 15:47:50 -030086#include <linux/videodev2.h>
Mauro Carvalho Chehab5e87efa2006-06-05 10:26:32 -030087#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/usb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90/*
91 * Version Information
92 */
Alan Cox5aff3082006-08-08 15:47:50 -030093#include <linux/version.h> /* for KERNEL_VERSION MACRO */
94
95#define DRIVER_VERSION "v0.41"
96#define RADIO_VERSION KERNEL_VERSION(0,4,1)
97
98static struct v4l2_queryctrl radio_qctrl[] = {
99 {
100 .id = V4L2_CID_AUDIO_MUTE,
101 .name = "Mute",
102 .minimum = 0,
103 .maximum = 1,
104 .default_value = 1,
105 .type = V4L2_CTRL_TYPE_BOOLEAN,
106 }
107};
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
110#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
111
112#define DSB100_VENDOR 0x04b4
113#define DSB100_PRODUCT 0x1002
114
115/* Commands the device appears to understand */
116#define DSB100_TUNE 1
117#define DSB100_ONOFF 2
118
119#define TB_LEN 16
120
121/* Frequency limits in MHz -- these are European values. For Japanese
122devices, that would be 76 and 91. */
123#define FREQ_MIN 87.5
124#define FREQ_MAX 108.0
125#define FREQ_MUL 16000
126
127
128static int usb_dsbr100_probe(struct usb_interface *intf,
129 const struct usb_device_id *id);
130static void usb_dsbr100_disconnect(struct usb_interface *intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131static int usb_dsbr100_open(struct inode *inode, struct file *file);
132static int usb_dsbr100_close(struct inode *inode, struct file *file);
133
134static int radio_nr = -1;
135module_param(radio_nr, int, 0);
136
137/* Data for one (physical) device */
Alan Cox5aff3082006-08-08 15:47:50 -0300138struct dsbr100_device {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 struct usb_device *usbdev;
140 struct video_device *videodev;
Oliver Neukum863c86d2007-12-03 06:48:43 -0300141 u8 *transfer_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 int curfreq;
143 int stereo;
144 int users;
145 int removed;
Alan Cox5aff3082006-08-08 15:47:50 -0300146 int muted;
147};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static struct usb_device_id usb_dsbr100_device_table [] = {
151 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
152 { } /* Terminating entry */
153};
154
155MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
156
157/* USB subsystem interface */
158static struct usb_driver usb_dsbr100_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 .name = "dsbr100",
160 .probe = usb_dsbr100_probe,
161 .disconnect = usb_dsbr100_disconnect,
162 .id_table = usb_dsbr100_device_table,
163};
164
165/* Low-level device interface begins here */
166
167/* switch on radio */
Alan Cox5aff3082006-08-08 15:47:50 -0300168static int dsbr100_start(struct dsbr100_device *radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
170 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300171 USB_REQ_GET_STATUS,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
173 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
174 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300175 DSB100_ONOFF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
177 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
178 return -1;
Alan Cox5aff3082006-08-08 15:47:50 -0300179 radio->muted=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 return (radio->transfer_buffer)[0];
181}
182
183
184/* switch off radio */
Alan Cox5aff3082006-08-08 15:47:50 -0300185static int dsbr100_stop(struct dsbr100_device *radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
187 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300188 USB_REQ_GET_STATUS,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
190 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
191 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300192 DSB100_ONOFF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
194 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
195 return -1;
Alan Cox5aff3082006-08-08 15:47:50 -0300196 radio->muted=1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 return (radio->transfer_buffer)[0];
198}
199
200/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
Alan Cox5aff3082006-08-08 15:47:50 -0300201static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 freq = (freq/16*80)/1000+856;
204 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300205 DSB100_TUNE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300207 (freq>>8)&0x00ff, freq&0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 radio->transfer_buffer, 8, 300)<0 ||
209 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300210 USB_REQ_GET_STATUS,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
212 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
213 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300214 USB_REQ_GET_STATUS,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
216 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
217 radio->stereo = -1;
218 return -1;
219 }
220 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
221 return (radio->transfer_buffer)[0];
222}
223
224/* return the device status. This is, in effect, just whether it
225sees a stereo signal or not. Pity. */
Alan Cox5aff3082006-08-08 15:47:50 -0300226static void dsbr100_getstat(struct dsbr100_device *radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300229 USB_REQ_GET_STATUS,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
231 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
232 radio->stereo = -1;
233 else
234 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
235}
236
237
238/* USB subsystem interface begins here */
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240/* handle unplugging of the device, release data structures
241if nothing keeps us from doing it. If something is still
242keeping us busy, the release callback of v4l will take care
Oliver Neukum863c86d2007-12-03 06:48:43 -0300243of releasing it. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244static void usb_dsbr100_disconnect(struct usb_interface *intf)
245{
Alan Cox5aff3082006-08-08 15:47:50 -0300246 struct dsbr100_device *radio = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 usb_set_intfdata (intf, NULL);
249 if (radio) {
250 video_unregister_device(radio->videodev);
251 radio->videodev = NULL;
252 if (radio->users) {
Oliver Neukum863c86d2007-12-03 06:48:43 -0300253 kfree(radio->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 kfree(radio);
255 } else {
256 radio->removed = 1;
257 }
258 }
259}
260
261
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300262static int vidioc_querycap(struct file *file, void *priv,
263 struct v4l2_capability *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300265 strlcpy(v->driver, "dsbr100", sizeof(v->driver));
266 strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
267 sprintf(v->bus_info, "ISA");
268 v->version = RADIO_VERSION;
269 v->capabilities = V4L2_CAP_TUNER;
270 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300273static int vidioc_g_tuner(struct file *file, void *priv,
274 struct v4l2_tuner *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300276 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
277
278 if (v->index > 0)
279 return -EINVAL;
280
281 dsbr100_getstat(radio);
282 strcpy(v->name, "FM");
283 v->type = V4L2_TUNER_RADIO;
284 v->rangelow = FREQ_MIN*FREQ_MUL;
285 v->rangehigh = FREQ_MAX*FREQ_MUL;
286 v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
287 v->capability = V4L2_TUNER_CAP_LOW;
288 if(radio->stereo)
289 v->audmode = V4L2_TUNER_MODE_STEREO;
290 else
291 v->audmode = V4L2_TUNER_MODE_MONO;
292 v->signal = 0xffff; /* We can't get the signal strength */
293 return 0;
294}
295
296static int vidioc_s_tuner(struct file *file, void *priv,
297 struct v4l2_tuner *v)
298{
299 if (v->index > 0)
300 return -EINVAL;
301
302 return 0;
303}
304
305static int vidioc_s_frequency(struct file *file, void *priv,
306 struct v4l2_frequency *f)
307{
308 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
309
310 radio->curfreq = f->frequency;
311 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
312 warn("Set frequency failed");
313 return 0;
314}
315
316static int vidioc_g_frequency(struct file *file, void *priv,
317 struct v4l2_frequency *f)
318{
319 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
320
321 f->type = V4L2_TUNER_RADIO;
322 f->frequency = radio->curfreq;
323 return 0;
324}
325
326static int vidioc_queryctrl(struct file *file, void *priv,
327 struct v4l2_queryctrl *qc)
328{
329 int i;
330
331 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
332 if (qc->id && qc->id == radio_qctrl[i].id) {
333 memcpy(qc, &(radio_qctrl[i]),
334 sizeof(*qc));
335 return 0;
336 }
337 }
338 return -EINVAL;
339}
340
341static int vidioc_g_ctrl(struct file *file, void *priv,
342 struct v4l2_control *ctrl)
343{
344 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
345
346 switch (ctrl->id) {
347 case V4L2_CID_AUDIO_MUTE:
348 ctrl->value = radio->muted;
349 return 0;
350 }
351 return -EINVAL;
352}
353
354static int vidioc_s_ctrl(struct file *file, void *priv,
355 struct v4l2_control *ctrl)
356{
357 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
358
359 switch (ctrl->id) {
360 case V4L2_CID_AUDIO_MUTE:
361 if (ctrl->value) {
362 if (dsbr100_stop(radio)==-1)
363 warn("Radio did not respond properly");
364 } else {
365 if (dsbr100_start(radio)==-1)
366 warn("Radio did not respond properly");
367 }
368 return 0;
369 }
370 return -EINVAL;
371}
372
373static int vidioc_g_audio(struct file *file, void *priv,
374 struct v4l2_audio *a)
375{
376 if (a->index > 1)
377 return -EINVAL;
378
379 strcpy(a->name, "Radio");
380 a->capability = V4L2_AUDCAP_STEREO;
381 return 0;
382}
383
384static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
385{
386 *i = 0;
387 return 0;
388}
389
390static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
391{
392 if (i != 0)
393 return -EINVAL;
394 return 0;
395}
396
397static int vidioc_s_audio(struct file *file, void *priv,
398 struct v4l2_audio *a)
399{
400 if (a->index != 0)
401 return -EINVAL;
402 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
405static int usb_dsbr100_open(struct inode *inode, struct file *file)
406{
Alan Cox5aff3082006-08-08 15:47:50 -0300407 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 radio->users = 1;
Alan Cox5aff3082006-08-08 15:47:50 -0300410 radio->muted = 1;
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (dsbr100_start(radio)<0) {
413 warn("Radio did not start up properly");
414 radio->users = 0;
415 return -EIO;
416 }
417 dsbr100_setfreq(radio, radio->curfreq);
418 return 0;
419}
420
421static int usb_dsbr100_close(struct inode *inode, struct file *file)
422{
Alan Cox5aff3082006-08-08 15:47:50 -0300423 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 if (!radio)
426 return -ENODEV;
427 radio->users = 0;
428 if (radio->removed) {
Oliver Neukum863c86d2007-12-03 06:48:43 -0300429 kfree(radio->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 kfree(radio);
431 }
432 return 0;
433}
434
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300435/* File system interface */
436static const struct file_operations usb_dsbr100_fops = {
437 .owner = THIS_MODULE,
438 .open = usb_dsbr100_open,
439 .release = usb_dsbr100_close,
440 .ioctl = video_ioctl2,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300441#ifdef CONFIG_COMPAT
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300442 .compat_ioctl = v4l_compat_ioctl32,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300443#endif
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300444 .llseek = no_llseek,
445};
446
447/* V4L2 interface */
448static struct video_device dsbr100_videodev_template =
449{
450 .owner = THIS_MODULE,
451 .name = "D-Link DSB-R 100",
452 .type = VID_TYPE_TUNER,
453 .fops = &usb_dsbr100_fops,
454 .release = video_device_release,
455 .vidioc_querycap = vidioc_querycap,
456 .vidioc_g_tuner = vidioc_g_tuner,
457 .vidioc_s_tuner = vidioc_s_tuner,
458 .vidioc_g_frequency = vidioc_g_frequency,
459 .vidioc_s_frequency = vidioc_s_frequency,
460 .vidioc_queryctrl = vidioc_queryctrl,
461 .vidioc_g_ctrl = vidioc_g_ctrl,
462 .vidioc_s_ctrl = vidioc_s_ctrl,
463 .vidioc_g_audio = vidioc_g_audio,
464 .vidioc_s_audio = vidioc_s_audio,
465 .vidioc_g_input = vidioc_g_input,
466 .vidioc_s_input = vidioc_s_input,
467};
468
469/* check if the device is present and register with v4l and
470usb if it is */
471static int usb_dsbr100_probe(struct usb_interface *intf,
472 const struct usb_device_id *id)
473{
474 struct dsbr100_device *radio;
475
476 if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
477 return -ENOMEM;
Oliver Neukum863c86d2007-12-03 06:48:43 -0300478 if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
479 kfree(radio);
480 return -ENOMEM;
481 }
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300482 if (!(radio->videodev = video_device_alloc())) {
Oliver Neukum863c86d2007-12-03 06:48:43 -0300483 kfree(radio->transfer_buffer);
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300484 kfree(radio);
485 return -ENOMEM;
486 }
487 memcpy(radio->videodev, &dsbr100_videodev_template,
488 sizeof(dsbr100_videodev_template));
489 radio->removed = 0;
490 radio->users = 0;
491 radio->usbdev = interface_to_usbdev(intf);
492 radio->curfreq = FREQ_MIN*FREQ_MUL;
493 video_set_drvdata(radio->videodev, radio);
494 if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
495 warn("Could not register video device");
496 video_device_release(radio->videodev);
Oliver Neukum863c86d2007-12-03 06:48:43 -0300497 kfree(radio->transfer_buffer);
Douglas Landgraf7002a4f2007-05-07 16:43:01 -0300498 kfree(radio);
499 return -EIO;
500 }
501 usb_set_intfdata(intf, radio);
502 return 0;
503}
504
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505static int __init dsbr100_init(void)
506{
507 int retval = usb_register(&usb_dsbr100_driver);
508 info(DRIVER_VERSION ":" DRIVER_DESC);
509 return retval;
510}
511
512static void __exit dsbr100_exit(void)
513{
514 usb_deregister(&usb_dsbr100_driver);
515}
516
517module_init (dsbr100_init);
518module_exit (dsbr100_exit);
519
520MODULE_AUTHOR( DRIVER_AUTHOR );
521MODULE_DESCRIPTION( DRIVER_DESC );
522MODULE_LICENSE("GPL");