diff options
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/usblp.c | 65 |
1 files changed, 39 insertions, 26 deletions
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 5192cd9356d..30d5a1315cc 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -69,7 +69,6 @@ #define USBLP_DEVICE_ID_SIZE 1024 /* ioctls: */ -#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 @@ -159,10 +158,12 @@ struct usblp { int wstatus; /* bytes written or error */ int rstatus; /* bytes ready or error */ unsigned int quirks; /* quirks flags */ + unsigned int flags; /* mode flags */ unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ unsigned char sleeping; /* interface is suspended */ + unsigned char no_paper; /* Paper Out happened */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -325,6 +326,7 @@ static void usblp_bulk_write(struct urb *urb) usblp->wstatus = status; else usblp->wstatus = urb->actual_length; + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock(&usblp->lock); @@ -411,18 +413,10 @@ static int usblp_open(struct inode *inode, struct file *file) goto out; /* - * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? - * This is #if 0-ed because we *don't* want to fail an open - * just because the printer is off-line. + * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: + * - We do not want persistent state which close(2) does not clear + * - It is not used anyway, according to CUPS people */ -#if 0 - if ((retval = usblp_check_status(usblp, 0))) { - retval = retval > 1 ? -EIO : -ENOSPC; - goto out; - } -#else - retval = 0; -#endif retval = usb_autopm_get_interface(intf); if (retval < 0) @@ -463,6 +457,8 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + usblp->flags &= ~LP_ABORT; + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { @@ -486,7 +482,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); + | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -675,6 +671,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; + case LPABORT: + if (arg) + usblp->flags |= LP_ABORT; + else + usblp->flags &= ~LP_ABORT; + break; + default: retval = -ENOTTY; } @@ -730,6 +733,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock_irq(&usblp->lock); @@ -747,12 +751,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t /* Presume that it's going to complete well. */ writecount += transfer_length; } + if (rv == -ENOSPC) { + spin_lock_irq(&usblp->lock); + usblp->no_paper = 1; /* Mark for poll(2) */ + spin_unlock_irq(&usblp->lock); + writecount += transfer_length; + } /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } if (usblp->wstatus < 0) { - usblp_check_status(usblp, 0); rv = -EIO; goto collect_error; } @@ -838,32 +847,36 @@ done: * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use * select(2) or poll(2) to wait for the buffer to drain before closing. * Alternatively, set blocking mode with fcntl and issue a zero-size write. - * - * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot - * to check the return code for timeout expiration, so it had no effect. - * Apparently, it was intended to check for error conditons, such as out - * of paper. It is going to return when we settle things with CUPS. XXX */ static int usblp_wwait(struct usblp *usblp, int nonblock) { DECLARE_WAITQUEUE(waita, current); int rc; + int err = 0; add_wait_queue(&usblp->wwait, &waita); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_wtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } + rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); - if (rc == 0) + if (rc <= 0) break; - schedule(); + + if (usblp->flags & LP_ABORT) { + if (schedule_timeout(msecs_to_jiffies(5000)) == 0) { + err = usblp_check_status(usblp, err); + if (err == 1) { /* Paper out */ + rc = -ENOSPC; + break; + } + } + } else { + schedule(); + } } set_current_state(TASK_RUNNING); remove_wait_queue(&usblp->wwait, &waita); |