From da185c3377a9a58922f8b3c052675964f5c4e566 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Wed, 19 Nov 2008 00:36:29 -0300 Subject: [PATCH] --- yaml --- r: 124287 b: refs/heads/master c: 3480130a502a528373f98fb852d2b3fc5f73e58b h: refs/heads/master i: 124285: be9fc8a8fbbd408a005024e78707cdc191b75bc8 124283: 69c537342cab121090a397e20c70848fa1648d6f 124279: 8e4ac67e6f1da1cdb2f9143e102d0a5dee0125a8 124271: c43bf9a1aa5e4fe0b407c87033ebbe7728a23917 124255: 372bb280709d2334b1f37f438499fceb02240cc3 124223: 7e782cc1a75d595e5ca247c990c1e530a7892265 124159: f3ab620f97dcb258ab299c2d96a11f96ea0fe268 v: v3 --- [refs] | 2 +- trunk/drivers/media/radio/radio-mr800.c | 62 +++++++++++++++++++++---- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/[refs] b/[refs] index b50b482e9825..5409a0ff5d6d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c7abfb47c9e19d63ce6f757afcb392c69ce09765 +refs/heads/master: 3480130a502a528373f98fb852d2b3fc5f73e58b diff --git a/trunk/drivers/media/radio/radio-mr800.c b/trunk/drivers/media/radio/radio-mr800.c index 61760019b033..7b7a1cfb121d 100644 --- a/trunk/drivers/media/radio/radio-mr800.c +++ b/trunk/drivers/media/radio/radio-mr800.c @@ -141,6 +141,7 @@ struct amradio_device { unsigned char *buffer; struct mutex lock; /* buffer locking */ + struct mutex disconnect_lock; int curfreq; int stereo; int users; @@ -207,6 +208,10 @@ static int amradio_stop(struct amradio_device *radio) int retval; int size; + /* safety check */ + if (radio->removed) + return -EIO; + mutex_lock(&radio->lock); radio->buffer[0] = 0x00; @@ -240,6 +245,10 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) int size; unsigned short freq_send = 0x13 + (freq >> 3) / 25; + /* safety check */ + if (radio->removed) + return -EIO; + mutex_lock(&radio->lock); radio->buffer[0] = 0x00; @@ -293,18 +302,16 @@ static void usb_amradio_disconnect(struct usb_interface *intf) { 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 */ @@ -325,6 +332,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + /* safety check */ + if (radio->removed) + return -EIO; + if (v->index > 0) return -EINVAL; @@ -351,6 +362,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, 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; @@ -362,6 +379,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, { 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) amradio_dev_warn(&radio->videodev->dev, @@ -375,6 +396,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, { 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; return 0; @@ -401,6 +426,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv, { 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; @@ -415,6 +444,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv, { 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: if (ctrl->value) { @@ -500,14 +533,26 @@ static int usb_amradio_open(struct inode *inode, struct file *file) 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; } @@ -607,6 +652,7 @@ static int usb_amradio_probe(struct usb_interface *intf, 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);