Commit cc901bbb authored by Craig W. Nadler's avatar Craig W. Nadler Committed by Greg Kroah-Hartman

USB: g_printer bugfixes

G_PRINTER: Bug fix for blocking reads and a fix for a memory leak.

This fixes bugs in blocking IO calls. When the poll() entry point
is called receive transfers will be setup if they have not already
been. Another bug fix is that the poll() entry point now checks the
current receive buffer for data when reporting if any data had been
received. A memory leak was fixed that could have occurred when a
USB reset happened.
Signed-off-by: default avatarCraig W. Nadler <craig@nadler.us>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 119fc8c9
...@@ -390,9 +390,12 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -390,9 +390,12 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
/* normal completion */ /* normal completion */
case 0: case 0:
if (req->actual > 0) {
list_add_tail(&req->list, &dev->rx_buffers); list_add_tail(&req->list, &dev->rx_buffers);
wake_up_interruptible(&dev->rx_wait);
DBG(dev, "G_Printer : rx length %d\n", req->actual); DBG(dev, "G_Printer : rx length %d\n", req->actual);
} else {
list_add(&req->list, &dev->rx_reqs);
}
break; break;
/* software-driven interface shutdown */ /* software-driven interface shutdown */
...@@ -417,6 +420,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -417,6 +420,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
list_add(&req->list, &dev->rx_reqs); list_add(&req->list, &dev->rx_reqs);
break; break;
} }
wake_up_interruptible(&dev->rx_wait);
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
} }
...@@ -494,33 +499,11 @@ printer_close(struct inode *inode, struct file *fd) ...@@ -494,33 +499,11 @@ printer_close(struct inode *inode, struct file *fd)
return 0; return 0;
} }
static ssize_t /* This function must be called with interrupts turned off. */
printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) static void
setup_rx_reqs(struct printer_dev *dev)
{ {
struct printer_dev *dev = fd->private_data;
unsigned long flags;
size_t size;
size_t bytes_copied;
struct usb_request *req; struct usb_request *req;
/* This is a pointer to the current USB rx request. */
struct usb_request *current_rx_req;
/* This is the number of bytes in the current rx buffer. */
size_t current_rx_bytes;
/* This is a pointer to the current rx buffer. */
u8 *current_rx_buf;
if (len == 0)
return -EINVAL;
DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
spin_lock(&dev->lock_printer_io);
spin_lock_irqsave(&dev->lock, flags);
/* We will use this flag later to check if a printer reset happened
* after we turn interrupts back on.
*/
dev->reset_printer = 0;
while (likely(!list_empty(&dev->rx_reqs))) { while (likely(!list_empty(&dev->rx_reqs))) {
int error; int error;
...@@ -547,6 +530,37 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) ...@@ -547,6 +530,37 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
list_add(&req->list, &dev->rx_reqs_active); 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)
{
struct printer_dev *dev = fd->private_data;
unsigned long flags;
size_t size;
size_t bytes_copied;
struct usb_request *req;
/* This is a pointer to the current USB rx request. */
struct usb_request *current_rx_req;
/* This is the number of bytes in the current rx buffer. */
size_t current_rx_bytes;
/* This is a pointer to the current rx buffer. */
u8 *current_rx_buf;
if (len == 0)
return -EINVAL;
DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
spin_lock(&dev->lock_printer_io);
spin_lock_irqsave(&dev->lock, flags);
/* We will use this flag later to check if a printer reset happened
* after we turn interrupts back on.
*/
dev->reset_printer = 0;
setup_rx_reqs(dev);
bytes_copied = 0; bytes_copied = 0;
current_rx_req = dev->current_rx_req; 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) ...@@ -615,9 +629,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irqsave(&dev->lock, flags); 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) { 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_irqrestore(&dev->lock, flags);
spin_unlock(&dev->lock_printer_io); spin_unlock(&dev->lock_printer_io);
return -EAGAIN; return -EAGAIN;
...@@ -735,7 +749,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) ...@@ -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 */ /* We've disconnected or reset so free the req and buffer */
if (dev->reset_printer) { 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_irqrestore(&dev->lock, flags);
spin_unlock(&dev->lock_printer_io); spin_unlock(&dev->lock_printer_io);
return -EAGAIN; return -EAGAIN;
...@@ -791,6 +805,12 @@ printer_poll(struct file *fd, poll_table *wait) ...@@ -791,6 +805,12 @@ printer_poll(struct file *fd, poll_table *wait)
unsigned long flags; unsigned long flags;
int status = 0; 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->rx_wait, wait);
poll_wait(fd, &dev->tx_wait, wait); poll_wait(fd, &dev->tx_wait, wait);
...@@ -798,7 +818,8 @@ printer_poll(struct file *fd, poll_table *wait) ...@@ -798,7 +818,8 @@ printer_poll(struct file *fd, poll_table *wait)
if (likely(!list_empty(&dev->tx_reqs))) if (likely(!list_empty(&dev->tx_reqs)))
status |= POLLOUT | POLLWRNORM; 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; status |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -1084,6 +1105,7 @@ static void printer_soft_reset(struct printer_dev *dev) ...@@ -1084,6 +1105,7 @@ static void printer_soft_reset(struct printer_dev *dev)
if (usb_ep_enable(dev->out_ep, dev->out)) if (usb_ep_enable(dev->out_ep, dev->out))
DBG(dev, "Failed to enable USB out_ep\n"); 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_wait);
wake_up_interruptible(&dev->tx_flush_wait); wake_up_interruptible(&dev->tx_flush_wait);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment