git.openpandora.org
/
pandora-kernel.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
cdc-wdm: Don't clear WDM_READ unless entire read buffer is emptied
[pandora-kernel.git]
/
drivers
/
usb
/
class
/
cdc-wdm.c
diff --git
a/drivers/usb/class/cdc-wdm.c
b/drivers/usb/class/cdc-wdm.c
index
efe6849
..
9eb71d8
100644
(file)
--- a/
drivers/usb/class/cdc-wdm.c
+++ b/
drivers/usb/class/cdc-wdm.c
@@
-57,6
+57,8
@@
MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_MAX 16
#define WDM_MAX 16
+/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
+#define WDM_DEFAULT_BUFSIZE 256
static DEFINE_MUTEX(wdm_mutex);
static DEFINE_MUTEX(wdm_mutex);
@@
-88,7
+90,8
@@
struct wdm_device {
int count;
dma_addr_t shandle;
dma_addr_t ihandle;
int count;
dma_addr_t shandle;
dma_addr_t ihandle;
- struct mutex lock;
+ struct mutex wlock;
+ struct mutex rlock;
wait_queue_head_t wait;
struct work_struct rxwork;
int werr;
wait_queue_head_t wait;
struct work_struct rxwork;
int werr;
@@
-323,7
+326,7
@@
static ssize_t wdm_write
}
/* concurrent writes and disconnect */
}
/* concurrent writes and disconnect */
- r = mutex_lock_interruptible(&desc->lock);
+ r = mutex_lock_interruptible(&desc->
w
lock);
rv = -ERESTARTSYS;
if (r) {
kfree(buf);
rv = -ERESTARTSYS;
if (r) {
kfree(buf);
@@
-386,7
+389,7
@@
static ssize_t wdm_write
out:
usb_autopm_put_interface(desc->intf);
outnp:
out:
usb_autopm_put_interface(desc->intf);
outnp:
- mutex_unlock(&desc->lock);
+ mutex_unlock(&desc->
w
lock);
outnl:
return rv < 0 ? rv : count;
}
outnl:
return rv < 0 ? rv : count;
}
@@
-394,16
+397,17
@@
outnl:
static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- int rv, cntr
= 0
;
+ int rv, cntr;
int i = 0;
struct wdm_device *desc = file->private_data;
int i = 0;
struct wdm_device *desc = file->private_data;
- rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */
+ rv = mutex_lock_interruptible(&desc->
r
lock); /*concurrent reads */
if (rv < 0)
return -ERESTARTSYS;
if (rv < 0)
return -ERESTARTSYS;
- if (desc->length == 0) {
+ cntr = ACCESS_ONCE(desc->length);
+ if (cntr == 0) {
desc->read = 0;
retry:
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
desc->read = 0;
retry:
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
@@
-453,17
+457,20
@@
retry:
spin_unlock_irq(&desc->iuspin);
goto retry;
}
spin_unlock_irq(&desc->iuspin);
goto retry;
}
- c
lear_bit(WDM_READ, &desc->flags)
;
+ c
ntr = desc->length
;
spin_unlock_irq(&desc->iuspin);
}
spin_unlock_irq(&desc->iuspin);
}
- cntr = count > desc->length ? desc->length : count;
+ if (cntr > count)
+ cntr = count;
rv = copy_to_user(buffer, desc->ubuf, cntr);
if (rv > 0) {
rv = -EFAULT;
goto err;
}
rv = copy_to_user(buffer, desc->ubuf, cntr);
if (rv > 0) {
rv = -EFAULT;
goto err;
}
+ spin_lock_irq(&desc->iuspin);
+
for (i = 0; i < desc->length - cntr; i++)
desc->ubuf[i] = desc->ubuf[i + cntr];
for (i = 0; i < desc->length - cntr; i++)
desc->ubuf[i] = desc->ubuf[i + cntr];
@@
-471,10
+478,13
@@
retry:
/* in case we had outstanding data */
if (!desc->length)
clear_bit(WDM_READ, &desc->flags);
/* in case we had outstanding data */
if (!desc->length)
clear_bit(WDM_READ, &desc->flags);
+
+ spin_unlock_irq(&desc->iuspin);
+
rv = cntr;
err:
rv = cntr;
err:
- mutex_unlock(&desc->lock);
+ mutex_unlock(&desc->
r
lock);
return rv;
}
return rv;
}
@@
-540,7
+550,8
@@
static int wdm_open(struct inode *inode, struct file *file)
}
intf->needs_remote_wakeup = 1;
}
intf->needs_remote_wakeup = 1;
- mutex_lock(&desc->lock);
+ /* using write lock to protect desc->count */
+ mutex_lock(&desc->wlock);
if (!desc->count++) {
desc->werr = 0;
desc->rerr = 0;
if (!desc->count++) {
desc->werr = 0;
desc->rerr = 0;
@@
-553,7
+564,7
@@
static int wdm_open(struct inode *inode, struct file *file)
} else {
rv = 0;
}
} else {
rv = 0;
}
- mutex_unlock(&desc->lock);
+ mutex_unlock(&desc->
w
lock);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
@@
-565,9
+576,11
@@
static int wdm_release(struct inode *inode, struct file *file)
struct wdm_device *desc = file->private_data;
mutex_lock(&wdm_mutex);
struct wdm_device *desc = file->private_data;
mutex_lock(&wdm_mutex);
- mutex_lock(&desc->lock);
+
+ /* using write lock to protect desc->count */
+ mutex_lock(&desc->wlock);
desc->count--;
desc->count--;
- mutex_unlock(&desc->lock);
+ mutex_unlock(&desc->
w
lock);
if (!desc->count) {
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
if (!desc->count) {
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
@@
-630,7
+643,7
@@
static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_cdc_dmm_desc *dmhd;
u8 *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
struct usb_cdc_dmm_desc *dmhd;
u8 *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
- u16 maxcom =
0
;
+ u16 maxcom =
WDM_DEFAULT_BUFSIZE
;
if (!buffer)
goto out;
if (!buffer)
goto out;
@@
-665,7
+678,8
@@
next_desc:
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc)
goto out;
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc)
goto out;
- mutex_init(&desc->lock);
+ mutex_init(&desc->rlock);
+ mutex_init(&desc->wlock);
spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait);
desc->wMaxCommand = maxcom;
spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait);
desc->wMaxCommand = maxcom;
@@
-716,7
+730,7
@@
next_desc:
goto err;
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
goto err;
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
- desc->
bMaxPacketSize0
,
+ desc->
wMaxCommand
,
GFP_KERNEL,
&desc->response->transfer_dma);
if (!desc->inbuf)
GFP_KERNEL,
&desc->response->transfer_dma);
if (!desc->inbuf)
@@
-779,11
+793,13
@@
static void wdm_disconnect(struct usb_interface *intf)
/* to terminate pending flushes */
clear_bit(WDM_IN_USE, &desc->flags);
spin_unlock_irqrestore(&desc->iuspin, flags);
/* to terminate pending flushes */
clear_bit(WDM_IN_USE, &desc->flags);
spin_unlock_irqrestore(&desc->iuspin, flags);
- mutex_lock(&desc->lock);
+ wake_up_all(&desc->wait);
+ mutex_lock(&desc->rlock);
+ mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
- mutex_unlock(&desc->lock);
-
wake_up_all(&desc->wait
);
+ mutex_unlock(&desc->
w
lock);
+
mutex_unlock(&desc->rlock
);
if (!desc->count)
cleanup(desc);
mutex_unlock(&wdm_mutex);
if (!desc->count)
cleanup(desc);
mutex_unlock(&wdm_mutex);
@@
-798,8
+814,10
@@
static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
/* if this is an autosuspend the caller does the locking */
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
/* if this is an autosuspend the caller does the locking */
- if (!PMSG_IS_AUTO(message))
- mutex_lock(&desc->lock);
+ if (!PMSG_IS_AUTO(message)) {
+ mutex_lock(&desc->rlock);
+ mutex_lock(&desc->wlock);
+ }
spin_lock_irq(&desc->iuspin);
if (PMSG_IS_AUTO(message) &&
spin_lock_irq(&desc->iuspin);
if (PMSG_IS_AUTO(message) &&
@@
-815,8
+833,10
@@
static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
}
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
}
- if (!PMSG_IS_AUTO(message))
- mutex_unlock(&desc->lock);
+ if (!PMSG_IS_AUTO(message)) {
+ mutex_unlock(&desc->wlock);
+ mutex_unlock(&desc->rlock);
+ }
return rv;
}
return rv;
}
@@
-854,7
+874,8
@@
static int wdm_pre_reset(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);
{
struct wdm_device *desc = usb_get_intfdata(intf);
- mutex_lock(&desc->lock);
+ mutex_lock(&desc->rlock);
+ mutex_lock(&desc->wlock);
kill_urbs(desc);
/*
kill_urbs(desc);
/*
@@
-876,7
+897,8
@@
static int wdm_post_reset(struct usb_interface *intf)
int rv;
rv = recover_from_urb_loss(desc);
int rv;
rv = recover_from_urb_loss(desc);
- mutex_unlock(&desc->lock);
+ mutex_unlock(&desc->wlock);
+ mutex_unlock(&desc->rlock);
return 0;
}
return 0;
}