diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:50:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:50:49 -0500 |
commit | 3e7468313758913c5e4d372f35b271b96bad1298 (patch) | |
tree | eb612d252a9e2349a1173451cd779beebd18a33e /drivers/media/radio/radio-mr800.c | |
parent | 6825fbc4cb219f2c98bb7d157915d797cf5cb823 (diff) | |
parent | e97f4677961f68e29bd906022ebf60a6df7f530a (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (345 commits)
V4L/DVB (13542): ir-keytable: Allow dynamic table change
V4L/DVB (13541): atbm8830: replace 64-bit division and floating point usage
V4L/DVB (13540): ir-common: Cleanup get key evdev code
V4L/DVB (13539): ir-common: add __func__ for debug messages
V4L/DVB (13538): ir-common: Use a dynamic keycode table
V4L/DVB (13537): ir: Prepare the code for dynamic keycode table allocation
V4L/DVB (13536): em28xx: Use the full RC5 code on HVR-950 Remote Controller
V4L/DVB (13535): ir-common: Add a hauppauge new table with the complete RC5 code
V4L/DVB (13534): ir-common: Remove some unused fields/structs
V4L/DVB (13533): ir: use dynamic tables, instead of static ones
V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table
V4L/DVB (13531): ir-common: rename the debug routine to allow exporting it
V4L/DVB (13458): go7007: subdev conversion
V4L/DVB (13457): s2250: subdev conversion
V4L/DVB (13456): s2250: Change module structure
V4L/DVB (13528): em28xx: add support for em2800 VC211A card
em28xx: don't reduce scale to half size for em2800
em28xx: don't load audio modules when AC97 is mis-detected
em28xx: em2800 chips support max width of 640
V4L/DVB (13523): dvb-bt8xx: fix compile warning
...
Fix up trivial conflicts due to spelling fixes from the trivial tree in
Documentation/video4linux/gspca.txt
drivers/media/video/cx18/cx18-mailbox.h
Diffstat (limited to 'drivers/media/radio/radio-mr800.c')
-rw-r--r-- | drivers/media/radio/radio-mr800.c | 358 |
1 files changed, 167 insertions, 191 deletions
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 5f79acb56e48..949f60513d9e 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c | |||
@@ -85,6 +85,9 @@ MODULE_LICENSE("GPL"); | |||
85 | #define amradio_dev_warn(dev, fmt, arg...) \ | 85 | #define amradio_dev_warn(dev, fmt, arg...) \ |
86 | dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) | 86 | dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) |
87 | 87 | ||
88 | #define amradio_dev_err(dev, fmt, arg...) \ | ||
89 | dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg) | ||
90 | |||
88 | /* Probably USB_TIMEOUT should be modified in module parameter */ | 91 | /* Probably USB_TIMEOUT should be modified in module parameter */ |
89 | #define BUFFER_LENGTH 8 | 92 | #define BUFFER_LENGTH 8 |
90 | #define USB_TIMEOUT 500 | 93 | #define USB_TIMEOUT 500 |
@@ -129,18 +132,20 @@ static int usb_amradio_resume(struct usb_interface *intf); | |||
129 | struct amradio_device { | 132 | struct amradio_device { |
130 | /* reference to USB and video device */ | 133 | /* reference to USB and video device */ |
131 | struct usb_device *usbdev; | 134 | struct usb_device *usbdev; |
132 | struct video_device *videodev; | 135 | struct usb_interface *intf; |
136 | struct video_device videodev; | ||
133 | struct v4l2_device v4l2_dev; | 137 | struct v4l2_device v4l2_dev; |
134 | 138 | ||
135 | unsigned char *buffer; | 139 | unsigned char *buffer; |
136 | struct mutex lock; /* buffer locking */ | 140 | struct mutex lock; /* buffer locking */ |
137 | int curfreq; | 141 | int curfreq; |
138 | int stereo; | 142 | int stereo; |
139 | int users; | ||
140 | int removed; | ||
141 | int muted; | 143 | int muted; |
144 | int initialized; | ||
142 | }; | 145 | }; |
143 | 146 | ||
147 | #define vdev_to_amradio(r) container_of(r, struct amradio_device, videodev) | ||
148 | |||
144 | /* USB Device ID List */ | 149 | /* USB Device ID List */ |
145 | static struct usb_device_id usb_amradio_device_table[] = { | 150 | static struct usb_device_id usb_amradio_device_table[] = { |
146 | {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, | 151 | {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, |
@@ -159,7 +164,7 @@ static struct usb_driver usb_amradio_driver = { | |||
159 | .resume = usb_amradio_resume, | 164 | .resume = usb_amradio_resume, |
160 | .reset_resume = usb_amradio_resume, | 165 | .reset_resume = usb_amradio_resume, |
161 | .id_table = usb_amradio_device_table, | 166 | .id_table = usb_amradio_device_table, |
162 | .supports_autosuspend = 0, | 167 | .supports_autosuspend = 1, |
163 | }; | 168 | }; |
164 | 169 | ||
165 | /* switch on/off the radio. Send 8 bytes to device */ | 170 | /* switch on/off the radio. Send 8 bytes to device */ |
@@ -168,11 +173,7 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) | |||
168 | int retval; | 173 | int retval; |
169 | int size; | 174 | int size; |
170 | 175 | ||
171 | /* safety check */ | 176 | BUG_ON(!mutex_is_locked(&radio->lock)); |
172 | if (radio->removed) | ||
173 | return -EIO; | ||
174 | |||
175 | mutex_lock(&radio->lock); | ||
176 | 177 | ||
177 | radio->buffer[0] = 0x00; | 178 | radio->buffer[0] = 0x00; |
178 | radio->buffer[1] = 0x55; | 179 | radio->buffer[1] = 0x55; |
@@ -187,14 +188,12 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) | |||
187 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 188 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
188 | 189 | ||
189 | if (retval < 0 || size != BUFFER_LENGTH) { | 190 | if (retval < 0 || size != BUFFER_LENGTH) { |
190 | mutex_unlock(&radio->lock); | 191 | amradio_dev_warn(&radio->videodev.dev, "set mute failed\n"); |
191 | return retval; | 192 | return retval; |
192 | } | 193 | } |
193 | 194 | ||
194 | radio->muted = argument; | 195 | radio->muted = argument; |
195 | 196 | ||
196 | mutex_unlock(&radio->lock); | ||
197 | |||
198 | return retval; | 197 | return retval; |
199 | } | 198 | } |
200 | 199 | ||
@@ -205,11 +204,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) | |||
205 | int size; | 204 | int size; |
206 | unsigned short freq_send = 0x10 + (freq >> 3) / 25; | 205 | unsigned short freq_send = 0x10 + (freq >> 3) / 25; |
207 | 206 | ||
208 | /* safety check */ | 207 | BUG_ON(!mutex_is_locked(&radio->lock)); |
209 | if (radio->removed) | ||
210 | return -EIO; | ||
211 | |||
212 | mutex_lock(&radio->lock); | ||
213 | 208 | ||
214 | radio->buffer[0] = 0x00; | 209 | radio->buffer[0] = 0x00; |
215 | radio->buffer[1] = 0x55; | 210 | radio->buffer[1] = 0x55; |
@@ -223,10 +218,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) | |||
223 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 218 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
224 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 219 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
225 | 220 | ||
226 | if (retval < 0 || size != BUFFER_LENGTH) { | 221 | if (retval < 0 || size != BUFFER_LENGTH) |
227 | mutex_unlock(&radio->lock); | 222 | goto out_err; |
228 | return retval; | ||
229 | } | ||
230 | 223 | ||
231 | /* frequency is calculated from freq_send and placed in first 2 bytes */ | 224 | /* frequency is calculated from freq_send and placed in first 2 bytes */ |
232 | radio->buffer[0] = (freq_send >> 8) & 0xff; | 225 | radio->buffer[0] = (freq_send >> 8) & 0xff; |
@@ -240,13 +233,15 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) | |||
240 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 233 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
241 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 234 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
242 | 235 | ||
243 | if (retval < 0 || size != BUFFER_LENGTH) { | 236 | if (retval < 0 || size != BUFFER_LENGTH) |
244 | mutex_unlock(&radio->lock); | 237 | goto out_err; |
245 | return retval; | ||
246 | } | ||
247 | 238 | ||
248 | mutex_unlock(&radio->lock); | 239 | radio->curfreq = freq; |
240 | goto out; | ||
249 | 241 | ||
242 | out_err: | ||
243 | amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n"); | ||
244 | out: | ||
250 | return retval; | 245 | return retval; |
251 | } | 246 | } |
252 | 247 | ||
@@ -255,11 +250,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) | |||
255 | int retval; | 250 | int retval; |
256 | int size; | 251 | int size; |
257 | 252 | ||
258 | /* safety check */ | 253 | BUG_ON(!mutex_is_locked(&radio->lock)); |
259 | if (radio->removed) | ||
260 | return -EIO; | ||
261 | |||
262 | mutex_lock(&radio->lock); | ||
263 | 254 | ||
264 | radio->buffer[0] = 0x00; | 255 | radio->buffer[0] = 0x00; |
265 | radio->buffer[1] = 0x55; | 256 | radio->buffer[1] = 0x55; |
@@ -274,14 +265,14 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) | |||
274 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 265 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
275 | 266 | ||
276 | if (retval < 0 || size != BUFFER_LENGTH) { | 267 | if (retval < 0 || size != BUFFER_LENGTH) { |
277 | radio->stereo = -1; | 268 | amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n"); |
278 | mutex_unlock(&radio->lock); | ||
279 | return retval; | 269 | return retval; |
280 | } | 270 | } |
281 | 271 | ||
282 | radio->stereo = 1; | 272 | if (argument == WANT_STEREO) |
283 | 273 | radio->stereo = 1; | |
284 | mutex_unlock(&radio->lock); | 274 | else |
275 | radio->stereo = 0; | ||
285 | 276 | ||
286 | return retval; | 277 | return retval; |
287 | } | 278 | } |
@@ -296,19 +287,19 @@ static void usb_amradio_disconnect(struct usb_interface *intf) | |||
296 | struct amradio_device *radio = usb_get_intfdata(intf); | 287 | struct amradio_device *radio = usb_get_intfdata(intf); |
297 | 288 | ||
298 | mutex_lock(&radio->lock); | 289 | mutex_lock(&radio->lock); |
299 | radio->removed = 1; | 290 | radio->usbdev = NULL; |
300 | mutex_unlock(&radio->lock); | 291 | mutex_unlock(&radio->lock); |
301 | 292 | ||
302 | usb_set_intfdata(intf, NULL); | 293 | usb_set_intfdata(intf, NULL); |
303 | video_unregister_device(radio->videodev); | ||
304 | v4l2_device_disconnect(&radio->v4l2_dev); | 294 | v4l2_device_disconnect(&radio->v4l2_dev); |
295 | video_unregister_device(&radio->videodev); | ||
305 | } | 296 | } |
306 | 297 | ||
307 | /* vidioc_querycap - query device capabilities */ | 298 | /* vidioc_querycap - query device capabilities */ |
308 | static int vidioc_querycap(struct file *file, void *priv, | 299 | static int vidioc_querycap(struct file *file, void *priv, |
309 | struct v4l2_capability *v) | 300 | struct v4l2_capability *v) |
310 | { | 301 | { |
311 | struct amradio_device *radio = video_drvdata(file); | 302 | struct amradio_device *radio = file->private_data; |
312 | 303 | ||
313 | strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); | 304 | strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); |
314 | strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); | 305 | strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); |
@@ -322,13 +313,9 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
322 | static int vidioc_g_tuner(struct file *file, void *priv, | 313 | static int vidioc_g_tuner(struct file *file, void *priv, |
323 | struct v4l2_tuner *v) | 314 | struct v4l2_tuner *v) |
324 | { | 315 | { |
325 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 316 | struct amradio_device *radio = file->private_data; |
326 | int retval; | 317 | int retval; |
327 | 318 | ||
328 | /* safety check */ | ||
329 | if (radio->removed) | ||
330 | return -EIO; | ||
331 | |||
332 | if (v->index > 0) | 319 | if (v->index > 0) |
333 | return -EINVAL; | 320 | return -EINVAL; |
334 | 321 | ||
@@ -341,9 +328,6 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
341 | * amradio_set_stereo shouldn't be here | 328 | * amradio_set_stereo shouldn't be here |
342 | */ | 329 | */ |
343 | retval = amradio_set_stereo(radio, WANT_STEREO); | 330 | retval = amradio_set_stereo(radio, WANT_STEREO); |
344 | if (retval < 0) | ||
345 | amradio_dev_warn(&radio->videodev->dev, | ||
346 | "set stereo failed\n"); | ||
347 | 331 | ||
348 | strcpy(v->name, "FM"); | 332 | strcpy(v->name, "FM"); |
349 | v->type = V4L2_TUNER_RADIO; | 333 | v->type = V4L2_TUNER_RADIO; |
@@ -357,19 +341,16 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
357 | v->audmode = V4L2_TUNER_MODE_MONO; | 341 | v->audmode = V4L2_TUNER_MODE_MONO; |
358 | v->signal = 0xffff; /* Can't get the signal strength, sad.. */ | 342 | v->signal = 0xffff; /* Can't get the signal strength, sad.. */ |
359 | v->afc = 0; /* Don't know what is this */ | 343 | v->afc = 0; /* Don't know what is this */ |
360 | return 0; | 344 | |
345 | return retval; | ||
361 | } | 346 | } |
362 | 347 | ||
363 | /* vidioc_s_tuner - set tuner attributes */ | 348 | /* vidioc_s_tuner - set tuner attributes */ |
364 | static int vidioc_s_tuner(struct file *file, void *priv, | 349 | static int vidioc_s_tuner(struct file *file, void *priv, |
365 | struct v4l2_tuner *v) | 350 | struct v4l2_tuner *v) |
366 | { | 351 | { |
367 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 352 | struct amradio_device *radio = file->private_data; |
368 | int retval; | 353 | int retval = -EINVAL; |
369 | |||
370 | /* safety check */ | ||
371 | if (radio->removed) | ||
372 | return -EIO; | ||
373 | 354 | ||
374 | if (v->index > 0) | 355 | if (v->index > 0) |
375 | return -EINVAL; | 356 | return -EINVAL; |
@@ -378,57 +359,33 @@ static int vidioc_s_tuner(struct file *file, void *priv, | |||
378 | switch (v->audmode) { | 359 | switch (v->audmode) { |
379 | case V4L2_TUNER_MODE_MONO: | 360 | case V4L2_TUNER_MODE_MONO: |
380 | retval = amradio_set_stereo(radio, WANT_MONO); | 361 | retval = amradio_set_stereo(radio, WANT_MONO); |
381 | if (retval < 0) | ||
382 | amradio_dev_warn(&radio->videodev->dev, | ||
383 | "set mono failed\n"); | ||
384 | break; | 362 | break; |
385 | case V4L2_TUNER_MODE_STEREO: | 363 | case V4L2_TUNER_MODE_STEREO: |
386 | retval = amradio_set_stereo(radio, WANT_STEREO); | 364 | retval = amradio_set_stereo(radio, WANT_STEREO); |
387 | if (retval < 0) | ||
388 | amradio_dev_warn(&radio->videodev->dev, | ||
389 | "set stereo failed\n"); | ||
390 | break; | 365 | break; |
391 | default: | ||
392 | return -EINVAL; | ||
393 | } | 366 | } |
394 | 367 | ||
395 | return 0; | 368 | return retval; |
396 | } | 369 | } |
397 | 370 | ||
398 | /* vidioc_s_frequency - set tuner radio frequency */ | 371 | /* vidioc_s_frequency - set tuner radio frequency */ |
399 | static int vidioc_s_frequency(struct file *file, void *priv, | 372 | static int vidioc_s_frequency(struct file *file, void *priv, |
400 | struct v4l2_frequency *f) | 373 | struct v4l2_frequency *f) |
401 | { | 374 | { |
402 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 375 | struct amradio_device *radio = file->private_data; |
403 | int retval; | ||
404 | 376 | ||
405 | /* safety check */ | 377 | return amradio_setfreq(radio, f->frequency); |
406 | if (radio->removed) | ||
407 | return -EIO; | ||
408 | |||
409 | mutex_lock(&radio->lock); | ||
410 | radio->curfreq = f->frequency; | ||
411 | mutex_unlock(&radio->lock); | ||
412 | |||
413 | retval = amradio_setfreq(radio, radio->curfreq); | ||
414 | if (retval < 0) | ||
415 | amradio_dev_warn(&radio->videodev->dev, | ||
416 | "set frequency failed\n"); | ||
417 | return 0; | ||
418 | } | 378 | } |
419 | 379 | ||
420 | /* vidioc_g_frequency - get tuner radio frequency */ | 380 | /* vidioc_g_frequency - get tuner radio frequency */ |
421 | static int vidioc_g_frequency(struct file *file, void *priv, | 381 | static int vidioc_g_frequency(struct file *file, void *priv, |
422 | struct v4l2_frequency *f) | 382 | struct v4l2_frequency *f) |
423 | { | 383 | { |
424 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 384 | struct amradio_device *radio = file->private_data; |
425 | |||
426 | /* safety check */ | ||
427 | if (radio->removed) | ||
428 | return -EIO; | ||
429 | 385 | ||
430 | f->type = V4L2_TUNER_RADIO; | 386 | f->type = V4L2_TUNER_RADIO; |
431 | f->frequency = radio->curfreq; | 387 | f->frequency = radio->curfreq; |
388 | |||
432 | return 0; | 389 | return 0; |
433 | } | 390 | } |
434 | 391 | ||
@@ -448,17 +405,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
448 | static int vidioc_g_ctrl(struct file *file, void *priv, | 405 | static int vidioc_g_ctrl(struct file *file, void *priv, |
449 | struct v4l2_control *ctrl) | 406 | struct v4l2_control *ctrl) |
450 | { | 407 | { |
451 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 408 | struct amradio_device *radio = file->private_data; |
452 | |||
453 | /* safety check */ | ||
454 | if (radio->removed) | ||
455 | return -EIO; | ||
456 | 409 | ||
457 | switch (ctrl->id) { | 410 | switch (ctrl->id) { |
458 | case V4L2_CID_AUDIO_MUTE: | 411 | case V4L2_CID_AUDIO_MUTE: |
459 | ctrl->value = radio->muted; | 412 | ctrl->value = radio->muted; |
460 | return 0; | 413 | return 0; |
461 | } | 414 | } |
415 | |||
462 | return -EINVAL; | 416 | return -EINVAL; |
463 | } | 417 | } |
464 | 418 | ||
@@ -466,33 +420,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
466 | static int vidioc_s_ctrl(struct file *file, void *priv, | 420 | static int vidioc_s_ctrl(struct file *file, void *priv, |
467 | struct v4l2_control *ctrl) | 421 | struct v4l2_control *ctrl) |
468 | { | 422 | { |
469 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 423 | struct amradio_device *radio = file->private_data; |
470 | int retval; | 424 | int retval = -EINVAL; |
471 | |||
472 | /* safety check */ | ||
473 | if (radio->removed) | ||
474 | return -EIO; | ||
475 | 425 | ||
476 | switch (ctrl->id) { | 426 | switch (ctrl->id) { |
477 | case V4L2_CID_AUDIO_MUTE: | 427 | case V4L2_CID_AUDIO_MUTE: |
478 | if (ctrl->value) { | 428 | if (ctrl->value) |
479 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 429 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
480 | if (retval < 0) { | 430 | else |
481 | amradio_dev_warn(&radio->videodev->dev, | ||
482 | "amradio_stop failed\n"); | ||
483 | return -1; | ||
484 | } | ||
485 | } else { | ||
486 | retval = amradio_set_mute(radio, AMRADIO_START); | 431 | retval = amradio_set_mute(radio, AMRADIO_START); |
487 | if (retval < 0) { | 432 | |
488 | amradio_dev_warn(&radio->videodev->dev, | 433 | break; |
489 | "amradio_start failed\n"); | ||
490 | return -1; | ||
491 | } | ||
492 | } | ||
493 | return 0; | ||
494 | } | 434 | } |
495 | return -EINVAL; | 435 | |
436 | return retval; | ||
496 | } | 437 | } |
497 | 438 | ||
498 | /* vidioc_g_audio - get audio attributes */ | 439 | /* vidioc_g_audio - get audio attributes */ |
@@ -531,75 +472,108 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | |||
531 | return 0; | 472 | return 0; |
532 | } | 473 | } |
533 | 474 | ||
534 | /* open device - amradio_start() and amradio_setfreq() */ | 475 | static int usb_amradio_init(struct amradio_device *radio) |
535 | static int usb_amradio_open(struct file *file) | ||
536 | { | 476 | { |
537 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | ||
538 | int retval; | 477 | int retval; |
539 | 478 | ||
540 | lock_kernel(); | 479 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
480 | if (retval) | ||
481 | goto out_err; | ||
541 | 482 | ||
542 | radio->users = 1; | 483 | retval = amradio_set_stereo(radio, WANT_STEREO); |
543 | radio->muted = 1; | 484 | if (retval) |
485 | goto out_err; | ||
544 | 486 | ||
545 | retval = amradio_set_mute(radio, AMRADIO_START); | 487 | radio->initialized = 1; |
546 | if (retval < 0) { | 488 | goto out; |
547 | amradio_dev_warn(&radio->videodev->dev, | 489 | |
548 | "radio did not start up properly\n"); | 490 | out_err: |
549 | radio->users = 0; | 491 | amradio_dev_err(&radio->videodev.dev, "initialization failed\n"); |
550 | unlock_kernel(); | 492 | out: |
551 | return -EIO; | 493 | return retval; |
494 | } | ||
495 | |||
496 | /* open device - amradio_start() and amradio_setfreq() */ | ||
497 | static int usb_amradio_open(struct file *file) | ||
498 | { | ||
499 | struct amradio_device *radio = vdev_to_amradio(video_devdata(file)); | ||
500 | int retval = 0; | ||
501 | |||
502 | mutex_lock(&radio->lock); | ||
503 | |||
504 | if (!radio->usbdev) { | ||
505 | retval = -EIO; | ||
506 | goto unlock; | ||
552 | } | 507 | } |
553 | 508 | ||
554 | retval = amradio_set_stereo(radio, WANT_STEREO); | 509 | file->private_data = radio; |
555 | if (retval < 0) | 510 | retval = usb_autopm_get_interface(radio->intf); |
556 | amradio_dev_warn(&radio->videodev->dev, | 511 | if (retval) |
557 | "set stereo failed\n"); | 512 | goto unlock; |
558 | 513 | ||
559 | retval = amradio_setfreq(radio, radio->curfreq); | 514 | if (unlikely(!radio->initialized)) { |
560 | if (retval < 0) | 515 | retval = usb_amradio_init(radio); |
561 | amradio_dev_warn(&radio->videodev->dev, | 516 | if (retval) |
562 | "set frequency failed\n"); | 517 | usb_autopm_put_interface(radio->intf); |
518 | } | ||
563 | 519 | ||
564 | unlock_kernel(); | 520 | unlock: |
565 | return 0; | 521 | mutex_unlock(&radio->lock); |
522 | return retval; | ||
566 | } | 523 | } |
567 | 524 | ||
568 | /*close device */ | 525 | /*close device */ |
569 | static int usb_amradio_close(struct file *file) | 526 | static int usb_amradio_close(struct file *file) |
570 | { | 527 | { |
571 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 528 | struct amradio_device *radio = file->private_data; |
572 | int retval; | 529 | int retval = 0; |
573 | |||
574 | if (!radio) | ||
575 | return -ENODEV; | ||
576 | 530 | ||
577 | mutex_lock(&radio->lock); | 531 | mutex_lock(&radio->lock); |
578 | radio->users = 0; | 532 | |
533 | if (!radio->usbdev) | ||
534 | retval = -EIO; | ||
535 | else | ||
536 | usb_autopm_put_interface(radio->intf); | ||
537 | |||
579 | mutex_unlock(&radio->lock); | 538 | mutex_unlock(&radio->lock); |
539 | return retval; | ||
540 | } | ||
580 | 541 | ||
581 | if (!radio->removed) { | 542 | static long usb_amradio_ioctl(struct file *file, unsigned int cmd, |
582 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 543 | unsigned long arg) |
583 | if (retval < 0) | 544 | { |
584 | amradio_dev_warn(&radio->videodev->dev, | 545 | struct amradio_device *radio = file->private_data; |
585 | "amradio_stop failed\n"); | 546 | long retval = 0; |
547 | |||
548 | mutex_lock(&radio->lock); | ||
549 | |||
550 | if (!radio->usbdev) { | ||
551 | retval = -EIO; | ||
552 | goto unlock; | ||
586 | } | 553 | } |
587 | 554 | ||
588 | return 0; | 555 | retval = video_ioctl2(file, cmd, arg); |
556 | |||
557 | unlock: | ||
558 | mutex_unlock(&radio->lock); | ||
559 | return retval; | ||
589 | } | 560 | } |
590 | 561 | ||
591 | /* Suspend device - stop device. Need to be checked and fixed */ | 562 | /* Suspend device - stop device. Need to be checked and fixed */ |
592 | static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) | 563 | static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) |
593 | { | 564 | { |
594 | struct amradio_device *radio = usb_get_intfdata(intf); | 565 | struct amradio_device *radio = usb_get_intfdata(intf); |
595 | int retval; | ||
596 | 566 | ||
597 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 567 | mutex_lock(&radio->lock); |
598 | if (retval < 0) | 568 | |
599 | dev_warn(&intf->dev, "amradio_stop failed\n"); | 569 | if (!radio->muted && radio->initialized) { |
570 | amradio_set_mute(radio, AMRADIO_STOP); | ||
571 | radio->muted = 0; | ||
572 | } | ||
600 | 573 | ||
601 | dev_info(&intf->dev, "going into suspend..\n"); | 574 | dev_info(&intf->dev, "going into suspend..\n"); |
602 | 575 | ||
576 | mutex_unlock(&radio->lock); | ||
603 | return 0; | 577 | return 0; |
604 | } | 578 | } |
605 | 579 | ||
@@ -607,14 +581,26 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) | |||
607 | static int usb_amradio_resume(struct usb_interface *intf) | 581 | static int usb_amradio_resume(struct usb_interface *intf) |
608 | { | 582 | { |
609 | struct amradio_device *radio = usb_get_intfdata(intf); | 583 | struct amradio_device *radio = usb_get_intfdata(intf); |
610 | int retval; | ||
611 | 584 | ||
612 | retval = amradio_set_mute(radio, AMRADIO_START); | 585 | mutex_lock(&radio->lock); |
613 | if (retval < 0) | 586 | |
614 | dev_warn(&intf->dev, "amradio_start failed\n"); | 587 | if (unlikely(!radio->initialized)) |
588 | goto unlock; | ||
589 | |||
590 | if (radio->stereo) | ||
591 | amradio_set_stereo(radio, WANT_STEREO); | ||
592 | else | ||
593 | amradio_set_stereo(radio, WANT_MONO); | ||
594 | |||
595 | amradio_setfreq(radio, radio->curfreq); | ||
615 | 596 | ||
597 | if (!radio->muted) | ||
598 | amradio_set_mute(radio, AMRADIO_START); | ||
599 | |||
600 | unlock: | ||
616 | dev_info(&intf->dev, "coming out of suspend..\n"); | 601 | dev_info(&intf->dev, "coming out of suspend..\n"); |
617 | 602 | ||
603 | mutex_unlock(&radio->lock); | ||
618 | return 0; | 604 | return 0; |
619 | } | 605 | } |
620 | 606 | ||
@@ -623,7 +609,7 @@ static const struct v4l2_file_operations usb_amradio_fops = { | |||
623 | .owner = THIS_MODULE, | 609 | .owner = THIS_MODULE, |
624 | .open = usb_amradio_open, | 610 | .open = usb_amradio_open, |
625 | .release = usb_amradio_close, | 611 | .release = usb_amradio_close, |
626 | .ioctl = video_ioctl2, | 612 | .ioctl = usb_amradio_ioctl, |
627 | }; | 613 | }; |
628 | 614 | ||
629 | static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { | 615 | static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { |
@@ -643,10 +629,7 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { | |||
643 | 629 | ||
644 | static void usb_amradio_video_device_release(struct video_device *videodev) | 630 | static void usb_amradio_video_device_release(struct video_device *videodev) |
645 | { | 631 | { |
646 | struct amradio_device *radio = video_get_drvdata(videodev); | 632 | struct amradio_device *radio = vdev_to_amradio(videodev); |
647 | |||
648 | /* we call v4l to free radio->videodev */ | ||
649 | video_device_release(videodev); | ||
650 | 633 | ||
651 | v4l2_device_unregister(&radio->v4l2_dev); | 634 | v4l2_device_unregister(&radio->v4l2_dev); |
652 | 635 | ||
@@ -660,70 +643,63 @@ static int usb_amradio_probe(struct usb_interface *intf, | |||
660 | const struct usb_device_id *id) | 643 | const struct usb_device_id *id) |
661 | { | 644 | { |
662 | struct amradio_device *radio; | 645 | struct amradio_device *radio; |
663 | struct v4l2_device *v4l2_dev; | 646 | int retval = 0; |
664 | int retval; | ||
665 | 647 | ||
666 | radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); | 648 | radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); |
667 | 649 | ||
668 | if (!radio) { | 650 | if (!radio) { |
669 | dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); | 651 | dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); |
670 | return -ENOMEM; | 652 | retval = -ENOMEM; |
653 | goto err; | ||
671 | } | 654 | } |
672 | 655 | ||
673 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); | 656 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); |
674 | 657 | ||
675 | if (!radio->buffer) { | 658 | if (!radio->buffer) { |
676 | dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); | 659 | dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); |
677 | kfree(radio); | 660 | retval = -ENOMEM; |
678 | return -ENOMEM; | 661 | goto err_nobuf; |
679 | } | 662 | } |
680 | 663 | ||
681 | v4l2_dev = &radio->v4l2_dev; | 664 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); |
682 | retval = v4l2_device_register(&intf->dev, v4l2_dev); | ||
683 | if (retval < 0) { | 665 | if (retval < 0) { |
684 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | 666 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); |
685 | kfree(radio->buffer); | 667 | goto err_v4l2; |
686 | kfree(radio); | ||
687 | return retval; | ||
688 | } | 668 | } |
689 | 669 | ||
690 | radio->videodev = video_device_alloc(); | 670 | strlcpy(radio->videodev.name, radio->v4l2_dev.name, |
691 | 671 | sizeof(radio->videodev.name)); | |
692 | if (!radio->videodev) { | 672 | radio->videodev.v4l2_dev = &radio->v4l2_dev; |
693 | dev_err(&intf->dev, "video_device_alloc failed\n"); | 673 | radio->videodev.fops = &usb_amradio_fops; |
694 | kfree(radio->buffer); | 674 | radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops; |
695 | kfree(radio); | 675 | radio->videodev.release = usb_amradio_video_device_release; |
696 | return -ENOMEM; | ||
697 | } | ||
698 | 676 | ||
699 | strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name)); | ||
700 | radio->videodev->v4l2_dev = v4l2_dev; | ||
701 | radio->videodev->fops = &usb_amradio_fops; | ||
702 | radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops; | ||
703 | radio->videodev->release = usb_amradio_video_device_release; | ||
704 | |||
705 | radio->removed = 0; | ||
706 | radio->users = 0; | ||
707 | radio->usbdev = interface_to_usbdev(intf); | 677 | radio->usbdev = interface_to_usbdev(intf); |
678 | radio->intf = intf; | ||
708 | radio->curfreq = 95.16 * FREQ_MUL; | 679 | radio->curfreq = 95.16 * FREQ_MUL; |
709 | radio->stereo = -1; | ||
710 | 680 | ||
711 | mutex_init(&radio->lock); | 681 | mutex_init(&radio->lock); |
712 | 682 | ||
713 | video_set_drvdata(radio->videodev, radio); | 683 | video_set_drvdata(&radio->videodev, radio); |
714 | 684 | ||
715 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); | 685 | retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, |
686 | radio_nr); | ||
716 | if (retval < 0) { | 687 | if (retval < 0) { |
717 | dev_err(&intf->dev, "could not register video device\n"); | 688 | dev_err(&intf->dev, "could not register video device\n"); |
718 | video_device_release(radio->videodev); | 689 | goto err_vdev; |
719 | v4l2_device_unregister(v4l2_dev); | ||
720 | kfree(radio->buffer); | ||
721 | kfree(radio); | ||
722 | return -EIO; | ||
723 | } | 690 | } |
724 | 691 | ||
725 | usb_set_intfdata(intf, radio); | 692 | usb_set_intfdata(intf, radio); |
726 | return 0; | 693 | return 0; |
694 | |||
695 | err_vdev: | ||
696 | v4l2_device_unregister(&radio->v4l2_dev); | ||
697 | err_v4l2: | ||
698 | kfree(radio->buffer); | ||
699 | err_nobuf: | ||
700 | kfree(radio); | ||
701 | err: | ||
702 | return retval; | ||
727 | } | 703 | } |
728 | 704 | ||
729 | static int __init amradio_init(void) | 705 | static int __init amradio_init(void) |