On Sat, 29 Oct 2005, Joshua Wise wrote:

> I understand that it'll probably not be ready for a commit now, but it's a
> lot cleaner than it used to be. Can someone run a pair of eyes over it and
> tell me if anything is glaringly preventing it from going into the tree?

Here are a few comments, mixed in with your code.

> #define DBUFMAX 65536

This is pretty big for a kernel buffer.  You ought to be able to
use something smaller.

> static unsigned buflen = 2048;
> static unsigned qlen = 8;

It's not clear that these values are the best.  It depends on the
characteristics of the transfers you expect.

> static const struct usb_device_descriptor
> device_desc = {
...
>       .bMaxPacketSize0 =      EP0_MAXPACKET,

For portability, this value cannot be predefined.  You have to get
it from the controller driver.

> static void gchar_complete (struct usb_ep *ep, struct usb_request *req)
> {
>       struct gchar_dev        *dev = ep->driver_data;
>       int                     status = req->status;
> 
>       switch (status) {
> 
>       case 0:                         /* normal completion? */
>               if (ep == dev->out_ep) {

This is an unnecessary test.  What other endpoint could it be?

>                       /* it looks like you've got a packet! */
>                       req->zero = (req->actual < req->length);

There's no point setting req->zero for an OUT transfer.

>                       req->length = req->actual;
>                       
>                       spin_lock(&dev->buflock);
>                               if ((dev->databuflen+req->actual) < DBUFMAX) {

You might as well copy all the data that will fit.  Is there any
reason to leave out an entire packet if it's a few bytes too long?

>                                       memcpy(&dev->databuf[dev->databuflen], 
> req->buf, req->actual);
>                                       dev->databuflen += req->actual;
>                               }
>                       spin_unlock(&dev->buflock);
>                       wake_up_interruptible(&dev->wait);
>                       
>                       /* queue the buffer for some later OUT packet */
>                       req->length = buflen;
>                       status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
>                       if (status == 0)
>                               return;
>                       
>                       ERROR (dev, "complete: failed to requeue request --> 
> %d\n", status);
>                       return;
>               }

This next section is all dead code.

>               /* queue the buffer for some later OUT packet */
>               req->length = buflen;
>               status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
>               
>               ERROR (dev, "complete: invalid endpoint --> %s (%d/%d)\n", 
> ep->name, req->actual, req->length);
>               if (status == 0)
>                       return;
>               /* FALLTHROUGH */

What is it doing here?  Looks like it something got left out or moved
to the wrong spot.


> static ssize_t read_gchar(struct file* file, char* buf, size_t count, loff_t 
> *ppos)

Isn't buf supposed to be __user?  And ditto for the write_gchar routine?

>       struct gchar_dev *dev = (struct gchar_dev *)file->private_data;
>       ssize_t readcnt;
>       DECLARE_WAITQUEUE(wait, current);
>       
>       add_wait_queue(&dev->wait, &wait);
>       current->state = TASK_INTERRUPTIBLE;
> 
>       do {
>               if (dev->databuflen != 0)
>                       break;
> 
>               if (file->f_flags & O_NONBLOCK)
>               {
>                       readcnt = -EAGAIN;
>                       goto out;
>               }
> 
>               if (!dev->configured)
>                       return -ENXIO;

Whoops!  You're still in TASK_INTERRUPTIBLE.

>               schedule();
>       } while (1);
> 
>       spin_lock_irq(&dev->buflock);
>               readcnt = (count > dev->databuflen) ? dev->databuflen : count;
>               memcpy(buf, dev->databuf, readcnt);

Shouldn't this be copy_from_user?

>               memmove(dev->databuf, dev->databuf+readcnt, 
> dev->databuflen-readcnt);
>               dev->databuflen -= readcnt;
>       spin_unlock_irq(&dev->buflock);


> static ssize_t write_gchar(struct file* file, const char* buf, size_t count, 
> loff_t* ppos)
> {
>       struct gchar_dev *dev = (struct gchar_dev *)file->private_data;
>       struct usb_request *req;
>       int result;
>       
>       req = alloc_ep_req (dev->in_ep, count);
> 
>       if (!dev)
>               return 0;
>               
>       if (!dev->configured)
>               return 0;

Looks like these tests should go before the alloc_ep_req call.  On the
other hand, I don't see how dev could ever be NULL.

> static loff_t null_lseek(struct file * file, loff_t offset, int orig)
> {
>       return file->f_pos = 0;
> }

Isn't there a standard kernel routine to do this for you?


Alan Stern



-------------------------------------------------------
This SF.Net email is sponsored by the JBoss Inc.
Get Certified Today * Register for a JBoss Training Course
Free Certification Exam for All Training Attendees Through End of 2005
Visit http://www.jboss.com/services/certification for more information
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to