Commit 4aebc289 authored by David Ellingsworth's avatar David Ellingsworth Committed by Mauro Carvalho Chehab

V4L/DVB (13060): radio-mr800: implement proper locking

Implement proper locking
Signed-off-by: default avatarDavid Ellingsworth <david@identd.dyndns.org>
Acked-by: default avatarAlexey Klimov <klimov.linux@gmail.com>
Signed-off-by: default avatarDouglas Schilling Landgraf <dougsland@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0f017212
...@@ -168,11 +168,7 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) ...@@ -168,11 +168,7 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
int retval; int retval;
int size; int size;
/* safety check */ BUG_ON(!mutex_is_locked(&radio->lock));
if (radio->removed)
return -EIO;
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00; radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55; radio->buffer[1] = 0x55;
...@@ -186,15 +182,11 @@ static int amradio_set_mute(struct amradio_device *radio, char argument) ...@@ -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), retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
if (retval < 0 || size != BUFFER_LENGTH) { if (retval < 0 || size != BUFFER_LENGTH)
mutex_unlock(&radio->lock);
return retval; return retval;
}
radio->muted = argument; radio->muted = argument;
mutex_unlock(&radio->lock);
return retval; return retval;
} }
...@@ -205,11 +197,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) ...@@ -205,11 +197,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
int size; int size;
unsigned short freq_send = 0x10 + (freq >> 3) / 25; unsigned short freq_send = 0x10 + (freq >> 3) / 25;
/* safety check */ BUG_ON(!mutex_is_locked(&radio->lock));
if (radio->removed)
return -EIO;
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00; radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55; radio->buffer[1] = 0x55;
...@@ -223,10 +211,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) ...@@ -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), retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
if (retval < 0 || size != BUFFER_LENGTH) { if (retval < 0 || size != BUFFER_LENGTH)
mutex_unlock(&radio->lock);
return retval; return retval;
}
/* frequency is calculated from freq_send and placed in first 2 bytes */ /* frequency is calculated from freq_send and placed in first 2 bytes */
radio->buffer[0] = (freq_send >> 8) & 0xff; radio->buffer[0] = (freq_send >> 8) & 0xff;
...@@ -240,13 +226,6 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) ...@@ -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), retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); (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; return retval;
} }
...@@ -255,11 +234,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) ...@@ -255,11 +234,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
int retval; int retval;
int size; int size;
/* safety check */ BUG_ON(!mutex_is_locked(&radio->lock));
if (radio->removed)
return -EIO;
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00; radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55; radio->buffer[1] = 0x55;
...@@ -275,14 +250,11 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument) ...@@ -275,14 +250,11 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
if (retval < 0 || size != BUFFER_LENGTH) { if (retval < 0 || size != BUFFER_LENGTH) {
radio->stereo = -1; radio->stereo = -1;
mutex_unlock(&radio->lock);
return retval; return retval;
} }
radio->stereo = 1; radio->stereo = 1;
mutex_unlock(&radio->lock);
return retval; return retval;
} }
...@@ -325,12 +297,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, ...@@ -325,12 +297,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval; int retval;
mutex_lock(&radio->lock);
/* safety check */ /* safety check */
if (radio->removed) if (radio->removed) {
return -EIO; retval = -EIO;
goto unlock;
}
if (v->index > 0) if (v->index > 0) {
return -EINVAL; retval = -EINVAL;
goto unlock;
}
/* TODO: Add function which look is signal stereo or not /* TODO: Add function which look is signal stereo or not
* amradio_getstat(radio); * amradio_getstat(radio);
...@@ -357,7 +335,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, ...@@ -357,7 +335,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->audmode = V4L2_TUNER_MODE_MONO; v->audmode = V4L2_TUNER_MODE_MONO;
v->signal = 0xffff; /* Can't get the signal strength, sad.. */ v->signal = 0xffff; /* Can't get the signal strength, sad.. */
v->afc = 0; /* Don't know what is this */ v->afc = 0; /* Don't know what is this */
return 0;
unlock:
mutex_unlock(&radio->lock);
return retval;
} }
/* vidioc_s_tuner - set tuner attributes */ /* vidioc_s_tuner - set tuner attributes */
...@@ -367,12 +348,18 @@ static int vidioc_s_tuner(struct file *file, void *priv, ...@@ -367,12 +348,18 @@ static int vidioc_s_tuner(struct file *file, void *priv,
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval; int retval;
mutex_lock(&radio->lock);
/* safety check */ /* safety check */
if (radio->removed) if (radio->removed) {
return -EIO; retval = -EIO;
goto unlock;
}
if (v->index > 0) if (v->index > 0) {
return -EINVAL; retval = -EINVAL;
goto unlock;
}
/* mono/stereo selector */ /* mono/stereo selector */
switch (v->audmode) { switch (v->audmode) {
...@@ -389,10 +376,12 @@ static int vidioc_s_tuner(struct file *file, void *priv, ...@@ -389,10 +376,12 @@ static int vidioc_s_tuner(struct file *file, void *priv,
"set stereo failed\n"); "set stereo failed\n");
break; break;
default: default:
return -EINVAL; retval = -EINVAL;
} }
return 0; unlock:
mutex_unlock(&radio->lock);
return retval;
} }
/* vidioc_s_frequency - set tuner radio frequency */ /* vidioc_s_frequency - set tuner radio frequency */
...@@ -402,19 +391,24 @@ static int vidioc_s_frequency(struct file *file, void *priv, ...@@ -402,19 +391,24 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval; int retval;
mutex_lock(&radio->lock);
/* safety check */ /* safety check */
if (radio->removed) if (radio->removed) {
return -EIO; retval = -EIO;
goto unlock;
}
mutex_lock(&radio->lock);
radio->curfreq = f->frequency; radio->curfreq = f->frequency;
mutex_unlock(&radio->lock);
retval = amradio_setfreq(radio, radio->curfreq); retval = amradio_setfreq(radio, radio->curfreq);
if (retval < 0) if (retval < 0)
amradio_dev_warn(&radio->videodev->dev, amradio_dev_warn(&radio->videodev->dev,
"set frequency failed\n"); "set frequency failed\n");
return 0;
unlock:
mutex_unlock(&radio->lock);
return retval;
} }
/* vidioc_g_frequency - get tuner radio frequency */ /* vidioc_g_frequency - get tuner radio frequency */
...@@ -422,14 +416,22 @@ static int vidioc_g_frequency(struct file *file, void *priv, ...@@ -422,14 +416,22 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f) struct v4l2_frequency *f)
{ {
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval = 0;
mutex_lock(&radio->lock);
/* safety check */ /* safety check */
if (radio->removed) if (radio->removed) {
return -EIO; retval = -EIO;
goto unlock;
}
f->type = V4L2_TUNER_RADIO; f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq; f->frequency = radio->curfreq;
return 0;
unlock:
mutex_unlock(&radio->lock);
return retval;
} }
/* vidioc_queryctrl - enumerate control items */ /* vidioc_queryctrl - enumerate control items */
...@@ -449,17 +451,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv, ...@@ -449,17 +451,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl) struct v4l2_control *ctrl)
{ {
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval = -EINVAL;
mutex_lock(&radio->lock);
/* safety check */ /* safety check */
if (radio->removed) if (radio->removed) {
return -EIO; retval = -EIO;
goto unlock;
}
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_MUTE:
ctrl->value = radio->muted; 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 */ /* vidioc_s_ctrl - set the value of a control */
...@@ -467,11 +478,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv, ...@@ -467,11 +478,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl) struct v4l2_control *ctrl)
{ {
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval; int retval = -EINVAL;
mutex_lock(&radio->lock);
/* safety check */ /* safety check */
if (radio->removed) if (radio->removed) {
return -EIO; retval = -EIO;
goto unlock;
}
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_MUTE:
...@@ -480,19 +495,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv, ...@@ -480,19 +495,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
if (retval < 0) { if (retval < 0) {
amradio_dev_warn(&radio->videodev->dev, amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n"); "amradio_stop failed\n");
return -1;
} }
} else { } else {
retval = amradio_set_mute(radio, AMRADIO_START); retval = amradio_set_mute(radio, AMRADIO_START);
if (retval < 0) { if (retval < 0) {
amradio_dev_warn(&radio->videodev->dev, amradio_dev_warn(&radio->videodev->dev,
"amradio_start failed\n"); "amradio_start failed\n");
return -1;
} }
} }
return 0; break;
} }
return -EINVAL;
unlock:
mutex_unlock(&radio->lock);
return retval;
} }
/* vidioc_g_audio - get audio attributes */ /* vidioc_g_audio - get audio attributes */
...@@ -535,9 +551,14 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) ...@@ -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) static int usb_amradio_open(struct file *file)
{ {
struct amradio_device *radio = video_get_drvdata(video_devdata(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->users = 1;
radio->muted = 1; radio->muted = 1;
...@@ -547,8 +568,7 @@ static int usb_amradio_open(struct file *file) ...@@ -547,8 +568,7 @@ static int usb_amradio_open(struct file *file)
amradio_dev_warn(&radio->videodev->dev, amradio_dev_warn(&radio->videodev->dev,
"radio did not start up properly\n"); "radio did not start up properly\n");
radio->users = 0; radio->users = 0;
unlock_kernel(); goto unlock;
return -EIO;
} }
retval = amradio_set_stereo(radio, WANT_STEREO); retval = amradio_set_stereo(radio, WANT_STEREO);
...@@ -561,22 +581,25 @@ static int usb_amradio_open(struct file *file) ...@@ -561,22 +581,25 @@ static int usb_amradio_open(struct file *file)
amradio_dev_warn(&radio->videodev->dev, amradio_dev_warn(&radio->videodev->dev,
"set frequency failed\n"); "set frequency failed\n");
unlock_kernel(); unlock:
return 0; mutex_unlock(&radio->lock);
return retval;
} }
/*close device */ /*close device */
static int usb_amradio_close(struct file *file) static int usb_amradio_close(struct file *file)
{ {
struct amradio_device *radio = video_get_drvdata(video_devdata(file)); struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval; int retval = 0;
if (!radio)
return -ENODEV;
mutex_lock(&radio->lock); mutex_lock(&radio->lock);
if (radio->removed) {
retval = -EIO;
goto unlock;
}
radio->users = 0; radio->users = 0;
mutex_unlock(&radio->lock);
if (!radio->removed) { if (!radio->removed) {
retval = amradio_set_mute(radio, AMRADIO_STOP); retval = amradio_set_mute(radio, AMRADIO_STOP);
...@@ -585,7 +608,9 @@ static int usb_amradio_close(struct file *file) ...@@ -585,7 +608,9 @@ static int usb_amradio_close(struct file *file)
"amradio_stop failed\n"); "amradio_stop failed\n");
} }
return 0; unlock:
mutex_unlock(&radio->lock);
return retval;
} }
/* Suspend device - stop device. Need to be checked and fixed */ /* 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,12 +619,15 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
struct amradio_device *radio = usb_get_intfdata(intf); struct amradio_device *radio = usb_get_intfdata(intf);
int retval; int retval;
mutex_lock(&radio->lock);
retval = amradio_set_mute(radio, AMRADIO_STOP); retval = amradio_set_mute(radio, AMRADIO_STOP);
if (retval < 0) if (retval < 0)
dev_warn(&intf->dev, "amradio_stop failed\n"); dev_warn(&intf->dev, "amradio_stop failed\n");
dev_info(&intf->dev, "going into suspend..\n"); dev_info(&intf->dev, "going into suspend..\n");
mutex_unlock(&radio->lock);
return 0; return 0;
} }
...@@ -609,12 +637,15 @@ static int usb_amradio_resume(struct usb_interface *intf) ...@@ -609,12 +637,15 @@ static int usb_amradio_resume(struct usb_interface *intf)
struct amradio_device *radio = usb_get_intfdata(intf); struct amradio_device *radio = usb_get_intfdata(intf);
int retval; int retval;
mutex_lock(&radio->lock);
retval = amradio_set_mute(radio, AMRADIO_START); retval = amradio_set_mute(radio, AMRADIO_START);
if (retval < 0) if (retval < 0)
dev_warn(&intf->dev, "amradio_start failed\n"); dev_warn(&intf->dev, "amradio_start failed\n");
dev_info(&intf->dev, "coming out of suspend..\n"); dev_info(&intf->dev, "coming out of suspend..\n");
mutex_unlock(&radio->lock);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment