Skip to content

Commit 7f47735

Browse files
Pete Zaitcevgregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ca337db commit 7f47735

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

drivers/usb/class/usblp.c

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969
#define USBLP_DEVICE_ID_SIZE 1024
7070

7171
/* ioctls: */
72-
#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
7372
#define IOCNR_GET_DEVICE_ID 1
7473
#define IOCNR_GET_PROTOCOLS 2
7574
#define IOCNR_SET_PROTOCOL 3
@@ -159,10 +158,12 @@ struct usblp {
159158
int wstatus; /* bytes written or error */
160159
int rstatus; /* bytes ready or error */
161160
unsigned int quirks; /* quirks flags */
161+
unsigned int flags; /* mode flags */
162162
unsigned char used; /* True if open */
163163
unsigned char present; /* True if not disconnected */
164164
unsigned char bidir; /* interface is bidirectional */
165165
unsigned char sleeping; /* interface is suspended */
166+
unsigned char no_paper; /* Paper Out happened */
166167
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
167168
/* first 2 bytes are (big-endian) length */
168169
};
@@ -325,6 +326,7 @@ static void usblp_bulk_write(struct urb *urb)
325326
usblp->wstatus = status;
326327
else
327328
usblp->wstatus = urb->actual_length;
329+
usblp->no_paper = 0;
328330
usblp->wcomplete = 1;
329331
wake_up(&usblp->wwait);
330332
spin_unlock(&usblp->lock);
@@ -411,18 +413,10 @@ static int usblp_open(struct inode *inode, struct file *file)
411413
goto out;
412414

413415
/*
414-
* TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
415-
* This is #if 0-ed because we *don't* want to fail an open
416-
* just because the printer is off-line.
416+
* We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
417+
* - We do not want persistent state which close(2) does not clear
418+
* - It is not used anyway, according to CUPS people
417419
*/
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
426420

427421
retval = usb_autopm_get_interface(intf);
428422
if (retval < 0)
@@ -463,6 +457,8 @@ static int usblp_release(struct inode *inode, struct file *file)
463457
{
464458
struct usblp *usblp = file->private_data;
465459

460+
usblp->flags &= ~LP_ABORT;
461+
466462
mutex_lock (&usblp_mutex);
467463
usblp->used = 0;
468464
if (usblp->present) {
@@ -486,7 +482,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
486482
poll_wait(file, &usblp->wwait, wait);
487483
spin_lock_irqsave(&usblp->lock, flags);
488484
ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
489-
| (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
485+
| ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
490486
spin_unlock_irqrestore(&usblp->lock, flags);
491487
return ret;
492488
}
@@ -675,6 +671,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
675671
retval = -EFAULT;
676672
break;
677673

674+
case LPABORT:
675+
if (arg)
676+
usblp->flags |= LP_ABORT;
677+
else
678+
usblp->flags &= ~LP_ABORT;
679+
break;
680+
678681
default:
679682
retval = -ENOTTY;
680683
}
@@ -730,6 +733,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
730733
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
731734
usblp->wstatus = 0;
732735
spin_lock_irq(&usblp->lock);
736+
usblp->no_paper = 0;
733737
usblp->wcomplete = 1;
734738
wake_up(&usblp->wwait);
735739
spin_unlock_irq(&usblp->lock);
@@ -747,12 +751,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
747751
/* Presume that it's going to complete well. */
748752
writecount += transfer_length;
749753
}
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+
}
750760
/* Leave URB dangling, to be cleaned on close. */
751761
goto collect_error;
752762
}
753763

754764
if (usblp->wstatus < 0) {
755-
usblp_check_status(usblp, 0);
756765
rv = -EIO;
757766
goto collect_error;
758767
}
@@ -838,32 +847,36 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo
838847
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
839848
* select(2) or poll(2) to wait for the buffer to drain before closing.
840849
* 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
846850
*/
847851
static int usblp_wwait(struct usblp *usblp, int nonblock)
848852
{
849853
DECLARE_WAITQUEUE(waita, current);
850854
int rc;
855+
int err = 0;
851856

852857
add_wait_queue(&usblp->wwait, &waita);
853858
for (;;) {
859+
set_current_state(TASK_INTERRUPTIBLE);
854860
if (mutex_lock_interruptible(&usblp->mut)) {
855861
rc = -EINTR;
856862
break;
857863
}
858-
set_current_state(TASK_INTERRUPTIBLE);
859-
if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
860-
mutex_unlock(&usblp->mut);
861-
break;
862-
}
864+
rc = usblp_wtest(usblp, nonblock);
863865
mutex_unlock(&usblp->mut);
864-
if (rc == 0)
866+
if (rc <= 0)
865867
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+
}
867880
}
868881
set_current_state(TASK_RUNNING);
869882
remove_wait_queue(&usblp->wwait, &waita);

0 commit comments

Comments
 (0)