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); mutex_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; current_rx_req = dev->current_rx_req; current_rx_bytes = dev->current_rx_bytes; current_rx_buf = dev->current_rx_buf; dev->current_rx_req = NULL; dev->current_rx_bytes = 0; dev->current_rx_buf = NULL; /* Check if there is any data in the read buffers. Please note that * current_rx_bytes is the number of bytes in the current rx buffer. * If it is zero then check if there are any other rx_buffers that * are on the completed list. We are only out of data if all rx * buffers are empty. */ if ((current_rx_bytes == 0) && (likely(list_empty(&dev->rx_buffers)))) { /* Turn interrupts back on before sleeping. */ spin_unlock_irqrestore(&dev->lock, flags); /* * If no data is available check if this is a NON-Blocking * call or not. */ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } /* Sleep until data is available */ wait_event_interruptible(dev->rx_wait, (likely(!list_empty(&dev->rx_buffers)))); spin_lock_irqsave(&dev->lock, flags); } /* We have data to return then copy it to the caller's buffer.*/ while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) && len) { if (current_rx_bytes == 0) { req = container_of(dev->rx_buffers.next, struct usb_request, list); list_del_init(&req->list); if (req->actual && req->buf) { current_rx_req = req; current_rx_bytes = req->actual; current_rx_buf = req->buf; } else { list_add(&req->list, &dev->rx_reqs); continue; } } /* Don't leave irqs off while doing memory copies */ spin_unlock_irqrestore(&dev->lock, flags); if (len > current_rx_bytes) size = current_rx_bytes; else size = len; size -= copy_to_user(buf, current_rx_buf, size); bytes_copied += size; len -= size; buf += size; spin_lock_irqsave(&dev->lock, flags); /* We've disconnected or reset so return. */ if (dev->reset_printer) { list_add(¤t_rx_req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->lock, flags); mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } /* If we not returning all the data left in this RX request * buffer then adjust the amount of data left in the buffer. * Othewise if we are done with this RX request buffer then * requeue it to get any incoming data from the USB host. */ if (size < current_rx_bytes) { current_rx_bytes -= size; current_rx_buf += size; } else { list_add(¤t_rx_req->list, &dev->rx_reqs); current_rx_bytes = 0; current_rx_buf = NULL; current_rx_req = NULL; } }
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; struct usb_request *current_rx_req; size_t current_rx_bytes; u8 *current_rx_buf; if (len == 0) return -EINVAL; DBG(dev, "printer_read trying to read %d bytes\n", (int)len); mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); dev->reset_printer = 0; setup_rx_reqs(dev); bytes_copied = 0; current_rx_req = dev->current_rx_req; current_rx_bytes = dev->current_rx_bytes; current_rx_buf = dev->current_rx_buf; dev->current_rx_req = NULL; dev->current_rx_bytes = 0; dev->current_rx_buf = NULL; if ((current_rx_bytes == 0) && (likely(list_empty(&dev->rx_buffers)))) { spin_unlock_irqrestore(&dev->lock, flags); if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } wait_event_interruptible(dev->rx_wait, (likely(!list_empty(&dev->rx_buffers)))); spin_lock_irqsave(&dev->lock, flags); } while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) && len) { if (current_rx_bytes == 0) { req = container_of(dev->rx_buffers.next, struct usb_request, list); list_del_init(&req->list); if (req->actual && req->buf) { current_rx_req = req; current_rx_bytes = req->actual; current_rx_buf = req->buf; } else { list_add(&req->list, &dev->rx_reqs); continue; } } spin_unlock_irqrestore(&dev->lock, flags); if (len > current_rx_bytes) size = current_rx_bytes; else size = len; size -= copy_to_user(buf, current_rx_buf, size); bytes_copied += size; len -= size; buf += size; spin_lock_irqsave(&dev->lock, flags); if (dev->reset_printer) { list_add(¤t_rx_req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->lock, flags); mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } if (size < current_rx_bytes) { current_rx_bytes -= size; current_rx_buf += size; } else { list_add(¤t_rx_req->list, &dev->rx_reqs); current_rx_bytes = 0; current_rx_buf = NULL; current_rx_req = NULL; } }