diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2010-10-17 09:26:18 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-22 23:40:58 -0200 |
commit | a682d4cb768381039bdafdc3c04c53cf8d70dcf0 (patch) | |
tree | 5b4b92be483f34d08b85e25ae7938af416bc7316 /drivers/media/radio/radio-mr800.c | |
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>
Diffstat (limited to 'drivers/media/radio/radio-mr800.c')
-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) struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); mutex_lock(&radio->lock); + /* increase the device node's refcount */ + get_device(&radio->videodev.dev); v4l2_device_disconnect(&radio->v4l2_dev); - mutex_unlock(&radio->lock); video_unregister_device(&radio->videodev); + mutex_unlock(&radio->lock); + /* decrease the device node's refcount, allowing it to be released */ + put_device(&radio->videodev.dev); } /* vidioc_querycap - query device capabilities */ @@ -515,7 +519,8 @@ static int usb_amradio_close(struct file *file) { struct amradio_device *radio = file->private_data; - usb_autopm_put_interface(radio->intf); + if (video_is_registered(&radio->videodev)) + usb_autopm_put_interface(radio->intf); return 0; } @@ -524,10 +529,12 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) { struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); + mutex_lock(&radio->lock); if (!radio->muted && radio->initialized) { amradio_set_mute(radio, AMRADIO_STOP); radio->muted = 0; } + mutex_unlock(&radio->lock); dev_info(&intf->dev, "going into suspend..\n"); return 0; @@ -538,8 +545,9 @@ static int usb_amradio_resume(struct usb_interface *intf) { struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); + mutex_lock(&radio->lock); if (unlikely(!radio->initialized)) - return 0; + goto unlock; if (radio->stereo) amradio_set_stereo(radio, WANT_STEREO); @@ -551,6 +559,9 @@ static int usb_amradio_resume(struct usb_interface *intf) if (!radio->muted) amradio_set_mute(radio, AMRADIO_START); +unlock: + mutex_unlock(&radio->lock); + dev_info(&intf->dev, "coming out of suspend..\n"); return 0; } |