Blame view

drivers/media/radio/dsbr100.c 16.2 KB
fc55bcb0a   Alexey Klimov   V4L/DVB (10060): ...
1
2
  /* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
   The device plugs into both the USB and an analog audio input, so this thing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   only deals with initialisation and frequency setting, the
   audio data has to be handled by a sound driver.
  
   Major issue: I can't find out where the device reports the signal
   strength, and indeed the windows software appearantly just looks
   at the stereo indicator as well.  So, scanning will only find
   stereo stations.  Sad, but I can't help it.
  
   Also, the windows program sends oodles of messages over to the
   device, and I couldn't figure out their meaning.  My suspicion
   is that they don't have any:-)
  
   You might find some interesting stuff about this module at
   http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
  
   Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
  
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  
   History:
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
35
36
37
   Version 0.46:
  	Removed usb_dsbr100_open/close calls and radio->users counter. Also,
  	radio->muted changed to radio->status and suspend/resume calls updated.
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
38
39
   Version 0.45:
  	Converted to v4l2_device.
6076dbf46   Alexey Klimov   V4L/DVB (10061): ...
40
41
42
   Version 0.44:
  	Add suspend/resume functions, fix unplug of device,
  	a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
863c86dd7   Oliver Neukum   V4L/DVB (6732): d...
43
44
   Version 0.43:
  	Oliver Neukum: avoided DMA coherency issue
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
45
46
47
   Version 0.42:
  	Converted dsbr100 to use video_ioctl2
  	by Douglas Landgraf <dougsland@gmail.com>
5aff308c5   Alan Cox   V4L/DVB (4410): C...
48
49
50
51
52
   Version 0.41-ac1:
  	Alan Cox: Some cleanups and fixes
  
   Version 0.41:
  	Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
   Version 0.40:
5aff308c5   Alan Cox   V4L/DVB (4410): C...
54
  	Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  
   Version 0.30:
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
57
  	Markus: Updates for 2.5.x kernel and more ISO compliant source
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  
   Version 0.25:
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
60
  	PSL and Markus: Cleanup, radio now doesn't stop on device close
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
   Version 0.24:
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
63
  	Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
  	right.  Some minor cleanup, improved standalone compilation
  
   Version 0.23:
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
67
  	Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  
   Version 0.22:
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
70
  	Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  	thanks to Mike Cox for pointing the problem out.
  
   Version 0.21:
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
74
  	Markus: Minor cleanup, warnings if something goes wrong, lame attempt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	to adhere to Documentation/CodingStyle
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
76
77
   Version 0.2:
  	Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
  	Markus: Copyright clarification
  
   Version 0.01: Markus: initial release
  
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/input.h>
5aff308c5   Alan Cox   V4L/DVB (4410): C...
88
  #include <linux/videodev2.h>
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
89
  #include <media/v4l2-device.h>
35ea11ff8   Hans Verkuil   V4L/DVB (8430): v...
90
  #include <media/v4l2-ioctl.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  #include <linux/usb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
  
  /*
   * Version Information
   */
29834c1ac   Mauro Carvalho Chehab   [media] radio: Us...
96
  #define DRIVER_VERSION "0.4.7"
5aff308c5   Alan Cox   V4L/DVB (4410): C...
97

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
  #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
  
  #define DSB100_VENDOR 0x04b4
  #define DSB100_PRODUCT 0x1002
  
  /* Commands the device appears to understand */
  #define DSB100_TUNE 1
  #define DSB100_ONOFF 2
  
  #define TB_LEN 16
  
  /* Frequency limits in MHz -- these are European values.  For Japanese
  devices, that would be 76 and 91.  */
  #define FREQ_MIN  87.5
  #define FREQ_MAX 108.0
  #define FREQ_MUL 16000
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
115
116
117
  /* defines for radio->status */
  #define STARTED	0
  #define STOPPED	1
130992949   Hans Verkuil   [media] dsbr100: ...
118
  #define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
  
  static int usb_dsbr100_probe(struct usb_interface *intf,
  			     const struct usb_device_id *id);
  static void usb_dsbr100_disconnect(struct usb_interface *intf);
