aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/printer.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 2c32bd08ee7..ecc1410073f 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -390,9 +390,12 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
/* normal completion */
case 0:
- list_add_tail(&req->list, &dev->rx_buffers);
- wake_up_interruptible(&dev->rx_wait);
- DBG(dev, "G_Printer : rx length %d\n", req->actual);
+ if (req->actual > 0) {
+ list_add_tail(&req->list, &dev->rx_buffers);
+ DBG(dev, "G_Printer : rx length %d\n", req->actual);
+ } else {
+ list_add(&req->list, &dev->rx_reqs);
+ }
break;
/* software-driven interface shutdown */
@@ -417,6 +420,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
list_add(&req->list, &dev->rx_reqs);
break;
}
+
+ wake_up_interruptible(&dev->rx_wait);
spin_unlock_irqrestore(&dev->lock, flags);
}
@@ -494,6 +499,39 @@ printer_close(struct inode *inode, struct file *fd)
return 0;
}
+/* This function must be called with interrupts turned off. */
+static void
+setup_rx_reqs(struct printer_dev *dev)
+{
+ struct usb_request *req;
+
+ while (likely(!list_empty(&dev->rx_reqs))) {
+ int error;
+
+ req = container_of(dev->rx_reqs.next,
+ struct usb_request, list);
+ list_del_init(&req->list);
+
+ /* The USB Host sends us whatever amount of data it wants to
+ * so we always set the length field to the full USB_BUFSIZE.
+ * If the amount of data is more than the read() caller asked
+ * for it will be stored in the request buffer until it is
+ * asked for by read().
+ */
+ req->length = USB_BUFSIZE;
+ req->complete = rx_complete;
+
+ error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+ if (error) {
+ DBG(dev, "rx submit --> %d\n", error);
+ list_add(&req->list, &dev->rx_reqs);
+ break;
+ } else {
+ list_add(&req->list, &dev->rx_reqs_active);
+ }
+ }
+}
+
static ssize_t
printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
@@ -522,31 +560,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
*/
dev->reset_printer = 0;
- while (likely(!list_empty(&dev->rx_reqs))) {
- int error;
-
- req = container_of(dev->rx_reqs.next,
- struct usb_request, list);
- list_del_init(&req->list);
-
- /* The USB Host sends us whatever amount of data it wants to
- * so we always set the length field to the full USB_BUFSIZE.
- * If the amount of data is more than the read() caller asked
- * for it will be stored in the request buffer until it is
- * asked for by read().
- */
- req->length = USB_BUFSIZE;
- req->complete = rx_complete;
-
- error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
- if (error) {
- DBG(dev, "rx submit --> %d\n", error);
- list_add(&req->list, &dev->rx_reqs);
- break;
- } else {
- list_add(&req->list, &dev->rx_reqs_active);
- }
- }
+ setup_rx_reqs(dev);
bytes_copied = 0;
current_rx_req = dev->current_rx_req;
@@ -615,9 +629,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irqsave(&dev->lock, flags);
- /* We've disconnected or reset free the req and buffer */
+ /* We've disconnected or reset so return. */
if (dev->reset_printer) {
- printer_req_free(dev->out_ep, current_rx_req);
+ list_add(&current_rx_req->list, &dev->rx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
spin_unlock(&dev->lock_printer_io);
return -EAGAIN;
@@ -735,7 +749,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
/* We've disconnected or reset so free the req and buffer */
if (dev->reset_printer) {
- printer_req_free(dev->in_ep, req);
+ list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
spin_unlock(&dev->lock_printer_io);
return -EAGAIN;
@@ -791,6 +805,12 @@ printer_poll(struct file *fd, poll_table *wait)
unsigned long flags;
int status = 0;
+ spin_lock(&dev->lock_printer_io);
+ spin_lock_irqsave(&dev->lock, flags);
+ setup_rx_reqs(dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+
poll_wait(fd, &dev->rx_wait, wait);
poll_wait(fd, &dev->tx_wait, wait);
@@ -798,7 +818,8 @@ printer_poll(struct file *fd, poll_table *wait)
if (likely(!list_empty(&dev->tx_reqs)))
status |= POLLOUT | POLLWRNORM;
- if (likely(!list_empty(&dev->rx_buffers)))
+ if (likely(dev->current_rx_bytes) ||
+ likely(!list_empty(&dev->rx_buffers)))
status |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1084,6 +1105,7 @@ static void printer_soft_reset(struct printer_dev *dev)
if (usb_ep_enable(dev->out_ep, dev->out))
DBG(dev, "Failed to enable USB out_ep\n");
+ wake_up_interruptible(&dev->rx_wait);
wake_up_interruptible(&dev->tx_wait);
wake_up_interruptible(&dev->tx_flush_wait);
}