Merge "usb: gadget: f_hid: Use spinlock instead of mutex"
This commit is contained in:
commit
8e9ed04da3
1 changed files with 34 additions and 23 deletions
|
@ -50,12 +50,12 @@ struct f_hidg {
|
||||||
|
|
||||||
/* recv report */
|
/* recv report */
|
||||||
struct list_head completed_out_req;
|
struct list_head completed_out_req;
|
||||||
spinlock_t spinlock;
|
spinlock_t read_spinlock;
|
||||||
wait_queue_head_t read_queue;
|
wait_queue_head_t read_queue;
|
||||||
unsigned int qlen;
|
unsigned int qlen;
|
||||||
|
|
||||||
/* send report */
|
/* send report */
|
||||||
struct mutex lock;
|
spinlock_t write_spinlock;
|
||||||
bool write_pending;
|
bool write_pending;
|
||||||
wait_queue_head_t write_queue;
|
wait_queue_head_t write_queue;
|
||||||
struct usb_request *req;
|
struct usb_request *req;
|
||||||
|
@ -204,20 +204,20 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||||
if (!access_ok(VERIFY_WRITE, buffer, count))
|
if (!access_ok(VERIFY_WRITE, buffer, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
spin_lock_irqsave(&hidg->read_spinlock, flags);
|
||||||
|
|
||||||
#define READ_COND (!list_empty(&hidg->completed_out_req))
|
#define READ_COND (!list_empty(&hidg->completed_out_req))
|
||||||
|
|
||||||
/* wait for at least one buffer to complete */
|
/* wait for at least one buffer to complete */
|
||||||
while (!READ_COND) {
|
while (!READ_COND) {
|
||||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
spin_unlock_irqrestore(&hidg->read_spinlock, flags);
|
||||||
if (file->f_flags & O_NONBLOCK)
|
if (file->f_flags & O_NONBLOCK)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
if (wait_event_interruptible(hidg->read_queue, READ_COND))
|
if (wait_event_interruptible(hidg->read_queue, READ_COND))
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
spin_lock_irqsave(&hidg->read_spinlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pick the first one */
|
/* pick the first one */
|
||||||
|
@ -232,7 +232,7 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||||
|
|
||||||
req = list->req;
|
req = list->req;
|
||||||
count = min_t(unsigned int, count, req->actual - list->pos);
|
count = min_t(unsigned int, count, req->actual - list->pos);
|
||||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
spin_unlock_irqrestore(&hidg->read_spinlock, flags);
|
||||||
|
|
||||||
/* copy to user outside spinlock */
|
/* copy to user outside spinlock */
|
||||||
count -= copy_to_user(buffer, req->buf + list->pos, count);
|
count -= copy_to_user(buffer, req->buf + list->pos, count);
|
||||||
|
@ -254,9 +254,9 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
spin_lock_irqsave(&hidg->read_spinlock, flags);
|
||||||
list_add(&list->list, &hidg->completed_out_req);
|
list_add(&list->list, &hidg->completed_out_req);
|
||||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
spin_unlock_irqrestore(&hidg->read_spinlock, flags);
|
||||||
|
|
||||||
wake_up(&hidg->read_queue);
|
wake_up(&hidg->read_queue);
|
||||||
}
|
}
|
||||||
|
@ -267,13 +267,16 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||||
static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
|
static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
|
||||||
{
|
{
|
||||||
struct f_hidg *hidg = (struct f_hidg *)ep->driver_data;
|
struct f_hidg *hidg = (struct f_hidg *)ep->driver_data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (req->status != 0) {
|
if (req->status != 0) {
|
||||||
ERROR(hidg->func.config->cdev,
|
ERROR(hidg->func.config->cdev,
|
||||||
"End Point Request ERROR: %d\n", req->status);
|
"End Point Request ERROR: %d\n", req->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
||||||
hidg->write_pending = 0;
|
hidg->write_pending = 0;
|
||||||
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
wake_up(&hidg->write_queue);
|
wake_up(&hidg->write_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,18 +284,19 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
|
||||||
size_t count, loff_t *offp)
|
size_t count, loff_t *offp)
|
||||||
{
|
{
|
||||||
struct f_hidg *hidg = file->private_data;
|
struct f_hidg *hidg = file->private_data;
|
||||||
|
unsigned long flags;
|
||||||
ssize_t status = -ENOMEM;
|
ssize_t status = -ENOMEM;
|
||||||
|
|
||||||
if (!access_ok(VERIFY_READ, buffer, count))
|
if (!access_ok(VERIFY_READ, buffer, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
mutex_lock(&hidg->lock);
|
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
||||||
|
|
||||||
#define WRITE_COND (!hidg->write_pending)
|
#define WRITE_COND (!hidg->write_pending)
|
||||||
|
|
||||||
/* write queue */
|
/* write queue */
|
||||||
while (!WRITE_COND) {
|
while (!WRITE_COND) {
|
||||||
mutex_unlock(&hidg->lock);
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
if (file->f_flags & O_NONBLOCK)
|
if (file->f_flags & O_NONBLOCK)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
@ -300,17 +304,20 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
|
||||||
hidg->write_queue, WRITE_COND))
|
hidg->write_queue, WRITE_COND))
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
mutex_lock(&hidg->lock);
|
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hidg->write_pending = 1;
|
||||||
count = min_t(unsigned, count, hidg->report_length);
|
count = min_t(unsigned, count, hidg->report_length);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
status = copy_from_user(hidg->req->buf, buffer, count);
|
status = copy_from_user(hidg->req->buf, buffer, count);
|
||||||
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
ERROR(hidg->func.config->cdev,
|
ERROR(hidg->func.config->cdev,
|
||||||
"copy_from_user error\n");
|
"copy_from_user error\n");
|
||||||
mutex_unlock(&hidg->lock);
|
status = -EINVAL;
|
||||||
return -EINVAL;
|
goto release_write_pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
hidg->req->status = 0;
|
hidg->req->status = 0;
|
||||||
|
@ -318,19 +325,23 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
|
||||||
hidg->req->length = count;
|
hidg->req->length = count;
|
||||||
hidg->req->complete = f_hidg_req_complete;
|
hidg->req->complete = f_hidg_req_complete;
|
||||||
hidg->req->context = hidg;
|
hidg->req->context = hidg;
|
||||||
hidg->write_pending = 1;
|
|
||||||
|
|
||||||
status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
|
status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ERROR(hidg->func.config->cdev,
|
ERROR(hidg->func.config->cdev,
|
||||||
"usb_ep_queue error on int endpoint %zd\n", status);
|
"usb_ep_queue error on int endpoint %zd\n", status);
|
||||||
hidg->write_pending = 0;
|
goto release_write_pending;
|
||||||
wake_up(&hidg->write_queue);
|
|
||||||
} else {
|
} else {
|
||||||
status = count;
|
status = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&hidg->lock);
|
return status;
|
||||||
|
release_write_pending:
|
||||||
|
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
||||||
|
hidg->write_pending = 0;
|
||||||
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
|
|
||||||
|
wake_up(&hidg->write_queue);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -397,9 +408,9 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
|
||||||
|
|
||||||
req_list->req = req;
|
req_list->req = req;
|
||||||
|
|
||||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
spin_lock_irqsave(&hidg->read_spinlock, flags);
|
||||||
list_add_tail(&req_list->list, &hidg->completed_out_req);
|
list_add_tail(&req_list->list, &hidg->completed_out_req);
|
||||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
spin_unlock_irqrestore(&hidg->read_spinlock, flags);
|
||||||
|
|
||||||
wake_up(&hidg->read_queue);
|
wake_up(&hidg->read_queue);
|
||||||
break;
|
break;
|
||||||
|
@ -523,13 +534,13 @@ static void hidg_disable(struct usb_function *f)
|
||||||
usb_ep_disable(hidg->in_ep);
|
usb_ep_disable(hidg->in_ep);
|
||||||
usb_ep_disable(hidg->out_ep);
|
usb_ep_disable(hidg->out_ep);
|
||||||
|
|
||||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
spin_lock_irqsave(&hidg->read_spinlock, flags);
|
||||||
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
|
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
|
||||||
free_ep_req(hidg->out_ep, list->req);
|
free_ep_req(hidg->out_ep, list->req);
|
||||||
list_del(&list->list);
|
list_del(&list->list);
|
||||||
kfree(list);
|
kfree(list);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
spin_unlock_irqrestore(&hidg->read_spinlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||||
|
@ -678,8 +689,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||||
if (status)
|
if (status)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
mutex_init(&hidg->lock);
|
spin_lock_init(&hidg->write_spinlock);
|
||||||
spin_lock_init(&hidg->spinlock);
|
spin_lock_init(&hidg->read_spinlock);
|
||||||
init_waitqueue_head(&hidg->write_queue);
|
init_waitqueue_head(&hidg->write_queue);
|
||||||
init_waitqueue_head(&hidg->read_queue);
|
init_waitqueue_head(&hidg->read_queue);
|
||||||
INIT_LIST_HEAD(&hidg->completed_out_req);
|
INIT_LIST_HEAD(&hidg->completed_out_req);
|
||||||
|
|
Loading…
Add table
Reference in a new issue