aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/usblp.c
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2007-07-23 04:58:15 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:54:58 -0400
commit7f477358e2384c54b190cc3b6ce28277050a041b (patch)
treec22c0dc67906eefed165f7abcf90b3c9a820756c /drivers/usb/class/usblp.c
parentca337db6f92a32347172a20b96f6f51b7bb63b7c (diff)
usblp: Implement the ENOSPC convention
This patch implements a mode when a printer returns ENOSPC when it runs out of paper. The default remains the same as before. An application which wishes to use this function has to enable it explicitly with an ioctl LPABORT. This is done on a request by our (Fedora) CUPS guy, Tim Waugh. The API is similar enough to the lp0's one that CUPS works with both (but see below), but it's has some differences. Most importantly, the abort mode is persistent in case of lp0: once tunelp was run your cat fill blow up until you reboot or run tunelp again. For usblp, I made it so the abort mode is only in effect as long as device is open. This way you can mix and match CUPS and cat(1) freely and nothing bad happens even if you run out of paper. It is also safer in the face of any unexpected crashes. It has to be noted that mixing LPABORT and O_NONBLOCK is not advised. It probably does not do what you want: instead of returning -ENOSPC it will always return -EAGAIN (because it would otherwise block while waiting for the paper). Applications which use O_NONBLOCK should continue to use LPGETSTATUS like before. Finally, CUPS actually requires patching to take full advantage of this. It has several components; those which invoke LPABORT work, but some of them need the ioctl added. This is completely compatible, you can mix old CUPS and new kernels or vice versa. Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class/usblp.c')
-rw-r--r--drivers/usb/class/usblp.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 5192cd9356de..30d5a1315cc8 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -69,7 +69,6 @@
69#define USBLP_DEVICE_ID_SIZE 1024 69#define USBLP_DEVICE_ID_SIZE 1024
70 70
71/* ioctls: */ 71/* ioctls: */
72#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
73#define IOCNR_GET_DEVICE_ID 1 72#define IOCNR_GET_DEVICE_ID 1
74#define IOCNR_GET_PROTOCOLS 2 73#define IOCNR_GET_PROTOCOLS 2
75#define IOCNR_SET_PROTOCOL 3 74#define IOCNR_SET_PROTOCOL 3
@@ -159,10 +158,12 @@ struct usblp {
159 int wstatus; /* bytes written or error */ 158 int wstatus; /* bytes written or error */
160 int rstatus; /* bytes ready or error */ 159 int rstatus; /* bytes ready or error */
161 unsigned int quirks; /* quirks flags */ 160 unsigned int quirks; /* quirks flags */
161 unsigned int flags; /* mode flags */
162 unsigned char used; /* True if open */ 162 unsigned char used; /* True if open */
163 unsigned char present; /* True if not disconnected */ 163 unsigned char present; /* True if not disconnected */
164 unsigned char bidir; /* interface is bidirectional */ 164 unsigned char bidir; /* interface is bidirectional */
165 unsigned char sleeping; /* interface is suspended */ 165 unsigned char sleeping; /* interface is suspended */
166 unsigned char no_paper; /* Paper Out happened */
166 unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ 167 unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
167 /* first 2 bytes are (big-endian) length */ 168 /* first 2 bytes are (big-endian) length */
168}; 169};
@@ -325,6 +326,7 @@ static void usblp_bulk_write(struct urb *urb)
325 usblp->wstatus = status; 326 usblp->wstatus = status;
326 else 327 else
327 usblp->wstatus = urb->actual_length; 328 usblp->wstatus = urb->actual_length;
329 usblp->no_paper = 0;
328 usblp->wcomplete = 1; 330 usblp->wcomplete = 1;
329 wake_up(&usblp->wwait); 331 wake_up(&usblp->wwait);
330 spin_unlock(&usblp->lock); 332 spin_unlock(&usblp->lock);
@@ -411,18 +413,10 @@ static int usblp_open(struct inode *inode, struct file *file)
411 goto out; 413 goto out;
412 414
413 /* 415 /*
414 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? 416 * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
415 * This is #if 0-ed because we *don't* want to fail an open 417 * - We do not want persistent state which close(2) does not clear
416 * just because the printer is off-line. 418 * - It is not used anyway, according to CUPS people
417 */ 419 */
418#if 0
419 if ((retval = usblp_check_status(usblp, 0))) {
420 retval = retval > 1 ? -EIO : -ENOSPC;
421 goto out;
422 }
423#else
424 retval = 0;
425#endif
426 420
427 retval = usb_autopm_get_interface(intf); 421 retval = usb_autopm_get_interface(intf);
428 if (retval < 0) 422 if (retval < 0)
@@ -463,6 +457,8 @@ static int usblp_release(struct inode *inode, struct file *file)
463{ 457{
464 struct usblp *usblp = file->private_data; 458 struct usblp *usblp = file->private_data;
465 459
460 usblp->flags &= ~LP_ABORT;
461
466 mutex_lock (&usblp_mutex); 462 mutex_lock (&usblp_mutex);
467 usblp->used = 0; 463 usblp->used = 0;
468 if (usblp->present) { 464 if (usblp->present) {
@@ -486,7 +482,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
486 poll_wait(file, &usblp->wwait, wait); 482 poll_wait(file, &usblp->wwait, wait);
487 spin_lock_irqsave(&usblp->lock, flags); 483 spin_lock_irqsave(&usblp->lock, flags);
488 ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) 484 ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
489 | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); 485 | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
490 spin_unlock_irqrestore(&usblp->lock, flags); 486 spin_unlock_irqrestore(&usblp->lock, flags);
491 return ret; 487 return ret;
492} 488}
@@ -675,6 +671,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
675 retval = -EFAULT; 671 retval = -EFAULT;
676 break; 672 break;
677 673
674 case LPABORT:
675 if (arg)
676 usblp->flags |= LP_ABORT;
677 else
678 usblp->flags &= ~LP_ABORT;
679 break;
680
678 default: 681 default:
679 retval = -ENOTTY; 682 retval = -ENOTTY;
680 } 683 }
@@ -730,6 +733,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
730 if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { 733 if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
731 usblp->wstatus = 0; 734 usblp->wstatus = 0;
732 spin_lock_irq(&usblp->lock); 735 spin_lock_irq(&usblp->lock);
736 usblp->no_paper = 0;
733 usblp->wcomplete = 1; 737 usblp->wcomplete = 1;
734 wake_up(&usblp->wwait); 738 wake_up(&usblp->wwait);
735 spin_unlock_irq(&usblp->lock); 739 spin_unlock_irq(&usblp->lock);
@@ -747,12 +751,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
747 /* Presume that it's going to complete well. */ 751 /* Presume that it's going to complete well. */
748 writecount += transfer_length; 752 writecount += transfer_length;
749 } 753 }
754 if (rv == -ENOSPC) {
755 spin_lock_irq(&usblp->lock);
756 usblp->no_paper = 1; /* Mark for poll(2) */
757 spin_unlock_irq(&usblp->lock);
758 writecount += transfer_length;
759 }
750 /* Leave URB dangling, to be cleaned on close. */ 760 /* Leave URB dangling, to be cleaned on close. */
751 goto collect_error; 761 goto collect_error;
752 } 762 }
753 763
754 if (usblp->wstatus < 0) { 764 if (usblp->wstatus < 0) {
755 usblp_check_status(usblp, 0);
756 rv = -EIO; 765 rv = -EIO;
757 goto collect_error; 766 goto collect_error;
758 } 767 }
@@ -838,32 +847,36 @@ done:
838 * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use 847 * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
839 * select(2) or poll(2) to wait for the buffer to drain before closing. 848 * select(2) or poll(2) to wait for the buffer to drain before closing.
840 * Alternatively, set blocking mode with fcntl and issue a zero-size write. 849 * Alternatively, set blocking mode with fcntl and issue a zero-size write.
841 *
842 * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
843 * to check the return code for timeout expiration, so it had no effect.
844 * Apparently, it was intended to check for error conditons, such as out
845 * of paper. It is going to return when we settle things with CUPS. XXX
846 */ 850 */
847static int usblp_wwait(struct usblp *usblp, int nonblock) 851static int usblp_wwait(struct usblp *usblp, int nonblock)
848{ 852{
849 DECLARE_WAITQUEUE(waita, current); 853 DECLARE_WAITQUEUE(waita, current);
850 int rc; 854 int rc;
855 int err = 0;
851 856
852 add_wait_queue(&usblp->wwait, &waita); 857 add_wait_queue(&usblp->wwait, &waita);
853 for (;;) { 858 for (;;) {
859 set_current_state(TASK_INTERRUPTIBLE);
854 if (mutex_lock_interruptible(&usblp->mut)) { 860 if (mutex_lock_interruptible(&usblp->mut)) {
855 rc = -EINTR; 861 rc = -EINTR;
856 break; 862 break;
857 } 863 }
858 set_current_state(TASK_INTERRUPTIBLE); 864 rc = usblp_wtest(usblp, nonblock);
859 if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
860 mutex_unlock(&usblp->mut);
861 break;
862 }
863 mutex_unlock(&usblp->mut); 865 mutex_unlock(&usblp->mut);
864 if (rc == 0) 866 if (rc <= 0)
865 break; 867 break;
866 schedule(); 868
869 if (usblp->flags & LP_ABORT) {
870 if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
871 err = usblp_check_status(usblp, err);
872 if (err == 1) { /* Paper out */
873 rc = -ENOSPC;
874 break;
875 }
876 }
877 } else {
878 schedule();
879 }
867 } 880 }
868 set_current_state(TASK_RUNNING); 881 set_current_state(TASK_RUNNING);
869 remove_wait_queue(&usblp->wwait, &waita); 882 remove_wait_queue(&usblp->wwait, &waita);