04e0ffbbd   Alexey Klimov   V4L/DVB (9539): d...
123
124
125
  static int usb_dsbr100_suspend(struct usb_interface *intf,
  						pm_message_t message);
  static int usb_dsbr100_resume(struct usb_interface *intf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
  
  static int radio_nr = -1;
  module_param(radio_nr, int, 0);
  
  /* Data for one (physical) device */
5aff308c5   Alan Cox   V4L/DVB (4410): C...
131
  struct dsbr100_device {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  	struct usb_device *usbdev;
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
133
  	struct video_device videodev;
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
134
  	struct v4l2_device v4l2_dev;
863c86dd7   Oliver Neukum   V4L/DVB (6732): d...
135
  	u8 *transfer_buffer;
e64d07c92   Hans Verkuil   [media] dsbr100: ...
136
  	struct mutex v4l2_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  	int curfreq;
  	int stereo;
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
139
  	int status;
5aff308c5   Alan Cox   V4L/DVB (4410): C...
140
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
148
149
150
  static struct usb_device_id usb_dsbr100_device_table [] = {
  	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
  	{ }						/* Terminating entry */
  };
  
  MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
  
  /* USB subsystem interface */
  static struct usb_driver usb_dsbr100_driver = {
04e0ffbbd   Alexey Klimov   V4L/DVB (9539): d...
151
152
153
154
155
156
157
158
  	.name			= "dsbr100",
  	.probe			= usb_dsbr100_probe,
  	.disconnect		= usb_dsbr100_disconnect,
  	.id_table		= usb_dsbr100_device_table,
  	.suspend		= usb_dsbr100_suspend,
  	.resume			= usb_dsbr100_resume,
  	.reset_resume		= usb_dsbr100_resume,
  	.supports_autosuspend	= 0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
163
  };
  
  /* Low-level device interface begins here */
  
  /* switch on radio */
5aff308c5   Alan Cox   V4L/DVB (4410): C...
164
  static int dsbr100_start(struct dsbr100_device *radio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  {
417b79536   Alexey Klimov   V4L/DVB (10058): ...
166
167
  	int retval;
  	int request;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
168
169
170
171
172
173
174
175
176
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		USB_REQ_GET_STATUS,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  		0x00, 0xC7, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = USB_REQ_GET_STATUS;
  		goto usb_control_msg_failed;
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
177
  	}
417b79536   Alexey Klimov   V4L/DVB (10058): ...
178
179
180
181
182
183
184
185
186
187
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		DSB100_ONOFF,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  		0x01, 0x00, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = DSB100_ONOFF;
  		goto usb_control_msg_failed;
  	}
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
188
  	radio->status = STARTED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	return (radio->transfer_buffer)[0];
417b79536   Alexey Klimov   V4L/DVB (10058): ...
190
191
  
  usb_control_msg_failed:
417b79536   Alexey Klimov   V4L/DVB (10058): ...
192
193
194
195
  	dev_err(&radio->usbdev->dev,
  		"%s - usb_control_msg returned %i, request %i
  ",
  			__func__, retval, request);
d25cb6461   Alexey Klimov   V4L/DVB (10062): ...
196
  	return retval;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
197

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  /* switch off radio */
5aff308c5   Alan Cox   V4L/DVB (4410): C...
200
  static int dsbr100_stop(struct dsbr100_device *radio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  {
417b79536   Alexey Klimov   V4L/DVB (10058): ...
202
203
  	int retval;
  	int request;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		USB_REQ_GET_STATUS,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  		0x16, 0x1C, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = USB_REQ_GET_STATUS;
  		goto usb_control_msg_failed;
  	}
  
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		DSB100_ONOFF,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  		0x00, 0x00, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = DSB100_ONOFF;
  		goto usb_control_msg_failed;
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
224
  	}
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
225
  	radio->status = STOPPED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  	return (radio->transfer_buffer)[0];
417b79536   Alexey Klimov   V4L/DVB (10058): ...
227
228
  
  usb_control_msg_failed:
417b79536   Alexey Klimov   V4L/DVB (10058): ...
229
230
231
232
  	dev_err(&radio->usbdev->dev,
  		"%s - usb_control_msg returned %i, request %i
  ",
  			__func__, retval, request);
d25cb6461   Alexey Klimov   V4L/DVB (10062): ...
233
  	return retval;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
234

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  }
  
  /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
917fab4f3   Alexey Klimov   V4L/DVB (11956): ...
238
  static int dsbr100_setfreq(struct dsbr100_device *radio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  {
417b79536   Alexey Klimov   V4L/DVB (10058): ...
240
241
  	int retval;
  	int request;
917fab4f3   Alexey Klimov   V4L/DVB (11956): ...
242
  	int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
243

417b79536   Alexey Klimov   V4L/DVB (10058): ...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		DSB100_TUNE,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  		(freq >> 8) & 0x00ff, freq & 0xff,
  		radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = DSB100_TUNE;
  		goto usb_control_msg_failed;
  	}
  
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		USB_REQ_GET_STATUS,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  		0x96, 0xB7, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = USB_REQ_GET_STATUS;
  		goto usb_control_msg_failed;
  	}
  
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
  		USB_REQ_GET_STATUS,
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
  		0x00, 0x24, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
  		request = USB_REQ_GET_STATUS;
  		goto usb_control_msg_failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	}
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
277

