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 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 | */ |
847 | static int usblp_wwait(struct usblp *usblp, int nonblock) | 851 | static 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); |