Finally, I made time to review this code!

On Monday 25 June 2007, Craig W. Nadler wrote:

> --- a/Documentation/usb/gadget_printer.txt      1969-12-31 19:00:00.000000000 
> -0500
> +++ b/Documentation/usb/gadget_printer.txt      2007-06-26 00:03:59.000000000 
> -0400
> @@ -0,0 +1,498 @@
> +     ...
> +
> +void
> +usage(const char *option)              /* I - Option string or NULL */
> +{
> +  if (option)
> +    fprintf(stderr, "prn_example: Unknown option \"%s\"!\n", option);

What's this "tabstop=2" stuff??  This is Linux!  :)

Seriously ... even in example code, let's stick to the
CodingStyle guidelines.  (I think Lindent should fix
most of this for you, other than maybe too-long lines.)


> --- a/drivers/usb/gadget/printer.c      1969-12-31 19:00:00.000000000 -0500
> +++ b/drivers/usb/gadget/printer.c      2007-06-26 00:36:08.000000000 -0400
> @@ -0,0 +1,1736 @@
> +     ...
> +
> +
> +#define DEBUG 1

No ... I submitted a patch (now in Greg's queue) to provide
CONFIG_USB_GADGET_DEBUG which will automagically #define DEBUG
when appropriate.  Don't force this on in drivers.

I fired this driver up, and noticed it was spamming my syslog
with debug data even though CONFIG_USB_GADGET_DEBUG wasn't set...


> +#define DRIVER_DESC            "Printer Gadget"
> +#define DRIVER_VERSION         "0.2.0 06/04/2007"

Version strings ... generally frowned on, since they
end up not meaning anything.  I'd be happier if you just
included included a date code.


> +#define GADGET_GET_PRINTER_STATUS      _IOR('P', 1, unsigned char)
> +#define GADGET_SET_PRINTER_STATUS      _IOWR('P', 2, unsigned char)

These need to show up in a header file that gets exported;
maybe <linux/usb/g_printer.h> would be suitable.  It'd be
useful to have constants for the printer status values too
(I'm assuming that makes sense.)


> +static struct class *usb_gadget_class;

Do you really need a usb_gadget class?  There can only
ever be one instance on a given system, and none of the
other drivers have one ... I think you should just remove
this.

Similarly for the printer class, although maybe udev/mdev
expect a class before they'll make a device node.  If so,
you'd only need a printer class.


> +/* Thanks to NetChip Technologies for donating this product ID.
> + */
> +#define PRINTER_VENDOR_NUM     0x0525          /* NetChip */
> +#define PRINTER_PRODUCT_NUM    0xa4a8          /* Linux-USB Printer Gadget */

Actually that ID was one of a bunch that was assigned to me,
and I just delegated it to this driver.  I didn't have a record
that I had already done that...


> +#define xprintk(d, level, fmt, args...) \
> +       printk(level "%s: " fmt, DRIVER_DESC, ## args)
> +
> +#ifdef DEBUG
> +#undef DEBUG
> +#define DEBUG(dev, fmt, args...) \
> +       xprintk(dev, KERN_DEBUG, fmt, ## args)
> +#else
> +#define DEBUG(dev, fmt, args...) \
> +       do { } while (0)
> +#endif /* DEBUG */
> +
> +#ifdef VERBOSE
> +#define VDEBUG(dev, fmt, args...) \
> +       xprintk(dev, KERN_DEBUG, fmt, ## args)
> +#else
> +#define VDEBUG(dev, fmt, args...) \
> +       xprintk(dev, KERN_DEBUG, fmt, ## args)
> +#endif /* DEBUG */
> +
> +#define ERROR(dev, fmt, args...) \
> +       xprintk(dev, KERN_ERR, fmt, ## args)
> +#define WARN(dev, fmt, args...) \
> +       xprintk(dev, KERN_WARNING, fmt, ## args)
> +#define INFO(dev, fmt, args...) \
> +       xprintk(dev, KERN_INFO, fmt, ## args)

I realize I'm partly to blame for this stuff, but could you just
switch away from DEBUG(...) to DBG()/VDBG() so that DEBUG isn't
overloaded?

Some folk would prefer that this use straight driver model stuff,
but in this case no device is truly appropriate (and there can only
be a single gadget driver).  So I'm OK with not using dev_dbg() and
friends in gadget drivers.


> +static struct usb_request *
> +printer_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags)

Oh, and the "use whitespace for readability" style -- "func (...)" -- is
now deprecated in favor of "save bytes" style -- "func(...)".  So please
convert this whole driver over to that style.


> +{
> +       struct usb_request      *req;
> +
> +       req = usb_ep_alloc_request (ep, gfp_flags);
> +       if (!req)
> +               return NULL;
> +
> +       req->buf = usb_ep_alloc_buffer (ep, size, &req->dma, gfp_flags);

Get rid of the ep_{alloc,free}_buffer() calls ... they're going
away.  You can just use kmalloc/kfree; you don't need dma-coherent
buffers.


> +
> +static int
> +printer_open (struct inode *inode, struct file *fd)
> +{
> +       struct printer_dev      *dev;
> +       unsigned long           flags;
> +       int                     ret = -EBUSY;
> +
> +

Extra whitespace; just one blank line there ... you do that
in a lot of places.


> +       dev = container_of (inode->i_cdev, struct printer_dev, printer_cdev);
> +
> +       if (dev == NULL) {

This test can never succeed ... don't bother testing for this!

> +               printk(KERN_ERR "printer_open: NULL device pointer\n");
> +               return -EIO;
> +       }
> +
> +       spin_lock_irqsave (&dev->lock, flags);
> +
> +       if (!dev->printer_cdev_open) {
> +               dev->printer_cdev_open = 1;
> +               fd->private_data = dev;
> +               ret = 0;
> +       }

... I'd change the status in that "if nyet open" block, too.
This looks wrong...

> +
> +       /* Change printer status to show that the printer is on-line. */
> +       dev->printer_status |= PRINTER_SELECTED;
> +
> +       spin_unlock_irqrestore (&dev->lock, flags);
> +
> +       DEBUG (dev, "printer_open returned %x\n", ret);
> +       printk(KERN_INFO "printer_open: returned %x\n", ret);

Another thing you do a lot here:  inappropriate KERN_INFO messaging.

> +
> +       return ret;
> +}
> +
> +
> +static int
> +printer_close (struct inode *inode, struct file *fd)
> +{
> +       struct printer_dev *dev;
> +       unsigned long           flags;
> +
> +       dev = container_of (inode->i_cdev, struct printer_dev, printer_cdev);

Mildly surprised this isn't dev = fd->private_data, like elsewhere...

> +
> +       if (dev == NULL) {

Again, can't-happen, don't-bother-testing-this-case.

> +               printk(KERN_ERR "printer_close: NULL device pointer\n");
> +               return -EIO;
> +       }
> +
> +       /* Change printer status to show that the printer is off-line. */
> +       dev->printer_status &= ~PRINTER_SELECTED;
> +
> +       spin_lock_irqsave (&dev->lock, flags);

Surely you should spinlock before you change the state that's protected
by that spinlock!  And also null out fd->private_data, so this is the
complete reverse of the open() logic above?

> +
> +       dev->printer_cdev_open = 0;
> +
> +       spin_unlock_irqrestore (&dev->lock, flags);
> +
> +       DEBUG (dev, "printer_close\n");
> +       printk(KERN_INFO "printer_close\n");
> +
> +       return 0;
> +}
> +
> +
> +static ssize_t
> +printer_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
> +{
> +       struct printer_dev              *dev = fd->private_data;
> +       unsigned long                   flags;
> +       size_t                          size;
> +       size_t                          bytes_copied;
> +       struct usb_request              *req;
> +       struct usb_request              *current_rx_req;
> +       size_t                          current_rx_bytes;
> +       u8                              *current_rx_buf;
> +
> +       if (dev == NULL) {
> +               printk(KERN_ERR "printer_read: NULL device pointer\n");

Can't happen, right?

> +               return -EIO;
> +       }
> +
> +       if (len == 0)
> +               return -EINVAL;
> +
> +       DEBUG (dev, "printer_read trying to read %d bytes\n", (int)len);
> +
> +       spin_lock (&dev->lock_printer_io);

Wouldn't that lock more naturally be a mutex ... ?


> +       spin_lock_irqsave (&dev->lock, flags);
> +
> +       /* Check if a printer reset happens while we have interrupts on */

I don't follow the comment.  IRQs are disabled here...


> +       dev->reset_printer = 0;
> +
> +       while (likely (!list_empty (&dev->rx_reqs))) {
> +               int error;
> +
> +               req = container_of (dev->rx_reqs.next,
> +                               struct usb_request, list);
> +               list_del_init (&req->list);
> +
> +               req->length = USB_BUFSIZE;

If "len" (parameter) is smaller than USB_BUFSIZE, you'll issue
reads for more than that?  Seems odd.  Especially since the
strategy used here has no comment, explaining what's going on...


> +               req->complete = rx_complete;
> +
> +               error = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
> +               if (error) {
> +                       DEBUG (dev, "rx submit --> %d\n", error);
> +                       list_add (&req->list, &dev->rx_reqs);
> +                       break;
> +               } else {
> +                       list_add (&req->list, &dev->rx_reqs_active);
> +               }
> +       }
> +
> +       bytes_copied = 0;
> +       current_rx_req = dev->current_rx_req;
> +       current_rx_bytes = dev->current_rx_bytes;
> +       current_rx_buf = dev->current_rx_buf;
> +       dev->current_rx_req = NULL;
> +       dev->current_rx_bytes = 0;
> +       dev->current_rx_buf = NULL;
> +

These next two loops look strangely structured.  I'd expect
something more like

        do {
                if (data ready)
                        copy to userspace
                if (done reading)
                        break;
                if (nonblocking)
                        setup -EAGAIN and break;
                sleep till more data arrives
        } while (not reset && rx buffers are queued);

As it is, if just one buffer is ready, you won't ever sleep;
even when the file descriptor isn't nonblocking ... so the
read should be sleeping until "len" bytes have been read,
rather than just until some byte becomes available.

Related:  I don't know the USB printer spec, but is this a
case where short packets should terminate the application
level read -- or not?  I suspect the latter ... if that's
the case, it's worth a comment since that's relatively
unusual (in the USB drivers I've worked with).


> +       /* Check if there is any data in the read buffers */
> +       if ((current_rx_bytes == 0) &&
> +                       (likely (list_empty (&dev->rx_buffers)))) {
> +               /* Turn interrupts back on before sleeping. */
> +               spin_unlock_irqrestore (&dev->lock, flags);
> +
> +               /*
> +                * If no data is available check if this is a NON-Blocking
> +                * call or not.
> +                */
> +               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
> +                       spin_unlock (&dev->lock_printer_io);
> +                       return -EAGAIN;
> +               }
> +
> +               /* Sleep until data is available */
> +               wait_event_interruptible(dev->rx_wait,
> +                               (likely (!list_empty (&dev->rx_buffers))));
> +               spin_lock_irqsave (&dev->lock, flags);
> +       }
> +
> +       while ((current_rx_bytes || likely (!list_empty (&dev->rx_buffers)))
> +                       && len) {
> +               if (current_rx_bytes == 0) {
> +                       req = container_of (dev->rx_buffers.next,
> +                                       struct usb_request, list);
> +                       list_del_init (&req->list);
> +
> +                       if (req->actual && req->buf) {
> +                               current_rx_req = req;
> +                               current_rx_bytes = req->actual;
> +                               current_rx_buf = req->buf;

This whole "current_rx_*" thing is confusing to me.
In the sense that it seems to obfuscate things.  What
I think is probably going on is:

 * There might be bytes left over from a previous read, at
   the tail end of a buffer at the head of dev->rx_buffers
   ... so dev->current_rx_{req,buf} are superfluous, but
   dev->current_rx_buf indicates leftover bytes.

 * You've got to copy out of the "current" buffer, and have
   local variables recording the request, its buffer, and
   its contents ... named to match the state in the preceding
   case

Please you really don't need so many confusing variables ... !?  :)


> +                       } else {
> +                               list_add (&req->list, &dev->rx_reqs);
> +                               continue;
> +                       }
> +               }
> +
> +               /* Don't leave irqs off while doing memory copies */
> +               spin_unlock_irqrestore (&dev->lock, flags);
> +
> +               if (len > current_rx_bytes)
> +                       size = current_rx_bytes;
> +               else
> +                       size = len;
> +
> +               size -= copy_to_user (buf, current_rx_buf, size);
> +               bytes_copied += size;
> +               len -= size;
> +               buf += size;
> +
> +               spin_lock_irqsave (&dev->lock, flags);
> +
> +               /* We've disconnected or reset free the req and buffer */
> +               if (dev->reset_printer) {
> +                       printer_req_free (dev->out_ep, current_rx_req);
> +                       spin_unlock_irqrestore (&dev->lock, flags);
> +                       spin_unlock (&dev->lock_printer_io);

As a rule, one always returns the number of bytes that have been
read, and THEN flags an EOF later.  Of course, you clobbered that
EOF/reset status first thing (which seems incorrect).


> +                       return -EAGAIN;
> +               }
> +
> +               if (size <  current_rx_bytes) {
> +                       current_rx_bytes -= size;
> +                       current_rx_buf += size;
> +               } else {
> +                       list_add (&current_rx_req->list, &dev->rx_reqs);
> +                       current_rx_bytes = 0;
> +                       current_rx_buf = NULL;
> +                       current_rx_req = NULL;
> +               }
> +       }
> +
> +       dev->current_rx_req = current_rx_req;
> +       dev->current_rx_bytes = current_rx_bytes;
> +       dev->current_rx_buf = current_rx_buf;
> +
> +       spin_unlock_irqrestore (&dev->lock, flags);
> +       spin_unlock (&dev->lock_printer_io);
> +
> +       DEBUG (dev, "printer_read returned %d bytes\n", (int)bytes_copied);
> +
> +       if (bytes_copied) {
> +               return bytes_copied;

Style-wise, one prefers to avoid braces if there's only
one statement in the "if" or "else" branch.


> +       } else {
> +               return -EAGAIN;
> +       }
> +}
> +
> +
> +static ssize_t
> +printer_write (struct file *fd, const char __user *buf, size_t len,
> +               loff_t *ptr)
> +{
> +       ...

Similar comments as on the read side.  


> +static unsigned int
> +printer_poll (struct file *fd, poll_table *wait)
> +{
> +       struct printer_dev      *dev = fd->private_data;
> +       unsigned long           flags;
> +       int                     status = 0;
> +
> +       if (dev == NULL) {
> +               printk(KERN_ERR "printer_poll: NULL device pointer\n");
> +               return -EIO;
> +       }
> +

I'll assume this is correct; I've not looked at poll() stuff
in ages.  

> +       poll_wait(fd, &dev->rx_wait, wait);
> +       poll_wait(fd, &dev->tx_wait, wait);
> +
> +       spin_lock_irqsave (&dev->lock, flags);
> +       if (likely (!list_empty (&dev->tx_reqs))) {
> +               status |= POLLOUT | POLLWRNORM;
> +       }
> +       if (likely (!list_empty (&dev->rx_buffers))) {
> +               status |= POLLIN | POLLRDNORM;
> +       }
> +       spin_unlock_irqrestore (&dev->lock, flags);
> +
> +       return status;
> +}
> +
> +
> +
> +static int
> +printer_ioctl (struct inode *inode, struct file *fd, unsigned int code,
> +               unsigned long arg)
> +{
> +       struct printer_dev      *dev = fd->private_data;
> +       unsigned long           flags;
> +       int                     status = 0;
> +
> +       if (dev == NULL) {
> +               printk(KERN_ERR "printer_ioctl: NULL device pointer\n");

can't happen, don't printk ...

> +               return -EIO;
> +       }
> +
> +       printk(KERN_INFO "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
> +

Maybe pr_debug(), but never pr_info() !!!


> +       /* handle ioctls */
> +
> +       spin_lock_irqsave (&dev->lock, flags);
> +
> +       switch (code) {
> +       case GADGET_GET_PRINTER_STATUS:
> +               status = (int)dev->printer_status;
> +               break;
> +       case GADGET_SET_PRINTER_STATUS:
> +               dev->printer_status = (u8)arg;
> +               break;
> +       default:
> +               /* could not handle ioctl */
> +               printk(KERN_ERR "printer_ioctl: ERROR cmd=0x%4.4x"
> +                               "is not supported\n", code);

This printk isn't appropriate; maybe pr_debug, but it's not
a KERN_ERR that someone needs to sit up and pay attention to.


> +               status = -ENOIOCTLCMD;
> +       }
> +
> +       spin_unlock_irqrestore (&dev->lock, flags);
> +
> +       return status;
> +}
> +
> +



> +/* change our operational config.  must agree with the code
> + * that returns config descriptors, and altsetting code.
> + */
> +static int
> +printer_set_config (struct printer_dev *dev, unsigned number)
> +{
> +       int                     result = 0;
> +       struct usb_gadget       *gadget = dev->gadget;
> +
> +       if (gadget_is_sa1100 (gadget)
> +                       && dev->config) {
> +               /* tx fifo is full, but we can't clear it...*/
> +               INFO (dev, "can't change configurations\n");
> +               return -ESPIPE;

Simpler to just refuse to run on sa1100, failing bind() ... in any case,
you don't *know* that fifo is full here!!



> +/* Change our operational Interface. */
> +static int
> +set_interface (struct printer_dev *dev, unsigned number)
> +{
> +       int                     result = 0;
> +
> +       if (gadget_is_sa1100 (dev->gadget)
> +                       && dev->interface < 0) {
> +               /* tx fifo is full, but we can't clear it...*/
> +               INFO (dev, "can't change interfaces\n");
> +               return -ESPIPE;

As above...



> +static void printer_soft_reset (struct printer_dev *dev)
> +{
> +       struct usb_request      *req;
> +
> +       INFO (dev, "Received Printer Reset Request\n");
> +
> +       if (usb_ep_disable (dev->in_ep))
> +               DEBUG (dev, "Failed to disable USB in_ep\n");
> +       if (usb_ep_disable (dev->out_ep))
> +               DEBUG (dev, "Failed to disable USB out_ep\n");
> +
> +       if (dev->current_rx_req != NULL) {
> +               list_add (&dev->current_rx_req->list, &dev->rx_reqs);
> +               dev->current_rx_req = NULL;
> +       }
> +       dev->current_rx_bytes = 0;
> +       dev->current_rx_buf = NULL;
> +       dev->reset_printer = 1;
> +
> +       while (likely (!(list_empty (&dev->rx_buffers)))) {
> +               req = container_of (dev->rx_buffers.next, struct usb_request,
> +                               list);
> +               list_del_init (&req->list);
> +               list_add (&req->list, &dev->rx_reqs);
> +       }
> +
> +       while (likely (!(list_empty (&dev->rx_reqs_active)))) {
> +               req = container_of (dev->rx_buffers.next, struct usb_request,
> +                               list);
> +               if (usb_ep_dequeue (dev->in_ep, req))
> +                       DEBUG (dev, "Failed to dequeue in req %p\n", req);

Shouldn't the ep_disable() calls above have aborted all pending
transfers?  So if there are still active requests, that's just a
bug to report, not something to clean up...

> +
> +               list_del_init (&req->list);
> +               list_add (&req->list, &dev->rx_reqs);
> +       }
> +
> +       while (likely (!(list_empty (&dev->tx_reqs_active)))) {

likewise...

> +               req = container_of (dev->tx_reqs_active.next,
> +                               struct usb_request, list);
> +               if (usb_ep_dequeue (dev->out_ep, req))
> +                       DEBUG (dev, "Failed to dequeue in req %p\n", req);
> +
> +               list_del_init (&req->list);
> +               list_add (&req->list, &dev->tx_reqs);
> +       }
> +
> +       if (usb_ep_enable (dev->in_ep, dev->in))
> +               DEBUG (dev, "Failed to enable USB in_ep\n");
> +       if (usb_ep_enable (dev->out_ep, dev->out))
> +               DEBUG (dev, "Failed to enable USB out_ep\n");
> +
> +       wake_up_interruptible(&dev->tx_wait);
> +       wake_up_interruptible(&dev->tx_flush_wait);
> +}
> +



> +
> +static void
> +printer_unbind (struct usb_gadget *gadget)
> +{
> +       struct printer_dev      *dev = get_gadget_data (gadget);
> +       struct usb_request      *req;
> +
> +
> +       DEBUG (dev, "%s\n", __FUNCTION__);
> +
> +       /* Remove sysfs files */
> +       device_destroy(usb_gadget_class, g_printer_devno);
> +
> +       /* Remove Character Device */
> +       cdev_del(&dev->printer_cdev);
> +
> +       /* we've already been disconnected ... no i/o is active */
> +       /* Free all memory for this driver. */
> +       while (likely (!list_empty (&dev->tx_reqs_active))) {

If no I/O is active, then you don't need this dequeue() loop.
You could report an error if that list is non-empty though.
(And likewise on the RX side.)


> +static void
> +printer_suspend (struct usb_gadget *gadget)
> +{
> +       struct printer_dev      *dev = get_gadget_data (gadget);
> +
> +       DEBUG (dev, "suspend\n");
> +       dev->suspended = 1;
> +}
> +
> +static void
> +printer_resume (struct usb_gadget *gadget)
> +{
> +       struct printer_dev      *dev = get_gadget_data (gadget);
> +
> +       DEBUG (dev, "resume\n");
> +       dev->suspended = 0;
> +}

If you're not going to do anything with that state, there's no
point in having suspend()/resume() methods ... ;)


> +MODULE_DESCRIPTION (DRIVER_DESC);
> +MODULE_AUTHOR ("Craig Nadler, David Brownell");

I'm not an author of this code; please don't put my name there.


> +MODULE_LICENSE ("GPL");
> +
> +
> +static int __init init (void)
> +{
> +       int status;
> +
> +       usb_gadget_class = class_create(THIS_MODULE, "usb_gadget");
> +       if (IS_ERR(usb_gadget_class)) {
> +               status = PTR_ERR(usb_gadget_class);
> +               ERROR (dev, "unable to create usb_gadget class %d\n", status);
> +               return status;
> +       }

Again, you don't need a usb_gadget class.  Or for that matter,
one for the printer.

> +
> +       status = alloc_chrdev_region (&g_printer_devno, 0, 2,
> +                       "USB printer gadget");

You don't need a region, you just need a single device ... this
would IMO be better done in the bind() routine, and undone in
the unbind() routine.

-------------------------------------------------------------------------
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/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to