diff options
| author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-11-19 04:17:44 -0500 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-11-20 14:20:14 -0500 |
| commit | f2a2e4910502e866833732f31ee697d15b3e56fd (patch) | |
| tree | 0679969d675d9e785c6c92a3625ce8df759e0cc3 | |
| parent | c4a98793a63c423c9e1af51822325969e23c16d4 (diff) | |
V4L/DVB (9647): em28xx: void having two concurrent control URB's
Now that we have a polling task for IR, there's a race condition, since
IR can be polling while other operations are being doing. Also, we are
now sharing the same urb_buf for both read and write control urb
operations. So, we need a mutex.
Thanks to Davin Heitmueller <devin.heitmueller@gmail.com> for warning me.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-core.c | 12 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 1 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 1 |
3 files changed, 12 insertions, 2 deletions
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 9551b8ab8c44..15e2b525310d 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
| @@ -76,18 +76,22 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, | |||
| 76 | 76 | ||
| 77 | em28xx_regdbg("req=%02x, reg=%02x ", req, reg); | 77 | em28xx_regdbg("req=%02x, reg=%02x ", req, reg); |
| 78 | 78 | ||
| 79 | mutex_lock(&dev->ctrl_urb_lock); | ||
| 79 | ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, | 80 | ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, |
| 80 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 81 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 81 | 0x0000, reg, dev->urb_buf, len, HZ); | 82 | 0x0000, reg, dev->urb_buf, len, HZ); |
| 82 | if (ret < 0) { | 83 | if (ret < 0) { |
| 83 | if (reg_debug) | 84 | if (reg_debug) |
| 84 | printk(" failed!\n"); | 85 | printk(" failed!\n"); |
| 86 | mutex_unlock(&dev->ctrl_urb_lock); | ||
| 85 | return ret; | 87 | return ret; |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 88 | if (len) | 90 | if (len) |
| 89 | memcpy(buf, dev->urb_buf, len); | 91 | memcpy(buf, dev->urb_buf, len); |
| 90 | 92 | ||
| 93 | mutex_unlock(&dev->ctrl_urb_lock); | ||
| 94 | |||
| 91 | if (reg_debug) { | 95 | if (reg_debug) { |
| 92 | printk("%02x values: ", ret); | 96 | printk("%02x values: ", ret); |
| 93 | for (byte = 0; byte < len; byte++) | 97 | for (byte = 0; byte < len; byte++) |
| @@ -112,16 +116,18 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) | |||
| 112 | 116 | ||
| 113 | em28xx_regdbg("req=%02x, reg=%02x:", req, reg); | 117 | em28xx_regdbg("req=%02x, reg=%02x:", req, reg); |
| 114 | 118 | ||
| 119 | mutex_lock(&dev->ctrl_urb_lock); | ||
| 115 | ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, | 120 | ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, |
| 116 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 121 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 117 | 0x0000, reg, dev->urb_buf, 1, HZ); | 122 | 0x0000, reg, dev->urb_buf, 1, HZ); |
| 123 | val = dev->urb_buf[0]; | ||
| 124 | mutex_unlock(&dev->ctrl_urb_lock); | ||
| 125 | |||
| 118 | if (ret < 0) { | 126 | if (ret < 0) { |
| 119 | printk(" failed!\n"); | 127 | printk(" failed!\n"); |
| 120 | return ret; | 128 | return ret; |
| 121 | } | 129 | } |
| 122 | 130 | ||
| 123 | val = dev->urb_buf[0]; | ||
| 124 | |||
| 125 | if (reg_debug) | 131 | if (reg_debug) |
| 126 | printk("%02x\n", (unsigned char) val); | 132 | printk("%02x\n", (unsigned char) val); |
| 127 | 133 | ||
| @@ -156,10 +162,12 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, | |||
| 156 | printk("\n"); | 162 | printk("\n"); |
| 157 | } | 163 | } |
| 158 | 164 | ||
| 165 | mutex_lock(&dev->ctrl_urb_lock); | ||
| 159 | memcpy(dev->urb_buf, buf, len); | 166 | memcpy(dev->urb_buf, buf, len); |
| 160 | ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, | 167 | ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, |
| 161 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 168 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 162 | 0x0000, reg, dev->urb_buf, len, HZ); | 169 | 0x0000, reg, dev->urb_buf, len, HZ); |
| 170 | mutex_unlock(&dev->ctrl_urb_lock); | ||
| 163 | 171 | ||
| 164 | if (dev->wait_after_write) | 172 | if (dev->wait_after_write) |
| 165 | msleep(dev->wait_after_write); | 173 | msleep(dev->wait_after_write); |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index bca5955339b8..c32fc7d24a42 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
| @@ -1936,6 +1936,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
| 1936 | 1936 | ||
| 1937 | dev->udev = udev; | 1937 | dev->udev = udev; |
| 1938 | mutex_init(&dev->lock); | 1938 | mutex_init(&dev->lock); |
| 1939 | mutex_init(&dev->ctrl_urb_lock); | ||
| 1939 | spin_lock_init(&dev->slock); | 1940 | spin_lock_init(&dev->slock); |
| 1940 | init_waitqueue_head(&dev->open); | 1941 | init_waitqueue_head(&dev->open); |
| 1941 | init_waitqueue_head(&dev->wait_frame); | 1942 | init_waitqueue_head(&dev->wait_frame); |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 1adf3d9d9bff..5956e9b3062f 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
| @@ -433,6 +433,7 @@ struct em28xx { | |||
| 433 | 433 | ||
| 434 | /* locks */ | 434 | /* locks */ |
| 435 | struct mutex lock; | 435 | struct mutex lock; |
| 436 | struct mutex ctrl_urb_lock; /* protects urb_buf */ | ||
| 436 | /* spinlock_t queue_lock; */ | 437 | /* spinlock_t queue_lock; */ |
| 437 | struct list_head inqueue, outqueue; | 438 | struct list_head inqueue, outqueue; |
| 438 | wait_queue_head_t open, wait_frame, wait_stream; | 439 | wait_queue_head_t open, wait_frame, wait_stream; |
