public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] radio-mr800: fix unplug
@ 2008-11-19  0:36 Alexey Klimov
  2008-11-20 15:53 ` David Ellingsworth
  0 siblings, 1 reply; 12+ messages in thread
From: Alexey Klimov @ 2008-11-19  0:36 UTC (permalink / raw)
  To: video4linux-list; +Cc: Mauro Carvalho Chehab


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2008-12-12  3:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-19  0:36 [PATCH 1/1] radio-mr800: fix unplug Alexey Klimov
2008-11-20 15:53 ` 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox