Re: [PATCH]usblp read race

Pete Zaitcev <[email protected]>
Newsgroups gmane.linux.usb.devel
Organization Red Hat, Inc.
Message-ID <[email protected]>
On Fri, 30 Mar 2007 20:34:47 +0200, Oliver Neukum <[email protected]> wrote:

> > What did I tell you about wait_event? It would be far cleaner
> > to open-code the loop.
> 
> Open code? What exactly are you proposing?

Oliver, I've removed wait_event. Please have a look if you have a moment.
This also should fix the endless loop upon a write error, which Jochen
reported.

Unfortunately, the diffstat is unfavourable: +247 -155. This may be the
fault of added comments, because the module itself lost about 700 bytes
on x86_64.  I think the code is more regular and clean now, but
please let me know if I muddied waters.

I made a special effort to preserve all oddities of the current driver,
because it had a history of "cleanups" causing regressions. Again, this
is something to pay attention to.

Two remaining items are:
 - Tim Waugh's ENOSPC like in drivers/char/lp.c
 - Greg-style dynamic URBs

-- Pete

P.S. I'm thinking if I should take usblp for maintenance from Vojtech
since I am reworking it anyway.

P.P.S. Does anyone remember what hash signs in front of copyright
statements mean?

diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6584cf0..4422fe8 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -5,7 +5,7 @@
  * Copyright (c) 1999 Pavel Machek	<[email protected]>
  * Copyright (c) 2000 Randy Dunlap	<[email protected]>
  * Copyright (c) 2000 Vojtech Pavlik	<[email protected]>
- # Copyright (c) 2001 Pete Zaitcev	<[email protected]>
+ * Copyright (c) 2001,2007 Pete Zaitcev	<[email protected]>
  # Copyright (c) 2001 David Paschal	<[email protected]>
  * Copyright (c) 2006 Oliver Neukum	<[email protected]>
  *
@@ -62,7 +62,6 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.13"
 #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
 #define DRIVER_DESC "USB Printer Device Class driver"
 
@@ -130,12 +129,13 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
 
 struct usblp {
 	struct usb_device 	*dev;			/* USB device */
-	struct mutex		mut;			/* locks this struct, especially "dev" */
+	struct mutex		mut;		/* locks usblp, except [rw]status */
+	spinlock_t		lock;		/* locks rcomplete, wcomplete */
 	char			*writebuf;		/* write transfer_buffer */
 	char			*readbuf;		/* read transfer_buffer */
 	char			*statusbuf;		/* status transfer_buffer */
 	struct urb		*readurb, *writeurb;	/* The urbs */
-	wait_queue_head_t	wait;			/* Zzzzz ... */
+	wait_queue_head_t	rwait, wwait;
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
 	struct usb_interface	*intf;			/* The interface */
@@ -148,8 +148,9 @@ struct usblp {
 	}			protocol[USBLP_MAX_PROTOCOLS];
 	int			current_protocol;
 	int			minor;			/* minor number of device */
-	int			wcomplete;		/* writing is completed */
-	int			rcomplete;		/* reading is completed */
+	int			wcomplete, rcomplete;
+	int			wstatus;	/* bytes written or error */
+	int			rstatus;	/* bytes ready or error */
 	unsigned int		quirks;			/* quirks flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		present;		/* True if not disconnected */
@@ -179,8 +180,8 @@ static void usblp_dump(struct usblp *usblp) {
     }
 	dbg("current_protocol=%d", usblp->current_protocol);
 	dbg("minor=%d", usblp->minor);
-	dbg("wcomplete=%d", usblp->wcomplete);
-	dbg("rcomplete=%d", usblp->rcomplete);
+	dbg("wstatus=%d", usblp->wstatus);
+	dbg("rstatus=%d", usblp->rstatus);
 	dbg("quirks=%d", usblp->quirks);
 	dbg("used=%d", usblp->used);
 	dbg("bidir=%d", usblp->bidir);
@@ -223,6 +224,10 @@ static const struct quirk_printer_struct quirk_printers[] = {
 	{ 0, 0 }
 };
 
+static int usblp_wwait_and_lock(struct usblp *usblp, int nonblock);
+static int usblp_wtest(struct usblp *usblp, int nonblock);
+static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock);
+static int usblp_rtest(struct usblp *usblp, int nonblock);
 static int usblp_select_alts(struct usblp *usblp);
 static int usblp_set_protocol(struct usblp *usblp, int protocol);
 static int usblp_cache_device_id_string(struct usblp *usblp);
@@ -280,33 +285,40 @@ static void usblp_bulk_read(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
 
-	if (unlikely(!usblp || !usblp->dev || !usblp->used))
-		return;
-
-	if (unlikely(!usblp->present))
-		goto unplug;
-	if (unlikely(urb->status))
-		warn("usblp%d: nonzero read/write bulk status received: %d",
-			usblp->minor, urb->status);
+	if (usblp->present) {
+		if (urb->status)
+			printk(KERN_WARNING "usblp%d: "
+			    "nonzero read bulk status received: %d\n",
+			    usblp->minor, urb->status);
+	}
+	spin_lock(&usblp->lock);
 	usblp->rcomplete = 1;
-unplug:
-	wake_up_interruptible(&usblp->wait);
+	if (urb->status < 0)
+		usblp->rstatus = urb->status;
+	else
+		usblp->rstatus = urb->actual_length;
+	spin_unlock(&usblp->lock);
+	wake_up_interruptible(&usblp->rwait);
 }
 
 static void usblp_bulk_write(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
 
-	if (unlikely(!usblp || !usblp->dev || !usblp->used))
-		return;
-	if (unlikely(!usblp->present))
-		goto unplug;
-	if (unlikely(urb->status))
-		warn("usblp%d: nonzero read/write bulk status received: %d",
-			usblp->minor, urb->status);
+	if (usblp->present) {
+		if (urb->status)
+			printk(KERN_WARNING "usblp%d: "
+			    "nonzero write bulk status received: %d\n",
+			    usblp->minor, urb->status);
+	}
+	spin_lock(&usblp->lock);
 	usblp->wcomplete = 1;
-unplug:
-	wake_up_interruptible(&usblp->wait);
+	if (urb->status < 0)
+		usblp->wstatus = urb->status;
+	else
+		usblp->wstatus = urb->actual_length;
+	spin_unlock(&usblp->lock);
+	wake_up_interruptible(&usblp->wwait);
 }
 
 /*
@@ -323,7 +335,8 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	error = usblp_read_status (usblp, usblp->statusbuf);
 	if (error < 0) {
 		if (printk_ratelimit())
-			err("usblp%d: error %d reading printer status",
+			printk(KERN_ERR
+				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 		return 0;
 	}
@@ -337,8 +350,10 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	if (~status & LP_PSELECD)
 		newerr = 2;
 
-	if (newerr != err)
-		info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
+	if (newerr != err) {
+		printk(KERN_INFO "usblp%d: %s\n",
+		   usblp->minor, usblp_messages[newerr]);
+	}
 
 	return newerr;
 }
@@ -408,9 +423,8 @@ static int usblp_open(struct inode *inode, struct file *file)
 
 	usblp->writeurb->transfer_buffer_length = 0;
 	usblp->wcomplete = 1; /* we begin writeable */
+	usblp->wstatus = 0;
 	usblp->rcomplete = 0;
-	usblp->writeurb->status = 0;
-	usblp->readurb->status = 0;
 
 	if (handle_bidir(usblp) < 0) {
 		file->private_data = NULL;
@@ -423,7 +437,7 @@ out:
 
 static void usblp_cleanup (struct usblp *usblp)
 {
-	info("usblp%d: removed", usblp->minor);
+	printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
 
 	kfree (usblp->device_id_string);
 	kfree (usblp->statusbuf);
@@ -457,10 +471,18 @@ static int usblp_release(struct inode *inode, struct file *file)
 /* No kernel lock - fine */
 static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
 {
+	int ret;
+	unsigned long flags;
+
 	struct usblp *usblp = file->private_data;
-	poll_wait(file, &usblp->wait, wait);
- 	return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
+	/* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
+	poll_wait(file, &usblp->rwait, 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);
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	return ret;
 }
 
 static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -634,10 +656,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		switch (cmd) {
 
 			case LPGETSTATUS:
-				if (usblp_read_status(usblp, usblp->statusbuf)) {
+				if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
 					if (printk_ratelimit())
-						err("usblp%d: failed reading printer status",
-							usblp->minor);
+						printk(KERN_ERR "usblp%d:"
+						    "failed reading printer status (%d)\n",
+						    usblp->minor, retval);
 					retval = -EIO;
 					goto done;
 				}
@@ -658,58 +681,26 @@ done:
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	int timeout, intr, rv, err = 0, transfer_length = 0;
-	size_t writecount = 0;
+	int rv, transfer_length = 0;
+	ssize_t writecount = 0;
 
 	while (writecount < count) {
-		if (!usblp->wcomplete) {
-			barrier();
-			if (file->f_flags & O_NONBLOCK) {
-				writecount += transfer_length;
-				return writecount ? writecount : -EAGAIN;
-			}
-
-			timeout = USBLP_WRITE_TIMEOUT;
-
-			rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
-			if (rv < 0)
-				return writecount ? writecount : -EINTR;
-		}
-		intr = mutex_lock_interruptible (&usblp->mut);
-		if (intr)
-			return writecount ? writecount : -EINTR;
-		if (!usblp->present) {
-			mutex_unlock (&usblp->mut);
-			return -ENODEV;
-		}
-
-		if (usblp->sleeping) {
-			mutex_unlock (&usblp->mut);
-			return writecount ? writecount : -ENODEV;
-		}
+		rv = usblp_wwait_and_lock(usblp, !!(file->f_flags&O_NONBLOCK));
+		if (rv < 0)
+			return writecount ? writecount : rv;
 
-		if (usblp->writeurb->status != 0) {
-			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-				if (!usblp->wcomplete)
-					err("usblp%d: error %d writing to printer",
-						usblp->minor, usblp->writeurb->status);
-				err = usblp->writeurb->status;
-			} else
-				err = usblp_check_status(usblp, err);
+		if (usblp->wstatus < 0) {
+			usblp_check_status(usblp, 0);
 			mutex_unlock (&usblp->mut);
-
-			/* if the fault was due to disconnect, let khubd's
-			 * call to usblp_disconnect() grab usblp->mut ...
-			 */
-			schedule ();
-			continue;
+			return writecount ? writecount : -EIO;
 		}
 
 		/* We must increment writecount here, and not at the
 		 * end of the loop. Otherwise, the final loop iteration may
 		 * be skipped, leading to incomplete printer output.
 		 */
-		writecount += transfer_length;
+		if (usblp->wstatus <= transfer_length)
+			writecount += usblp->wstatus;
 		if (writecount == count) {
 			mutex_unlock(&usblp->mut);
 			break;
@@ -729,90 +720,72 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
 
 		usblp->writeurb->dev = usblp->dev;
 		usblp->wcomplete = 0;
-		err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
-		if (err) {
+		if ((rv = usb_submit_urb(usblp->writeurb, GFP_KERNEL)) < 0) {
 			usblp->wcomplete = 1;
-			if (err != -ENOMEM)
-				count = -EIO;
-			else
-				count = writecount ? writecount : -ENOMEM;
+			usblp->wstatus = 0;
 			mutex_unlock (&usblp->mut);
-			break;
+			return writecount ? writecount : -EIO;
 		}
 		mutex_unlock (&usblp->mut);
 	}
 
-	return count;
+	return writecount;
 }
 
-static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+/*
+ * Notice that we fail to restart in a few cases: on EFAULT, on restart
+ * error, etc. This is the historical behaviour. In all such cases we return
+ * EIO, and applications loop in order to get the new read going.
+ */
+static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	int rv, intr;
+	ssize_t count;
+	ssize_t avail;
+	int rv;
 
 	if (!usblp->bidir)
 		return -EINVAL;
 
-	intr = mutex_lock_interruptible (&usblp->mut);
-	if (intr)
-		return -EINTR;
-	if (!usblp->present) {
-		count = -ENODEV;
-		goto done;
-	}
-
-	if (!usblp->rcomplete) {
-		barrier();
-
-		if (file->f_flags & O_NONBLOCK) {
-			count = -EAGAIN;
-			goto done;
-		}
-		mutex_unlock(&usblp->mut);
-		rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
-		mutex_lock(&usblp->mut);
-		if (rv < 0) {
-			count = -EINTR;
-			goto done;
-		}
-	}
-
-	if (!usblp->present) {
-		count = -ENODEV;
-		goto done;
-	}
-
-	if (usblp->sleeping) {
-		count = -ENODEV;
+	rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK));
+	if (rv < 0) {
+		count = rv;
 		goto done;
 	}
 
-	if (usblp->readurb->status) {
-		err("usblp%d: error %d reading from printer",
-			usblp->minor, usblp->readurb->status);
+	if ((avail = usblp->rstatus) < 0) {
+		printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+		    usblp->minor, (int)avail);
 		usblp->readurb->dev = usblp->dev;
  		usblp->readcount = 0;
 		usblp->rcomplete = 0;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
-			dbg("error submitting urb");
+		if ((rv = usb_submit_urb(usblp->readurb, GFP_KERNEL)) < 0) {
+			dbg("error submitting urb (%d)", rv);
+			usblp->rcomplete = 1;
+			usblp->rstatus = rv;
+		}
 		count = -EIO;
 		goto done;
 	}
 
-	count = count < usblp->readurb->actual_length - usblp->readcount ?
-		count :	usblp->readurb->actual_length - usblp->readcount;
-
-	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
+	count = len < avail - usblp->readcount ? len : avail - usblp->readcount;
+	if (count != 0 &&
+	    copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
 		count = -EFAULT;
 		goto done;
 	}
 
-	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
+	if ((usblp->readcount += count) == avail) {
 		usblp->readcount = 0;
 		usblp->readurb->dev = usblp->dev;
 		usblp->rcomplete = 0;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
-			count = -EIO;
+		if ((rv = usb_submit_urb(usblp->readurb, GFP_KERNEL)) < 0) {
+			dbg("error submitting urb (%d)", rv);
+			usblp->rcomplete = 1;
+			usblp->rstatus = rv;
+			/* We don't want to leak USB return codes into errno. */
+			if (count == 0)
+				count = -EIO;
 			goto done;
 		}
 	}
@@ -823,6 +796,122 @@ done:
 }
 
 /*
+ * Write for write URB to complete. Return with locked usblp on success.
+ *
+ * Our write path has a peculiar property: it does not buffer like a tty,
+ * but waits for the write to succeed. This allows our ->release to bug out
+ * without waiting for writes to drain. But it obviously does not work
+ * 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.
+ * But what was the intent of it? Timing out writes would be _very_ bad,
+ * because printouts would break every time when paper ran out.
+ */
+static int usblp_wwait_and_lock(struct usblp *usblp, int nonblock)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	int rc;
+
+	add_wait_queue(&usblp->wwait, &waita);
+	for (;;) {
+		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;
+		}
+		if (rc == 0)
+			break;
+		mutex_unlock(&usblp->mut);
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&usblp->wwait, &waita);
+	return rc;
+}
+
+static int usblp_wtest(struct usblp *usblp, int nonblock)
+{
+	unsigned long flags;
+
+	if (!usblp->present)
+		return -ENODEV;
+	if (signal_pending(current))
+		return -EINTR;
+	spin_lock_irqsave(&usblp->lock, flags);
+	if (usblp->wcomplete) {
+		spin_unlock_irqrestore(&usblp->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	if (usblp->sleeping)
+		return -ENODEV;
+	if (nonblock)
+		return -EAGAIN;
+	return 1;
+}
+
+/*
+ * Wait for read bytes to become available. This probably should have been
+ * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional
+ * name for functions which lock and return.
+ * 
+ * We do not use wait_event_interruptible because it makes locking iffy.
+ */
+static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	int rc;
+
+	add_wait_queue(&usblp->rwait, &waita);
+	for (;;) {
+		if (mutex_lock_interruptible(&usblp->mut)) {
+			rc = -EINTR;
+			break;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		if ((rc = usblp_rtest(usblp, nonblock)) < 0) {
+			mutex_unlock(&usblp->mut);
+			break;
+		}
+		if (rc == 0)	/* Keep it locked */
+			break;
+		mutex_unlock(&usblp->mut);
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&usblp->rwait, &waita);
+	return rc;
+}
+
+static int usblp_rtest(struct usblp *usblp, int nonblock)
+{
+	unsigned long flags;
+
+	if (!usblp->present)
+		return -ENODEV;
+	if (signal_pending(current))
+		return -EINTR;
+	spin_lock_irqsave(&usblp->lock, flags);
+	if (usblp->rcomplete) {
+		spin_unlock_irqrestore(&usblp->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	if (usblp->sleeping)
+		return -ENODEV;
+	if (nonblock)
+		return -EAGAIN;
+	return 1;
+}
+
+/*
  * Checks for printers that have quirks, such as requiring unidirectional
  * communication but reporting bidirectional; currently some HP printers
  * have this flaw (HP 810, 880, 895, etc.), or needing an init string
@@ -893,23 +982,25 @@ static int usblp_probe(struct usb_interface *intf,
 	/* Malloc and start initializing usblp structure so we can use it
 	 * directly. */
 	if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
-		err("out of memory for usblp");
+		retval = -ENOMEM;
 		goto abort;
 	}
 	usblp->dev = dev;
 	mutex_init (&usblp->mut);
-	init_waitqueue_head(&usblp->wait);
+	spin_lock_init(&usblp->lock);
+	init_waitqueue_head(&usblp->rwait);
+	init_waitqueue_head(&usblp->wwait);
 	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
 	usblp->intf = intf;
 
 	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usblp->writeurb) {
-		err("out of memory");
+		retval = -ENOMEM;
 		goto abort;
 	}
 	usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usblp->readurb) {
-		err("out of memory");
+		retval = -ENOMEM;
 		goto abort;
 	}
 
@@ -917,7 +1008,7 @@ static int usblp_probe(struct usb_interface *intf,
 	 * since we can re-query it on an ioctl and a dynamic string
 	 * could change in length. */
 	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
-		err("out of memory for device_id_string");
+		retval = -ENOMEM;
 		goto abort;
 	}
 
@@ -929,19 +1020,19 @@ static int usblp_probe(struct usb_interface *intf,
 	 * alternate setting can be changed later via an ioctl. */
 	if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
 				GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
-		err("out of memory for write buf");
+		retval = -ENOMEM;
 		goto abort;
 	}
 	if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
 				GFP_KERNEL, &usblp->readurb->transfer_dma))) {
-		err("out of memory for read buf");
+		retval = -ENOMEM;
 		goto abort;
 	}
 
 	/* Allocate buffer for printer status */
 	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
 	if (!usblp->statusbuf) {
-		err("out of memory for statusbuf");
+		retval = -ENOMEM;
 		goto abort;
 	}
 
