From: Alexey Klimov <klimov.linux@gmail.com>
To: video4linux-list@redhat.com
Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
Subject: [PATCH 1/1] radio-mr800: fix unplug
Date: Wed, 19 Nov 2008 03:36:29 +0300 [thread overview]
Message-ID: <1227054989.2389.33.camel@tux.localhost> (raw)
This patch fixes problems(kernel oopses) with unplug of device while
it's working.
Patch adds disconnect_lock mutex, changes usb_amradio_close and
usb_amradio_disconnect functions and adds a lot of safety checks.
Signed-off-by: Alexey Klimov <klimov.linux@gmail.com>
---
diff -r 1536e16ffdf1 linux/drivers/media/radio/radio-mr800.c
--- a/linux/drivers/media/radio/radio-mr800.c Tue Nov 18 15:51:08 2008 -0200
+++ b/linux/drivers/media/radio/radio-mr800.c Wed Nov 19 03:27:59 2008 +0300
@@ -142,6 +142,7 @@
unsigned char *buffer;
struct mutex lock; /* buffer locking */
+ struct mutex disconnect_lock;
int curfreq;
int stereo;
int users;
@@ -210,6 +211,10 @@
int retval;
int size;
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00;
@@ -242,6 +247,10 @@
int retval;
int size;
unsigned short freq_send = 0x13 + (freq >> 3) / 25;
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
mutex_lock(&radio->lock);
@@ -296,18 +305,16 @@
{
struct amradio_device *radio = usb_get_intfdata(intf);
+ mutex_lock(&radio->disconnect_lock);
+ radio->removed = 1;
usb_set_intfdata(intf, NULL);
- if (radio) {
+ if (radio->users == 0) {
video_unregister_device(radio->videodev);
- radio->videodev = NULL;
- if (radio->users) {
- kfree(radio->buffer);
- kfree(radio);
- } else {
- radio->removed = 1;
- }
+ kfree(radio->buffer);
+ kfree(radio);
}
+ mutex_unlock(&radio->disconnect_lock);
}
/* vidioc_querycap - query device capabilities */
@@ -327,6 +334,10 @@
struct v4l2_tuner *v)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
if (v->index > 0)
return -EINVAL;
@@ -354,6 +365,12 @@
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
+ struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
if (v->index > 0)
return -EINVAL;
return 0;
@@ -364,6 +381,10 @@
struct v4l2_frequency *f)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
radio->curfreq = f->frequency;
if (amradio_setfreq(radio, radio->curfreq) < 0)
@@ -377,6 +398,10 @@
struct v4l2_frequency *f)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
@@ -404,6 +429,10 @@
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = radio->muted;
@@ -417,6 +446,10 @@
struct v4l2_control *ctrl)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -503,14 +536,26 @@
static int usb_amradio_close(struct inode *inode, struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
if (!radio)
return -ENODEV;
+
+ mutex_lock(&radio->disconnect_lock);
radio->users = 0;
if (radio->removed) {
+ video_unregister_device(radio->videodev);
kfree(radio->buffer);
kfree(radio);
+
+ } else {
+ retval = amradio_stop(radio);
+ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "amradio_stop failed\n");
}
+
+ mutex_unlock(&radio->disconnect_lock);
return 0;
}
@@ -610,6 +655,7 @@
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = 95.16 * FREQ_MUL;
+ mutex_init(&radio->disconnect_lock);
mutex_init(&radio->lock);
video_set_drvdata(radio->videodev, radio);
--
Best regards, Klimov Alexey
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
next reply other threads:[~2008-11-19 0:36 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-11-19 0:36 Alexey Klimov [this message]
2008-11-20 15:53 ` [PATCH 1/1] radio-mr800: fix unplug David Ellingsworth
2008-11-23 3:19 ` Alexey Klimov
2008-11-24 14:35 ` David Ellingsworth
2008-11-27 12:00 ` Alexey Klimov
2008-11-30 5:19 ` David Ellingsworth
2008-12-06 0:04 ` Alexey Klimov
2008-12-06 10:05 ` Mauro Carvalho Chehab
2008-12-09 1:35 ` [please review patch] dsbr100: fix unplug oops Alexey Klimov
2008-12-09 14:02 ` David Ellingsworth
2008-12-09 20:55 ` [PATCH] " Alexey Klimov
2008-12-12 3:05 ` Douglas Schilling Landgraf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1227054989.2389.33.camel@tux.localhost \
--to=klimov.linux@gmail.com \
--cc=mchehab@redhat.com \
--cc=video4linux-list@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox