mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
USB: gadget: f_mtp: Add support for queueing multiple interrupt requests
Fixes problem sending "store added" events when there are multiple stores Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
/* number of tx and rx requests to allocate */
|
||||
#define TX_REQ_MAX 4
|
||||
#define RX_REQ_MAX 2
|
||||
#define INTR_REQ_MAX 5
|
||||
|
||||
/* ID for Microsoft MTP OS String */
|
||||
#define MTP_OS_STRING_ID 0xEE
|
||||
@@ -88,14 +89,13 @@ struct mtp_dev {
|
||||
atomic_t ioctl_excl;
|
||||
|
||||
struct list_head tx_idle;
|
||||
struct list_head intr_idle;
|
||||
|
||||
wait_queue_head_t read_wq;
|
||||
wait_queue_head_t write_wq;
|
||||
wait_queue_head_t intr_wq;
|
||||
struct usb_request *rx_req[RX_REQ_MAX];
|
||||
struct usb_request *intr_req;
|
||||
int rx_done;
|
||||
/* true if interrupt endpoint is busy */
|
||||
int intr_busy;
|
||||
|
||||
/* for processing MTP_SEND_FILE and MTP_RECEIVE_FILE
|
||||
* ioctls on a work queue
|
||||
@@ -372,11 +372,12 @@ static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct mtp_dev *dev = _mtp_dev;
|
||||
|
||||
DBG(dev->cdev, "mtp_complete_intr status: %d actual: %d\n",
|
||||
req->status, req->actual);
|
||||
dev->intr_busy = 0;
|
||||
if (req->status != 0)
|
||||
dev->state = STATE_ERROR;
|
||||
|
||||
mtp_req_put(dev, &dev->intr_idle, req);
|
||||
|
||||
wake_up(&dev->intr_wq);
|
||||
}
|
||||
|
||||
static int mtp_create_bulk_endpoints(struct mtp_dev *dev,
|
||||
@@ -442,11 +443,13 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev,
|
||||
req->complete = mtp_complete_out;
|
||||
dev->rx_req[i] = req;
|
||||
}
|
||||
req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE);
|
||||
if (!req)
|
||||
goto fail;
|
||||
req->complete = mtp_complete_intr;
|
||||
dev->intr_req = req;
|
||||
for (i = 0; i < INTR_REQ_MAX; i++) {
|
||||
req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE);
|
||||
if (!req)
|
||||
goto fail;
|
||||
req->complete = mtp_complete_intr;
|
||||
mtp_req_put(dev, &dev->intr_idle, req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -789,7 +792,7 @@ static void receive_file_work(struct work_struct *data)
|
||||
|
||||
static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event)
|
||||
{
|
||||
struct usb_request *req;
|
||||
struct usb_request *req= NULL;
|
||||
int ret;
|
||||
int length = event->length;
|
||||
|
||||
@@ -799,21 +802,20 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event)
|
||||
return -EINVAL;
|
||||
if (dev->state == STATE_OFFLINE)
|
||||
return -ENODEV;
|
||||
/* unfortunately an interrupt request might hang indefinitely if the host
|
||||
* is not listening on the interrupt endpoint, so instead of waiting,
|
||||
* we just fail if the endpoint is busy.
|
||||
*/
|
||||
if (dev->intr_busy)
|
||||
return -EBUSY;
|
||||
|
||||
req = dev->intr_req;
|
||||
if (copy_from_user(req->buf, (void __user *)event->data, length))
|
||||
ret = wait_event_interruptible_timeout(dev->intr_wq,
|
||||
(req = mtp_req_get(dev, &dev->intr_idle)), msecs_to_jiffies(1000));
|
||||
if (!req)
|
||||
return -ETIME;
|
||||
|
||||
if (copy_from_user(req->buf, (void __user *)event->data, length)) {
|
||||
mtp_req_put(dev, &dev->intr_idle, req);
|
||||
return -EFAULT;
|
||||
}
|
||||
req->length = length;
|
||||
dev->intr_busy = 1;
|
||||
ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL);
|
||||
if (ret)
|
||||
dev->intr_busy = 0;
|
||||
mtp_req_put(dev, &dev->intr_idle, req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1050,7 +1052,8 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
mtp_request_free(req, dev->ep_in);
|
||||
for (i = 0; i < RX_REQ_MAX; i++)
|
||||
mtp_request_free(dev->rx_req[i], dev->ep_out);
|
||||
mtp_request_free(dev->intr_req, dev->ep_intr);
|
||||
while ((req = mtp_req_get(dev, &dev->intr_idle)))
|
||||
mtp_request_free(req, dev->ep_intr);
|
||||
dev->state = STATE_OFFLINE;
|
||||
}
|
||||
|
||||
@@ -1243,9 +1246,11 @@ static int mtp_setup(void)
|
||||
spin_lock_init(&dev->lock);
|
||||
init_waitqueue_head(&dev->read_wq);
|
||||
init_waitqueue_head(&dev->write_wq);
|
||||
init_waitqueue_head(&dev->intr_wq);
|
||||
atomic_set(&dev->open_excl, 0);
|
||||
atomic_set(&dev->ioctl_excl, 0);
|
||||
INIT_LIST_HEAD(&dev->tx_idle);
|
||||
INIT_LIST_HEAD(&dev->intr_idle);
|
||||
|
||||
dev->wq = create_singlethread_workqueue("f_mtp");
|
||||
if (!dev->wq) {
|
||||
|
||||
Reference in New Issue
Block a user