223377e76   Alexey Klimov   V4L/DVB (9304): d...
278
  	radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	return (radio->transfer_buffer)[0];
417b79536   Alexey Klimov   V4L/DVB (10058): ...
280
281
282
  
  usb_control_msg_failed:
  	radio->stereo = -1;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
283
284
285
286
  	dev_err(&radio->usbdev->dev,
  		"%s - usb_control_msg returned %i, request %i
  ",
  			__func__, retval, request);
d25cb6461   Alexey Klimov   V4L/DVB (10062): ...
287
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
  }
  
  /* return the device status.  This is, in effect, just whether it
  sees a stereo signal or not.  Pity. */
5aff308c5   Alan Cox   V4L/DVB (4410): C...
292
  static void dsbr100_getstat(struct dsbr100_device *radio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  {
417b79536   Alexey Klimov   V4L/DVB (10058): ...
294
  	int retval;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
295
296
  	retval = usb_control_msg(radio->usbdev,
  		usb_rcvctrlpipe(radio->usbdev, 0),
d56410e0a   Mauro Carvalho Chehab   V4L/DVB (3599b): ...
297
  		USB_REQ_GET_STATUS,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
417b79536   Alexey Klimov   V4L/DVB (10058): ...
299
300
301
  		0x00 , 0x24, radio->transfer_buffer, 8, 300);
  
  	if (retval < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  		radio->stereo = -1;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
303
304
305
306
307
  		dev_err(&radio->usbdev->dev,
  			"%s - usb_control_msg returned %i, request %i
  ",
  				__func__, retval, USB_REQ_GET_STATUS);
  	} else {
223377e76   Alexey Klimov   V4L/DVB (9304): d...
308
  		radio->stereo = !(radio->transfer_buffer[0] & 0x01);
417b79536   Alexey Klimov   V4L/DVB (10058): ...
309
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  }
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
311
312
313
  static int vidioc_querycap(struct file *file, void *priv,
  					struct v4l2_capability *v)
  {
c7181cfa6   Alexey Klimov   V4L/DVB (10316): ...
314
  	struct dsbr100_device *radio = video_drvdata(file);
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
315
316
  	strlcpy(v->driver, "dsbr100", sizeof(v->driver));
  	strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
c7181cfa6   Alexey Klimov   V4L/DVB (10316): ...
317
  	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
318
319
320
  	v->capabilities = V4L2_CAP_TUNER;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
322
323
  static int vidioc_g_tuner(struct file *file, void *priv,
  				struct v4l2_tuner *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  {
c170ecf43   Hans Verkuil   V4L/DVB (8788): v...
325
  	struct dsbr100_device *radio = video_drvdata(file);
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
326
327
328
329
330
331
332
  
  	if (v->index > 0)
  		return -EINVAL;
  
  	dsbr100_getstat(radio);
  	strcpy(v->name, "FM");
  	v->type = V4L2_TUNER_RADIO;
223377e76   Alexey Klimov   V4L/DVB (9304): d...
333
334
335
  	v->rangelow = FREQ_MIN * FREQ_MUL;
  	v->rangehigh = FREQ_MAX * FREQ_MUL;
  	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
336
337
338
339
340
341
342
343
  	v->capability = V4L2_TUNER_CAP_LOW;
  	if(radio->stereo)
  		v->audmode = V4L2_TUNER_MODE_STEREO;
  	else
  		v->audmode = V4L2_TUNER_MODE_MONO;
  	v->signal = 0xffff;     /* We can't get the signal strength */
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
345
346
347
  static int vidioc_s_tuner(struct file *file, void *priv,
  				struct v4l2_tuner *v)
  {
130992949   Hans Verkuil   [media] dsbr100: ...
348
  	return v->index ? -EINVAL : 0;
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
349
  }
5aff308c5   Alan Cox   V4L/DVB (4410): C...
350

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
351
352
353
  static int vidioc_s_frequency(struct file *file, void *priv,
  				struct v4l2_frequency *f)
  {
c170ecf43   Hans Verkuil   V4L/DVB (8788): v...
354
  	struct dsbr100_device *radio = video_drvdata(file);
417b79536   Alexey Klimov   V4L/DVB (10058): ...
355
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
357
  	radio->curfreq = f->frequency;
fdf9c9979   Alexey Klimov   V4L/DVB (10465): ...
358

917fab4f3   Alexey Klimov   V4L/DVB (11956): ...
359
  	retval = dsbr100_setfreq(radio);
d25cb6461   Alexey Klimov   V4L/DVB (10062): ...
360
  	if (retval < 0)
aa82661ba   Greg Kroah-Hartman   USB: remove warn(...
361
362
  		dev_warn(&radio->usbdev->dev, "Set frequency failed
  ");
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
363
364
  	return 0;
  }
5aff308c5   Alan Cox   V4L/DVB (4410): C...
365

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
366
367
368
  static int vidioc_g_frequency(struct file *file, void *priv,
  				struct v4l2_frequency *f)
  {
c170ecf43   Hans Verkuil   V4L/DVB (8788): v...
369
  	struct dsbr100_device *radio = video_drvdata(file);
5aff308c5   Alan Cox   V4L/DVB (4410): C...
370

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
371
372
373
374
  	f->type = V4L2_TUNER_RADIO;
  	f->frequency = radio->curfreq;
  	return 0;
  }
5aff308c5   Alan Cox   V4L/DVB (4410): C...
375

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
376
377
378
  static int vidioc_queryctrl(struct file *file, void *priv,
  				struct v4l2_queryctrl *qc)
  {
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
379
380
381
  	switch (qc->id) {
  	case V4L2_CID_AUDIO_MUTE:
  		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
382
  	}
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
383

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
384
385
  	return -EINVAL;
  }
5aff308c5   Alan Cox   V4L/DVB (4410): C...
386

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
387
388
389
  static int vidioc_g_ctrl(struct file *file, void *priv,
  				struct v4l2_control *ctrl)
  {
c170ecf43   Hans Verkuil   V4L/DVB (8788): v...
390
  	struct dsbr100_device *radio = video_drvdata(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
392
393
  	switch (ctrl->id) {
  	case V4L2_CID_AUDIO_MUTE:
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
394
  		ctrl->value = radio->status;
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
395
396
397
398
  		return 0;
  	}
  	return -EINVAL;
  }
5aff308c5   Alan Cox   V4L/DVB (4410): C...
399

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
400
401
402
  static int vidioc_s_ctrl(struct file *file, void *priv,
  				struct v4l2_control *ctrl)
  {
c170ecf43   Hans Verkuil   V4L/DVB (8788): v...
403
  	struct dsbr100_device *radio = video_drvdata(file);
417b79536   Alexey Klimov   V4L/DVB (10058): ...
404
  	int retval;
5aff308c5   Alan Cox   V4L/DVB (4410): C...
405

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
406
407
408
  	switch (ctrl->id) {
  	case V4L2_CID_AUDIO_MUTE:
  		if (ctrl->value) {
417b79536   Alexey Klimov   V4L/DVB (10058): ...
409
  			retval = dsbr100_stop(radio);
d25cb6461   Alexey Klimov   V4L/DVB (10062): ...
410
  			if (retval < 0) {
aa82661ba   Greg Kroah-Hartman   USB: remove warn(...
411
412
413
  				dev_warn(&radio->usbdev->dev,
  					 "Radio did not respond properly
  ");
90b698dd4   Alexey Klimov   V4L/DVB (9151): d...
414
415
  				return -EBUSY;
  			}
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
416
  		} else {
417b79536   Alexey Klimov   V4L/DVB (10058): ...
417
  			retval = dsbr100_start(radio);
d25cb6461   Alexey Klimov   V4L/DVB (10062): ...
418
  			if (retval < 0) {
aa82661ba   Greg Kroah-Hartman   USB: remove warn(...
419
420
421
  				dev_warn(&radio->usbdev->dev,
  					 "Radio did not respond properly
  ");
90b698dd4   Alexey Klimov   V4L/DVB (9151): d...
422
423
  				return -EBUSY;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  		}
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
425
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  	}
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
427
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  }
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
429
430
  static int vidioc_g_audio(struct file *file, void *priv,
  				struct v4l2_audio *a)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  {
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  	if (a->index > 1)
  		return -EINVAL;
  
  	strcpy(a->name, "Radio");
  	a->capability = V4L2_AUDCAP_STEREO;
  	return 0;
  }
  
  static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
  {
  	*i = 0;
  	return 0;
  }
  
  static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
  {
130992949   Hans Verkuil   [media] dsbr100: ...
448
  	return i ? -EINVAL : 0;
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
449
450
451
452
453
  }
  
  static int vidioc_s_audio(struct file *file, void *priv,
  					struct v4l2_audio *a)
  {
130992949   Hans Verkuil   [media] dsbr100: ...
454
  	return a->index ? -EINVAL : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  }
e64d07c92   Hans Verkuil   [media] dsbr100: ...
456
457
458
459
460
461
462
463
464
465
466
  /* USB subsystem interface begins here */
  
  /*
   * Handle unplugging of the device.
   * We call video_unregister_device in any case.
   * The last function called in this procedure is
   * usb_dsbr100_video_device_release
   */
  static void usb_dsbr100_disconnect(struct usb_interface *intf)
  {
  	struct dsbr100_device *radio = usb_get_intfdata(intf);
130992949   Hans Verkuil   [media] dsbr100: ...
467
  	v4l2_device_get(&radio->v4l2_dev);
e64d07c92   Hans Verkuil   [media] dsbr100: ...
468
  	mutex_lock(&radio->v4l2_lock);
130992949   Hans Verkuil   [media] dsbr100: ...
469
  	usb_set_intfdata(intf, NULL);
e64d07c92   Hans Verkuil   [media] dsbr100: ...
470
471
  	video_unregister_device(&radio->videodev);
  	v4l2_device_disconnect(&radio->v4l2_dev);
130992949   Hans Verkuil   [media] dsbr100: ...
472
473
  	mutex_unlock(&radio->v4l2_lock);
  	v4l2_device_put(&radio->v4l2_dev);
e64d07c92   Hans Verkuil   [media] dsbr100: ...
474
  }
04e0ffbbd   Alexey Klimov   V4L/DVB (9539): d...
475
476
477
478
479
  /* Suspend device - stop device. */
  static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
  {
  	struct dsbr100_device *radio = usb_get_intfdata(intf);
  	int retval;
e64d07c92   Hans Verkuil   [media] dsbr100: ...
480
  	mutex_lock(&radio->v4l2_lock);
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
481
482
483
484
485
486
487
488
489
490
491
  	if (radio->status == STARTED) {
  		retval = dsbr100_stop(radio);
  		if (retval < 0)
  			dev_warn(&intf->dev, "dsbr100_stop failed
  ");
  
  		/* After dsbr100_stop() status set to STOPPED.
  		 * If we want driver to start radio on resume
  		 * we set status equal to STARTED.
  		 * On resume we will check status and run radio if needed.
  		 */
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
492
  		radio->status = STARTED;
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
493
  	}
e64d07c92   Hans Verkuil   [media] dsbr100: ...
494
  	mutex_unlock(&radio->v4l2_lock);
04e0ffbbd   Alexey Klimov   V4L/DVB (9539): d...
495
496
497
498
499
500
501
502
503
504
505
506
  
  	dev_info(&intf->dev, "going into suspend..
  ");
  
  	return 0;
  }
  
  /* Resume device - start device. */
  static int usb_dsbr100_resume(struct usb_interface *intf)
  {
  	struct dsbr100_device *radio = usb_get_intfdata(intf);
  	int retval;
e64d07c92   Hans Verkuil   [media] dsbr100: ...
507
  	mutex_lock(&radio->v4l2_lock);
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
508
509
510
511
512
513
  	if (radio->status == STARTED) {
  		retval = dsbr100_start(radio);
  		if (retval < 0)
  			dev_warn(&intf->dev, "dsbr100_start failed
  ");
  	}
e64d07c92   Hans Verkuil   [media] dsbr100: ...
514
  	mutex_unlock(&radio->v4l2_lock);
04e0ffbbd   Alexey Klimov   V4L/DVB (9539): d...
515
516
517
518
519
520
  
  	dev_info(&intf->dev, "coming out of suspend..
  ");
  
  	return 0;
  }
fc55bcb0a   Alexey Klimov   V4L/DVB (10060): ...
521
  /* free data structures */
130992949   Hans Verkuil   [media] dsbr100: ...
522
  static void usb_dsbr100_release(struct v4l2_device *v4l2_dev)
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
523
  {
130992949   Hans Verkuil   [media] dsbr100: ...
524
  	struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
525

406827ccc   Alexey Klimov   V4L/DVB (11435): ...
526
  	v4l2_device_unregister(&radio->v4l2_dev);
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
527
528
529
  	kfree(radio->transfer_buffer);
  	kfree(radio);
  }
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
530
  /* File system interface */
bec43661b   Hans Verkuil   V4L/DVB (10135): ...
531
  static const struct v4l2_file_operations usb_dsbr100_fops = {
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
532
  	.owner		= THIS_MODULE,
e64d07c92   Hans Verkuil   [media] dsbr100: ...
533
  	.unlocked_ioctl	= video_ioctl2,
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
534
  };
a399810ca   Hans Verkuil   V4L/DVB (8482): v...
535
  static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
536
537
538
539
540
541
542
543
544
545
546
547
548
  	.vidioc_querycap    = vidioc_querycap,
  	.vidioc_g_tuner     = vidioc_g_tuner,
  	.vidioc_s_tuner     = vidioc_s_tuner,
  	.vidioc_g_frequency = vidioc_g_frequency,
  	.vidioc_s_frequency = vidioc_s_frequency,
  	.vidioc_queryctrl   = vidioc_queryctrl,
  	.vidioc_g_ctrl      = vidioc_g_ctrl,
  	.vidioc_s_ctrl      = vidioc_s_ctrl,
  	.vidioc_g_audio     = vidioc_g_audio,
  	.vidioc_s_audio     = vidioc_s_audio,
  	.vidioc_g_input     = vidioc_g_input,
  	.vidioc_s_input     = vidioc_s_input,
  };
fc55bcb0a   Alexey Klimov   V4L/DVB (10060): ...
549
  /* check if the device is present and register with v4l and usb if it is */
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
550
551
552
553
  static int usb_dsbr100_probe(struct usb_interface *intf,
  				const struct usb_device_id *id)
  {
  	struct dsbr100_device *radio;
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
554
  	struct v4l2_device *v4l2_dev;
417b79536   Alexey Klimov   V4L/DVB (10058): ...
555
  	int retval;
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
556

406827ccc   Alexey Klimov   V4L/DVB (11435): ...
557
  	radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
223377e76   Alexey Klimov   V4L/DVB (9304): d...
558
559
  
  	if (!radio)
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
560
  		return -ENOMEM;
223377e76   Alexey Klimov   V4L/DVB (9304): d...
561
562
563
564
  
  	radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL);
  
  	if (!(radio->transfer_buffer)) {
863c86dd7   Oliver Neukum   V4L/DVB (6732): d...
565
566
567
  		kfree(radio);
  		return -ENOMEM;
  	}
223377e76   Alexey Klimov   V4L/DVB (9304): d...
568

406827ccc   Alexey Klimov   V4L/DVB (11435): ...
569
  	v4l2_dev = &radio->v4l2_dev;
130992949   Hans Verkuil   [media] dsbr100: ...
570
  	v4l2_dev->release = usb_dsbr100_release;
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
571
572
573
574
575
576
577
578
579
  
  	retval = v4l2_device_register(&intf->dev, v4l2_dev);
  	if (retval < 0) {
  		v4l2_err(v4l2_dev, "couldn't register v4l2_device
  ");
  		kfree(radio->transfer_buffer);
  		kfree(radio);
  		return retval;
  	}
e64d07c92   Hans Verkuil   [media] dsbr100: ...
580
  	mutex_init(&radio->v4l2_lock);
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
581
582
583
584
  	strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
  	radio->videodev.v4l2_dev = v4l2_dev;
  	radio->videodev.fops = &usb_dsbr100_fops;
  	radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
130992949   Hans Verkuil   [media] dsbr100: ...
585
  	radio->videodev.release = video_device_release_empty;
e64d07c92   Hans Verkuil   [media] dsbr100: ...
586
  	radio->videodev.lock = &radio->v4l2_lock;
3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
587

7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
588
  	radio->usbdev = interface_to_usbdev(intf);
223377e76   Alexey Klimov   V4L/DVB (9304): d...
589
  	radio->curfreq = FREQ_MIN * FREQ_MUL;
f1ca0adfc   Alexey Klimov   V4L/DVB (11957): ...
590
  	radio->status = STOPPED;
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
591

3a0efc320   Alexey Klimov   V4L/DVB (10054): ...
592
  	video_set_drvdata(&radio->videodev, radio);
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
593

417b79536   Alexey Klimov   V4L/DVB (10058): ...
594
595
  	retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
  	if (retval < 0) {
406827ccc   Alexey Klimov   V4L/DVB (11435): ...
596
597
598
  		v4l2_err(v4l2_dev, "couldn't register video device
  ");
  		v4l2_device_unregister(v4l2_dev);
863c86dd7   Oliver Neukum   V4L/DVB (6732): d...
599
  		kfree(radio->transfer_buffer);
7002a4f35   Douglas Landgraf   V4L/DVB (5623): D...
600
601
602
603
604
605
  		kfree(radio);
  		return -EIO;
  	}
  	usb_set_intfdata(intf, radio);
  	return 0;
  }
ecb3b2b35   Greg Kroah-Hartman   USB: convert driv...
606
  module_usb_driver(usb_dsbr100_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
  
  MODULE_AUTHOR( DRIVER_AUTHOR );
  MODULE_DESCRIPTION( DRIVER_DESC );
  MODULE_LICENSE("GPL");
29834c1ac   Mauro Carvalho Chehab   [media] radio: Us...
611
  MODULE_VERSION(DRIVER_VERSION);