diff options
author | David Ellingsworth <david@identd.dyndns.org> | 2009-09-22 20:22:19 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-12-05 15:40:07 -0500 |
commit | 4aebc2893eada9e054a37df8bb342a53f8ca0d2a (patch) | |
tree | 74346cee8857ecb5859abc47259cc8254d3e0301 /drivers/media/radio/radio-mr800.c | |
parent | 0f017212567793ecedf86f709f43ca40f9b84655 (diff) |
V4L/DVB (13060): radio-mr800: implement proper locking
Implement proper locking
Signed-off-by: David Ellingsworth <david@identd.dyndns.org>
Acked-by: Alexey Klimov <klimov.linux@gmail.com>
Signed-off-by: Douglas Schilling Landgraf <dougsland@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio/radio-mr800.c')
-rw-r--r-- | drivers/media/radio/radio-mr800.c | 181 |
1 files changed, 106 insertions, 75 deletions
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index a1239083472d..75c69755a04c 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c | |||
@@ -168,11 +168,7 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) | |||
168 | int retval; | 168 | int retval; |
169 | int size; | 169 | int size; |
170 | 170 | ||
171 | /* safety check */ | 171 | BUG_ON(!mutex_is_locked(&radio->lock)); |
172 | if (radio->removed) | ||
173 | return -EIO; | ||
174 | |||
175 | mutex_lock(&radio->lock); | ||
176 | 172 | ||
177 | radio->buffer[0] = 0x00; | 173 | radio->buffer[0] = 0x00; |
178 | radio->buffer[1] = 0x55; | 174 | radio->buffer[1] = 0x55; |
@@ -186,15 +182,11 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) | |||
186 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 182 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
187 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 183 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
188 | 184 | ||
189 | if (retval < 0 || size != BUFFER_LENGTH) { | 185 | if (retval < 0 || size != BUFFER_LENGTH) |
190 | mutex_unlock(&radio->lock); | ||
191 | return retval; | 186 | return retval; |
192 | } | ||
193 | 187 | ||
194 | radio->muted = argument; | 188 | radio->muted = argument; |
195 | 189 | ||
196 | mutex_unlock(&radio->lock); | ||
197 | |||
198 | return retval; | 190 | return retval; |
199 | } | 191 | } |
200 | 192 | ||
@@ -205,11 +197,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) | |||
205 | int size; | 197 | int size; |
206 | unsigned short freq_send = 0x10 + (freq >> 3) / 25; | 198 | unsigned short freq_send = 0x10 + (freq >> 3) / 25; |
207 | 199 | ||
208 | /* safety check */ | 200 | BUG_ON(!mutex_is_locked(&radio->lock)); |
209 | if (radio->removed) | ||
210 | return -EIO; | ||
211 | |||
212 | mutex_lock(&radio->lock); | ||
213 | 201 | ||
214 | radio->buffer[0] = 0x00; | 202 | radio->buffer[0] = 0x00; |
215 | radio->buffer[1] = 0x55; | 203 | radio->buffer[1] = 0x55; |
@@ -223,10 +211,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) | |||
223 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 211 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
224 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 212 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
225 | 213 | ||
226 | if (retval < 0 || size != BUFFER_LENGTH) { | 214 | if (retval < 0 || size != BUFFER_LENGTH) |
227 | mutex_unlock(&radio->lock); | ||
228 | return retval; | 215 | return retval; |
229 | } | ||
230 | 216 | ||
231 | /* frequency is calculated from freq_send and placed in first 2 bytes */ | 217 | /* frequency is calculated from freq_send and placed in first 2 bytes */ |
232 | radio->buffer[0] = (freq_send >> 8) & 0xff; | 218 | radio->buffer[0] = (freq_send >> 8) & 0xff; |
@@ -240,13 +226,6 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) | |||
240 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 226 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
241 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 227 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
242 | 228 | ||
243 | if (retval < 0 || size != BUFFER_LENGTH) { | ||
244 | mutex_unlock(&radio->lock); | ||
245 | return retval; | ||
246 | } | ||
247 | |||
248 | mutex_unlock(&radio->lock); | ||
249 | |||
250 | return retval; | 229 | return retval; |
251 | } | 230 | } |
252 | 231 | ||
@@ -255,11 +234,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) | |||
255 | int retval; | 234 | int retval; |
256 | int size; | 235 | int size; |
257 | 236 | ||
258 | /* safety check */ | 237 | BUG_ON(!mutex_is_locked(&radio->lock)); |
259 | if (radio->removed) | ||
260 | return -EIO; | ||
261 | |||
262 | mutex_lock(&radio->lock); | ||
263 | 238 | ||
264 | radio->buffer[0] = 0x00; | 239 | radio->buffer[0] = 0x00; |
265 | radio->buffer[1] = 0x55; | 240 | radio->buffer[1] = 0x55; |
@@ -275,14 +250,11 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) | |||
275 | 250 | ||
276 | if (retval < 0 || size != BUFFER_LENGTH) { | 251 | if (retval < 0 || size != BUFFER_LENGTH) { |
277 | radio->stereo = -1; | 252 | radio->stereo = -1; |
278 | mutex_unlock(&radio->lock); | ||
279 | return retval; | 253 | return retval; |
280 | } | 254 | } |
281 | 255 | ||
282 | radio->stereo = 1; | 256 | radio->stereo = 1; |
283 | 257 | ||
284 | mutex_unlock(&radio->lock); | ||
285 | |||
286 | return retval; | 258 | return retval; |
287 | } | 259 | } |
288 | 260 | ||
@@ -325,12 +297,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
325 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 297 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
326 | int retval; | 298 | int retval; |
327 | 299 | ||
300 | mutex_lock(&radio->lock); | ||
301 | |||
328 | /* safety check */ | 302 | /* safety check */ |
329 | if (radio->removed) | 303 | if (radio->removed) { |
330 | return -EIO; | 304 | retval = -EIO; |
305 | goto unlock; | ||
306 | } | ||
331 | 307 | ||
332 | if (v->index > 0) | 308 | if (v->index > 0) { |
333 | return -EINVAL; | 309 | retval = -EINVAL; |
310 | goto unlock; | ||
311 | } | ||
334 | 312 | ||
335 | /* TODO: Add function which look is signal stereo or not | 313 | /* TODO: Add function which look is signal stereo or not |
336 | * amradio_getstat(radio); | 314 | * amradio_getstat(radio); |
@@ -357,7 +335,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
357 | v->audmode = V4L2_TUNER_MODE_MONO; | 335 | v->audmode = V4L2_TUNER_MODE_MONO; |
358 | v->signal = 0xffff; /* Can't get the signal strength, sad.. */ | 336 | v->signal = 0xffff; /* Can't get the signal strength, sad.. */ |
359 | v->afc = 0; /* Don't know what is this */ | 337 | v->afc = 0; /* Don't know what is this */ |
360 | return 0; | 338 | |
339 | unlock: | ||
340 | mutex_unlock(&radio->lock); | ||
341 | return retval; | ||
361 | } | 342 | } |
362 | 343 | ||
363 | /* vidioc_s_tuner - set tuner attributes */ | 344 | /* vidioc_s_tuner - set tuner attributes */ |
@@ -367,12 +348,18 @@ static int vidioc_s_tuner(struct file *file, void *priv, | |||
367 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 348 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
368 | int retval; | 349 | int retval; |
369 | 350 | ||
351 | mutex_lock(&radio->lock); | ||
352 | |||
370 | /* safety check */ | 353 | /* safety check */ |
371 | if (radio->removed) | 354 | if (radio->removed) { |
372 | return -EIO; | 355 | retval = -EIO; |
356 | goto unlock; | ||
357 | } | ||
373 | 358 | ||
374 | if (v->index > 0) | 359 | if (v->index > 0) { |
375 | return -EINVAL; | 360 | retval = -EINVAL; |
361 | goto unlock; | ||
362 | } | ||
376 | 363 | ||
377 | /* mono/stereo selector */ | 364 | /* mono/stereo selector */ |
378 | switch (v->audmode) { | 365 | switch (v->audmode) { |
@@ -389,10 +376,12 @@ static int vidioc_s_tuner(struct file *file, void *priv, | |||
389 | "set stereo failed\n"); | 376 | "set stereo failed\n"); |
390 | break; | 377 | break; |
391 | default: | 378 | default: |
392 | return -EINVAL; | 379 | retval = -EINVAL; |
393 | } | 380 | } |
394 | 381 | ||
395 | return 0; | 382 | unlock: |
383 | mutex_unlock(&radio->lock); | ||
384 | return retval; | ||
396 | } | 385 | } |
397 | 386 | ||
398 | /* vidioc_s_frequency - set tuner radio frequency */ | 387 | /* vidioc_s_frequency - set tuner radio frequency */ |
@@ -402,19 +391,24 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
402 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 391 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
403 | int retval; | 392 | int retval; |
404 | 393 | ||
394 | mutex_lock(&radio->lock); | ||
395 | |||
405 | /* safety check */ | 396 | /* safety check */ |
406 | if (radio->removed) | 397 | if (radio->removed) { |
407 | return -EIO; | 398 | retval = -EIO; |
399 | goto unlock; | ||
400 | } | ||
408 | 401 | ||
409 | mutex_lock(&radio->lock); | ||
410 | radio->curfreq = f->frequency; | 402 | radio->curfreq = f->frequency; |
411 | mutex_unlock(&radio->lock); | ||
412 | 403 | ||
413 | retval = amradio_setfreq(radio, radio->curfreq); | 404 | retval = amradio_setfreq(radio, radio->curfreq); |
414 | if (retval < 0) | 405 | if (retval < 0) |
415 | amradio_dev_warn(&radio->videodev->dev, | 406 | amradio_dev_warn(&radio->videodev->dev, |
416 | "set frequency failed\n"); | 407 | "set frequency failed\n"); |
417 | return 0; | 408 | |
409 | unlock: | ||
410 | mutex_unlock(&radio->lock); | ||
411 | return retval; | ||
418 | } | 412 | } |
419 | 413 | ||
420 | /* vidioc_g_frequency - get tuner radio frequency */ | 414 | /* vidioc_g_frequency - get tuner radio frequency */ |
@@ -422,14 +416,22 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
422 | struct v4l2_frequency *f) | 416 | struct v4l2_frequency *f) |
423 | { | 417 | { |
424 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 418 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
419 | int retval = 0; | ||
420 | |||
421 | mutex_lock(&radio->lock); | ||
425 | 422 | ||
426 | /* safety check */ | 423 | /* safety check */ |
427 | if (radio->removed) | 424 | if (radio->removed) { |
428 | return -EIO; | 425 | retval = -EIO; |
426 | goto unlock; | ||
427 | } | ||
429 | 428 | ||
430 | f->type = V4L2_TUNER_RADIO; | 429 | f->type = V4L2_TUNER_RADIO; |
431 | f->frequency = radio->curfreq; | 430 | f->frequency = radio->curfreq; |
432 | return 0; | 431 | |
432 | unlock: | ||
433 | mutex_unlock(&radio->lock); | ||
434 | return retval; | ||
433 | } | 435 | } |
434 | 436 | ||
435 | /* vidioc_queryctrl - enumerate control items */ | 437 | /* vidioc_queryctrl - enumerate control items */ |
@@ -449,17 +451,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
449 | struct v4l2_control *ctrl) | 451 | struct v4l2_control *ctrl) |
450 | { | 452 | { |
451 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 453 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
454 | int retval = -EINVAL; | ||
455 | |||
456 | mutex_lock(&radio->lock); | ||
452 | 457 | ||
453 | /* safety check */ | 458 | /* safety check */ |
454 | if (radio->removed) | 459 | if (radio->removed) { |
455 | return -EIO; | 460 | retval = -EIO; |
461 | goto unlock; | ||
462 | } | ||
456 | 463 | ||
457 | switch (ctrl->id) { | 464 | switch (ctrl->id) { |
458 | case V4L2_CID_AUDIO_MUTE: | 465 | case V4L2_CID_AUDIO_MUTE: |
459 | ctrl->value = radio->muted; | 466 | ctrl->value = radio->muted; |
460 | return 0; | 467 | retval = 0; |
468 | break; | ||
461 | } | 469 | } |
462 | return -EINVAL; | 470 | |
471 | unlock: | ||
472 | mutex_unlock(&radio->lock); | ||
473 | return retval; | ||
463 | } | 474 | } |
464 | 475 | ||
465 | /* vidioc_s_ctrl - set the value of a control */ | 476 | /* vidioc_s_ctrl - set the value of a control */ |
@@ -467,11 +478,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
467 | struct v4l2_control *ctrl) | 478 | struct v4l2_control *ctrl) |
468 | { | 479 | { |
469 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 480 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
470 | int retval; | 481 | int retval = -EINVAL; |
482 | |||
483 | mutex_lock(&radio->lock); | ||
471 | 484 | ||
472 | /* safety check */ | 485 | /* safety check */ |
473 | if (radio->removed) | 486 | if (radio->removed) { |
474 | return -EIO; | 487 | retval = -EIO; |
488 | goto unlock; | ||
489 | } | ||
475 | 490 | ||
476 | switch (ctrl->id) { | 491 | switch (ctrl->id) { |
477 | case V4L2_CID_AUDIO_MUTE: | 492 | case V4L2_CID_AUDIO_MUTE: |
@@ -480,19 +495,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
480 | if (retval < 0) { | 495 | if (retval < 0) { |
481 | amradio_dev_warn(&radio->videodev->dev, | 496 | amradio_dev_warn(&radio->videodev->dev, |
482 | "amradio_stop failed\n"); | 497 | "amradio_stop failed\n"); |
483 | return -1; | ||
484 | } | 498 | } |
485 | } else { | 499 | } else { |
486 | retval = amradio_set_mute(radio, AMRADIO_START); | 500 | retval = amradio_set_mute(radio, AMRADIO_START); |
487 | if (retval < 0) { | 501 | if (retval < 0) { |
488 | amradio_dev_warn(&radio->videodev->dev, | 502 | amradio_dev_warn(&radio->videodev->dev, |
489 | "amradio_start failed\n"); | 503 | "amradio_start failed\n"); |
490 | return -1; | ||
491 | } | 504 | } |
492 | } | 505 | } |
493 | return 0; | 506 | break; |
494 | } | 507 | } |
495 | return -EINVAL; | 508 | |
509 | unlock: | ||
510 | mutex_unlock(&radio->lock); | ||
511 | return retval; | ||
496 | } | 512 | } |
497 | 513 | ||
498 | /* vidioc_g_audio - get audio attributes */ | 514 | /* vidioc_g_audio - get audio attributes */ |
@@ -535,9 +551,14 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | |||
535 | static int usb_amradio_open(struct file *file) | 551 | static int usb_amradio_open(struct file *file) |
536 | { | 552 | { |
537 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 553 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
538 | int retval; | 554 | int retval = 0; |
539 | 555 | ||
540 | lock_kernel(); | 556 | mutex_lock(&radio->lock); |
557 | |||
558 | if (radio->removed) { | ||
559 | retval = -EIO; | ||
560 | goto unlock; | ||
561 | } | ||
541 | 562 | ||
542 | radio->users = 1; | 563 | radio->users = 1; |
543 | radio->muted = 1; | 564 | radio->muted = 1; |
@@ -547,8 +568,7 @@ static int usb_amradio_open(struct file *file) | |||
547 | amradio_dev_warn(&radio->videodev->dev, | 568 | amradio_dev_warn(&radio->videodev->dev, |
548 | "radio did not start up properly\n"); | 569 | "radio did not start up properly\n"); |
549 | radio->users = 0; | 570 | radio->users = 0; |
550 | unlock_kernel(); | 571 | goto unlock; |
551 | return -EIO; | ||
552 | } | 572 | } |
553 | 573 | ||
554 | retval = amradio_set_stereo(radio, WANT_STEREO); | 574 | retval = amradio_set_stereo(radio, WANT_STEREO); |
@@ -561,22 +581,25 @@ static int usb_amradio_open(struct file *file) | |||
561 | amradio_dev_warn(&radio->videodev->dev, | 581 | amradio_dev_warn(&radio->videodev->dev, |
562 | "set frequency failed\n"); | 582 | "set frequency failed\n"); |
563 | 583 | ||
564 | unlock_kernel(); | 584 | unlock: |
565 | return 0; | 585 | mutex_unlock(&radio->lock); |
586 | return retval; | ||
566 | } | 587 | } |
567 | 588 | ||
568 | /*close device */ | 589 | /*close device */ |
569 | static int usb_amradio_close(struct file *file) | 590 | static int usb_amradio_close(struct file *file) |
570 | { | 591 | { |
571 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 592 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
572 | int retval; | 593 | int retval = 0; |
573 | |||
574 | if (!radio) | ||
575 | return -ENODEV; | ||
576 | 594 | ||
577 | mutex_lock(&radio->lock); | 595 | mutex_lock(&radio->lock); |
596 | |||
597 | if (radio->removed) { | ||
598 | retval = -EIO; | ||
599 | goto unlock; | ||
600 | } | ||
601 | |||
578 | radio->users = 0; | 602 | radio->users = 0; |
579 | mutex_unlock(&radio->lock); | ||
580 | 603 | ||
581 | if (!radio->removed) { | 604 | if (!radio->removed) { |
582 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 605 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
@@ -585,7 +608,9 @@ static int usb_amradio_close(struct file *file) | |||
585 | "amradio_stop failed\n"); | 608 | "amradio_stop failed\n"); |
586 | } | 609 | } |
587 | 610 | ||
588 | return 0; | 611 | unlock: |
612 | mutex_unlock(&radio->lock); | ||
613 | return retval; | ||
589 | } | 614 | } |
590 | 615 | ||
591 | /* Suspend device - stop device. Need to be checked and fixed */ | 616 | /* Suspend device - stop device. Need to be checked and fixed */ |
@@ -594,12 +619,15 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) | |||
594 | struct amradio_device *radio = usb_get_intfdata(intf); | 619 | struct amradio_device *radio = usb_get_intfdata(intf); |
595 | int retval; | 620 | int retval; |
596 | 621 | ||
622 | mutex_lock(&radio->lock); | ||
623 | |||
597 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 624 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
598 | if (retval < 0) | 625 | if (retval < 0) |
599 | dev_warn(&intf->dev, "amradio_stop failed\n"); | 626 | dev_warn(&intf->dev, "amradio_stop failed\n"); |
600 | 627 | ||
601 | dev_info(&intf->dev, "going into suspend..\n"); | 628 | dev_info(&intf->dev, "going into suspend..\n"); |
602 | 629 | ||
630 | mutex_unlock(&radio->lock); | ||
603 | return 0; | 631 | return 0; |
604 | } | 632 | } |
605 | 633 | ||
@@ -609,12 +637,15 @@ static int usb_amradio_resume(struct usb_interface *intf) | |||
609 | struct amradio_device *radio = usb_get_intfdata(intf); | 637 | struct amradio_device *radio = usb_get_intfdata(intf); |
610 | int retval; | 638 | int retval; |
611 | 639 | ||
640 | mutex_lock(&radio->lock); | ||
641 | |||
612 | retval = amradio_set_mute(radio, AMRADIO_START); | 642 | retval = amradio_set_mute(radio, AMRADIO_START); |
613 | if (retval < 0) | 643 | if (retval < 0) |
614 | dev_warn(&intf->dev, "amradio_start failed\n"); | 644 | dev_warn(&intf->dev, "amradio_start failed\n"); |
615 | 645 | ||
616 | dev_info(&intf->dev, "coming out of suspend..\n"); | 646 | dev_info(&intf->dev, "coming out of suspend..\n"); |
617 | 647 | ||
648 | mutex_unlock(&radio->lock); | ||
618 | return 0; | 649 | return 0; |
619 | } | 650 | } |
620 | 651 | ||