@@ -956,12 +1047,15 @@ static int usblp_probe(struct usb_interface *intf,
 		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
 			le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idProduct));
+		retval = -ENODEV;
 		goto abort;
 	}
 
 	/* Setup the selected alternate setting and endpoints. */
-	if (usblp_set_protocol(usblp, protocol) < 0)
+	if (usblp_set_protocol(usblp, protocol) < 0) {
+		retval = -ENODEV;	/* ->probe isn't ->ioctl */
 		goto abort;
+	}
 
 	/* Retrieve and store the device ID string. */
 	usblp_cache_device_id_string(usblp);
@@ -979,12 +1073,14 @@ static int usblp_probe(struct usb_interface *intf,
 
 	retval = usb_register_dev(intf, &usblp_class);
 	if (retval) {
-		err("Not able to get a minor for this device.");
+		printk(KERN_ERR "usblp: Not able to get a minor"
+		    " (base %u, slice default).",
+		    USBLP_MINOR_BASE);
 		goto abort_intfdata;
 	}
 	usblp->minor = intf->minor;
-	info("usblp%d: USB %sdirectional printer dev %d "
-		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
+	printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
+		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
 		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
 		usblp->ifnum,
 		usblp->protocol[usblp->current_protocol].alt_setting,
@@ -1011,7 +1107,7 @@ abort:
 		usb_free_urb(usblp->readurb);
 		kfree(usblp);
 	}
-	return -EIO;
+	return retval;
 }
 
 /*
@@ -1080,8 +1176,9 @@ static int usblp_select_alts(struct usblp *usblp)
 		if (ifd->desc.bInterfaceProtocol == 1) {
 			epread = NULL;
 		} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-			info("Disabling reads from problem bidirectional "
-				"printer on usblp%d", usblp->minor);
+			printk(KERN_INFO "usblp%d: Disabling reads from "
+			    "problematic bidirectional printer\n",
+			    usblp->minor);
 			epread = NULL;
 		}
 
@@ -1121,7 +1218,7 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
 		return -EINVAL;
 	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
 	if (r < 0) {
-		err("can't set desired altsetting %d on interface %d",
+		printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
 			alts, usblp->ifnum);
 		return r;
 	}
@@ -1253,12 +1350,7 @@ static struct usb_driver usblp_driver = {
 
 static int __init usblp_init(void)
 {
-	int retval;
-	retval = usb_register(&usblp_driver);
-	if (!retval)
-		info(DRIVER_VERSION ": " DRIVER_DESC);
-
-	return retval;
+	return usb_register(&usblp_driver);
 }
 
 static void __exit usblp_exit(void)

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.