From 4aebc2893eada9e054a37df8bb342a53f8ca0d2a Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Tue, 22 Sep 2009 21:22:19 -0300 Subject: [PATCH] V4L/DVB (13060): radio-mr800: implement proper locking Implement proper locking Signed-off-by: David Ellingsworth Acked-by: Alexey Klimov Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-mr800.c | 181 +++++++++++++++++------------- 1 file 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) int retval; int size; - /* safety check */ - if (radio->removed) - return -EIO; - - mutex_lock(&radio->lock); + BUG_ON(!mutex_is_locked(&radio->lock)); radio->buffer[0] = 0x00; radio->buffer[1] = 0x55; @@ -186,15 +182,11 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - if (retval < 0 || size != BUFFER_LENGTH) { - mutex_unlock(&radio->lock); + if (retval < 0 || size != BUFFER_LENGTH) return retval; - } radio->muted = argument; - mutex_unlock(&radio->lock); - return retval; } @@ -205,11 +197,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) int size; unsigned short freq_send = 0x10 + (freq >> 3) / 25; - /* safety check */ - if (radio->removed) - return -EIO; - - mutex_lock(&radio->lock); + BUG_ON(!mutex_is_locked(&radio->lock)); radio->buffer[0] = 0x00; radio->buffer[1] = 0x55; @@ -223,10 +211,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - if (retval < 0 || size != BUFFER_LENGTH) { - mutex_unlock(&radio->lock); + if (retval < 0 || size != BUFFER_LENGTH) return retval; - } /* frequency is calculated from freq_send and placed in first 2 bytes */ radio->buffer[0] = (freq_send >> 8) & 0xff; @@ -240,13 +226,6 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - if (retval < 0 || size != BUFFER_LENGTH) { - mutex_unlock(&radio->lock); - return retval; - } - - mutex_unlock(&radio->lock); - return retval; } @@ -255,11 +234,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) int retval; int size; - /* safety check */ - if (radio->removed) - return -EIO; - - mutex_lock(&radio->lock); + BUG_ON(!mutex_is_locked(&radio->lock)); radio->buffer[0] = 0x00; radio->buffer[1] = 0x55; @@ -275,14 +250,11 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) if (retval < 0 || size != BUFFER_LENGTH) { radio->stereo = -1; - mutex_unlock(&radio->lock); return retval; } radio->stereo = 1; - mutex_unlock(&radio->lock); - return retval; } @@ -325,12 +297,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct amradio_device *radio = video_get_drvdata(video_devdata(file)); int retval; + mutex_lock(&radio->lock); + /* safety check */ - if (radio->removed) - return -EIO; + if (radio->removed) { + retval = -EIO; + goto unlock; + } - if (v->index > 0) - return -EINVAL; + if (v->index > 0) { + retval = -EINVAL; + goto unlock; + } /* TODO: Add function which look is signal stereo or not * amradio_getstat(radio); @@ -357,7 +335,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, v->audmode = V4L2_TUNER_MODE_MONO; v->signal = 0xffff; /* Can't get the signal strength, sad.. */ v->afc = 0; /* Don't know what is this */ - return 0; + +unlock: + mutex_unlock(&radio->lock); + return retval; } /* vidioc_s_tuner - set tuner attributes */ @@ -367,12 +348,18 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct amradio_device *radio = video_get_drvdata(video_devdata(file)); int retval; + mutex_lock(&radio->lock); + /* safety check */ - if (radio->removed) - return -EIO; + if (radio->removed) { + retval = -EIO; + goto unlock; + } - if (v->index > 0) - return -EINVAL; + if (v->index > 0) { + retval = -EINVAL; + goto unlock; + } /* mono/stereo selector */ switch (v->audmode) { @@ -389,10 +376,12 @@ static int vidioc_s_tuner(struct file *file, void *priv, "set stereo failed\n"); break; default: - return -EINVAL; + retval = -EINVAL; } - return 0; +unlock: + mutex_unlock(&radio->lock); + return retval; } /* vidioc_s_frequency - set tuner radio frequency */ @@ -402,19 +391,24 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct amradio_device *radio = video_get_drvdata(video_devdata(file)); int retval; + mutex_lock(&radio->lock); + /* safety check */ - if (radio->removed) - return -EIO; + if (radio->removed) { + retval = -EIO; + goto unlock; + } - mutex_lock(&radio->lock); radio->curfreq = f->frequency; - mutex_unlock(&radio->lock); retval = amradio_setfreq(radio, radio->curfreq); if (retval < 0) amradio_dev_warn(&radio->videodev->dev, "set frequency failed\n"); - return 0; + +unlock: + mutex_unlock(&radio->lock); + return retval; } /* vidioc_g_frequency - get tuner radio frequency */ @@ -422,14 +416,22 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval = 0; + + mutex_lock(&radio->lock); /* safety check */ - if (radio->removed) - return -EIO; + if (radio->removed) { + retval = -EIO; + goto unlock; + } f->type = V4L2_TUNER_RADIO; f->frequency = radio->curfreq; - return 0; + +unlock: + mutex_unlock(&radio->lock); + return retval; } /* vidioc_queryctrl - enumerate control items */ @@ -449,17 +451,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval = -EINVAL; + + mutex_lock(&radio->lock); /* safety check */ - if (radio->removed) - return -EIO; + if (radio->removed) { + retval = -EIO; + goto unlock; + } switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = radio->muted; - return 0; + retval = 0; + break; } - return -EINVAL; + +unlock: + mutex_unlock(&radio->lock); + return retval; } /* vidioc_s_ctrl - set the value of a control */ @@ -467,11 +478,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); - int retval; + int retval = -EINVAL; + + mutex_lock(&radio->lock); /* safety check */ - if (radio->removed) - return -EIO; + if (radio->removed) { + retval = -EIO; + goto unlock; + } switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -480,19 +495,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv, if (retval < 0) { amradio_dev_warn(&radio->videodev->dev, "amradio_stop failed\n"); - return -1; } } else { retval = amradio_set_mute(radio, AMRADIO_START); if (retval < 0) { amradio_dev_warn(&radio->videodev->dev, "amradio_start failed\n"); - return -1; } } - return 0; + break; } - return -EINVAL; + +unlock: + mutex_unlock(&radio->lock); + return retval; } /* vidioc_g_audio - get audio attributes */ @@ -535,9 +551,14 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) static int usb_amradio_open(struct file *file) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); - int retval; + int retval = 0; - lock_kernel(); + mutex_lock(&radio->lock); + + if (radio->removed) { + retval = -EIO; + goto unlock; + } radio->users = 1; radio->muted = 1; @@ -547,8 +568,7 @@ static int usb_amradio_open(struct file *file) amradio_dev_warn(&radio->videodev->dev, "radio did not start up properly\n"); radio->users = 0; - unlock_kernel(); - return -EIO; + goto unlock; } retval = amradio_set_stereo(radio, WANT_STEREO); @@ -561,22 +581,25 @@ static int usb_amradio_open(struct file *file) amradio_dev_warn(&radio->videodev->dev, "set frequency failed\n"); - unlock_kernel(); - return 0; +unlock: + mutex_unlock(&radio->lock); + return retval; } /*close device */ static int usb_amradio_close(struct file *file) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); - int retval; - - if (!radio) - return -ENODEV; + int retval = 0; mutex_lock(&radio->lock); + + if (radio->removed) { + retval = -EIO; + goto unlock; + } + radio->users = 0; - mutex_unlock(&radio->lock); if (!radio->removed) { retval = amradio_set_mute(radio, AMRADIO_STOP); @@ -585,7 +608,9 @@ static int usb_amradio_close(struct file *file) "amradio_stop failed\n"); } - return 0; +unlock: + mutex_unlock(&radio->lock); + return retval; } /* 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) struct amradio_device *radio = usb_get_intfdata(intf); int retval; + mutex_lock(&radio->lock); + retval = amradio_set_mute(radio, AMRADIO_STOP); if (retval < 0) dev_warn(&intf->dev, "amradio_stop failed\n"); dev_info(&intf->dev, "going into suspend..\n"); + mutex_unlock(&radio->lock); return 0; } @@ -609,12 +637,15 @@ static int usb_amradio_resume(struct usb_interface *intf) struct amradio_device *radio = usb_get_intfdata(intf); int retval; + mutex_lock(&radio->lock); + retval = amradio_set_mute(radio, AMRADIO_START); if (retval < 0) dev_warn(&intf->dev, "amradio_start failed\n"); dev_info(&intf->dev, "coming out of suspend..\n"); + mutex_unlock(&radio->lock); return 0; } -- GitLab