diff options
| author | Hans Verkuil <hverkuil@xs4all.nl> | 2010-10-17 08:26:18 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-22 21:40:58 -0400 |
| commit | a682d4cb768381039bdafdc3c04c53cf8d70dcf0 (patch) | |
| tree | 5b4b92be483f34d08b85e25ae7938af416bc7316 | |
| parent | e2302501c32a0e7e34b7077f10da03b72dd91570 (diff) | |
[media] [RFC] radio-mr800: locking fixes
- serialize the suspend and resume functions using the global lock.
- do not call usb_autopm_put_interface after a disconnect.
- fix a race when disconnecting the device.
Reported-by: David Ellingsworth <david@identd.dyndns.org>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Acked-by: David Ellingsworth<david@identd.dyndns.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| -rw-r--r-- | drivers/media/radio/radio-mr800.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 2f56b26cece9..b540e8072e92 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c | |||
| @@ -284,9 +284,13 @@ static void usb_amradio_disconnect(struct usb_interface *intf) | |||
| 284 | struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); | 284 | struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); |
| 285 | 285 | ||
| 286 | mutex_lock(&radio->lock); | 286 | mutex_lock(&radio->lock); |
| 287 | /* increase the device node's refcount */ | ||
| 288 | get_device(&radio->videodev.dev); | ||
| 287 | v4l2_device_disconnect(&radio->v4l2_dev); | 289 | v4l2_device_disconnect(&radio->v4l2_dev); |
| 288 | mutex_unlock(&radio->lock); | ||
| 289 | video_unregister_device(&radio->videodev); | 290 | video_unregister_device(&radio->videodev); |
| 291 | mutex_unlock(&radio->lock); | ||
| 292 | /* decrease the device node's refcount, allowing it to be released */ | ||
| 293 | put_device(&radio->videodev.dev); | ||
| 290 | } | 294 | } |
| 291 | 295 | ||
| 292 | /* vidioc_querycap - query device capabilities */ | 296 | /* vidioc_querycap - query device capabilities */ |
| @@ -515,7 +519,8 @@ static int usb_amradio_close(struct file *file) | |||
| 515 | { | 519 | { |
| 516 | struct amradio_device *radio = file->private_data; | 520 | struct amradio_device *radio = file->private_data; |
| 517 | 521 | ||
| 518 | usb_autopm_put_interface(radio->intf); | 522 | if (video_is_registered(&radio->videodev)) |
| 523 | usb_autopm_put_interface(radio->intf); | ||
| 519 | return 0; | 524 | return 0; |
| 520 | } | 525 | } |
| 521 | 526 | ||
| @@ -524,10 +529,12 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 524 | { | 529 | { |
| 525 | struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); | 530 | struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); |
| 526 | 531 | ||
| 532 | mutex_lock(&radio->lock); | ||
| 527 | if (!radio->muted && radio->initialized) { | 533 | if (!radio->muted && radio->initialized) { |
| 528 | amradio_set_mute(radio, AMRADIO_STOP); | 534 | amradio_set_mute(radio, AMRADIO_STOP); |
| 529 | radio->muted = 0; | 535 | radio->muted = 0; |
| 530 | } | 536 | } |
| 537 | mutex_unlock(&radio->lock); | ||
| 531 | 538 | ||
| 532 | dev_info(&intf->dev, "going into suspend..\n"); | 539 | dev_info(&intf->dev, "going into suspend..\n"); |
| 533 | return 0; | 540 | return 0; |
| @@ -538,8 +545,9 @@ static int usb_amradio_resume(struct usb_interface *intf) | |||
| 538 | { | 545 | { |
| 539 | struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); | 546 | struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); |
| 540 | 547 | ||
| 548 | mutex_lock(&radio->lock); | ||
| 541 | if (unlikely(!radio->initialized)) | 549 | if (unlikely(!radio->initialized)) |
| 542 | return 0; | 550 | goto unlock; |
| 543 | 551 | ||
| 544 | if (radio->stereo) | 552 | if (radio->stereo) |
| 545 | amradio_set_stereo(radio, WANT_STEREO); | 553 | amradio_set_stereo(radio, WANT_STEREO); |
| @@ -551,6 +559,9 @@ static int usb_amradio_resume(struct usb_interface *intf) | |||
| 551 | if (!radio->muted) | 559 | if (!radio->muted) |
| 552 | amradio_set_mute(radio, AMRADIO_START); | 560 | amradio_set_mute(radio, AMRADIO_START); |
| 553 | 561 | ||
| 562 | unlock: | ||
| 563 | mutex_unlock(&radio->lock); | ||
| 564 | |||
| 554 | dev_info(&intf->dev, "coming out of suspend..\n"); | 565 | dev_info(&intf->dev, "coming out of suspend..\n"); |
| 555 | return 0; | 566 | return 0; |
| 556 | } | 567 | } |
