Hi Steven,
Em Wed, 9 Aug 2006 14:50:54 +1000
Steven Haigh <[EMAIL PROTECTED]> escreveu:
| Patch is against 2.6.17.7
There's a hunk failing for the Makefile change when applying it in
the latest -rc kernel.
As this will be applied there, I recomend you to rediff.
| + * History:
| + *
| + * 2006-08-07 - 0.0.13 - shaigh
| + * - fixed various errors to compile on kernel 2.6.17.7
| + * 2006-02-19 - 0.0.12 - jhomppi
| + * - remove the mode parameter from the usb_class_driver structure
| + * (for kernel version 2.6.15)
| + * 2006-02-03 - 0.0.11 jhomppi
| + * - remove the serial number retrieval "short-cut"
| + * 2006-01-16 - 0.0.10 jhomppi
| + * - use vendor/product table in adu_probe
| + * - check LINUX_VERSION_CODE for version of linux kernel
| + * and utilize appropriate termination of transfer
| + * 2005-12-02 - 0.0.9 jhomppi
| + * - pre-stage an input read URB to catch first read operation
| + * 2005-11-21 - 0.0.8 jhomppi
| + * - add ADU120,ADU130,ADU208,ADU218 to supported device list
| + * 2005-11-20 - 0.0.7 jhomppi
| + * - remove references to URB_ASYNC_UNLINK
| + * - add MODULE_LICENSE macro to identify our license to kernel
| + * 2005-09-20 - 0.0.6 jhomppi
| + * - replace deprecated usb_unlink_urb with usb_kill_urb
| + * 2003-12-23 - 0.0.5 jhomppi
| + * - urb after each read and write
| + * 2003-12-02 - 0.0.4 jhomppi
| + * - replace urb_submitted with urb status==-EINPROGRESS to stay
| + * in synch with real urb state
| + * - allow multiple open handles to the same device (now that
| + * urb_submitted problem has been removed)
| + * 2003-11-28 - 0.0.3 jhomppi
| + * - applied more changes suggested by Oliver Neukum
| + * - pre-start read if a buffer is available
| + * - correct the location of spin_unlock at end of a read
| + * - added hack to return serial number to caller if read buffer
| + * starts with an 's' (allows serial# retrieval without ioctl)
| + * - check that udev was not nuked by an early disconnect
| + * (ie. check for a null dev->udev in adu_abort_transfers)
| + * - increase scope of lock_irqsave in adu_read so that
| + * urb_submitted is protected versus the interrupt_in_callback
| + * - use down_interruptible where appropriate to prevent locking
| + * driver module into memory forever
| + * 2003-11-27 - 0.0.2 jhomppi
| + * - applied changes suggested by Oliver Neukum to add
| + * spin locks and double buffering to adu_interrupt_in_callback
| + * 2003-11-25 - 0.0.1 jhomppi
| + * - copied from the Lego Tower USB driver for Kernel 2.6.0
| + * - modified to support ADU devices (basically changed only
| + * the names and constants)
| + */
You don't need this, we'll track history in GIT. ;)
| +/* prevent races between open() and disconnect */
| +static DECLARE_MUTEX (disconnect_sem);
I think this can be a mutex intead of a semaphore.
| +/* local function prototypes */
| +static ssize_t adu_read (struct file *file, char *buffer, size_t count,
loff_t *ppos);
| +static ssize_t adu_write (struct file *file, const char *buffer, size_t
count, loff_t *ppos);
| +static int adu_ioctl (struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg);
| +static inline void adu_delete (struct adu_device *dev);
| +static int adu_open(struct inode *inode, struct file *file);
| +static int adu_release(struct inode *inode, struct file *file);
| +static int adu_release_internal (struct adu_device *dev);
| +static void adu_abort_transfers (struct adu_device *dev);
| +static void adu_interrupt_in_callback (struct urb *urb, struct pt_regs
*regs);
| +static void adu_interrupt_out_callback (struct urb *urb, struct pt_regs
*regs);
| +
| +static int adu_probe (struct usb_interface *interface, const struct
usb_device_id *id);
| +static void adu_disconnect (struct usb_interface *interface);
CodyingStyle hints:
Functions prototypes and definitions are:
my_func()
and not
my_func ()
| +/* file operations needed when we register this driver */
| +static struct file_operations adu_fops = {
| + .owner = THIS_MODULE,
| + .read = adu_read,
| + .write = adu_write,
| + .ioctl = adu_ioctl,
| + .open = adu_open,
| + .release = adu_release,
| +};
make this const please.
| +/**
| + * adu_debug_data
| + */
| +static inline void adu_debug_data (int level, const char *function, int
size, const unsigned char *data)
| +{
| + int i;
| +
| + if (debug < level)
| + return;
| +
| + printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function,
size);
| + for (i = 0; i < size; ++i) {
| + printk ("%.2x ", data[i]);
| + }
| + printk ("\n");
| +} /* end adu_debug_data */
Are you sure you want this inline?
| +/**
| + * adu_delete
| + */
| +static inline void adu_delete (struct adu_device *dev)
| +{
Ditto.
| + /* free data structures */
| + if (dev->interrupt_in_urb != NULL) {
| + usb_free_urb (dev->interrupt_in_urb);
| + }
| + if (dev->interrupt_out_urb != NULL) {
| + usb_free_urb (dev->interrupt_out_urb);
| + }
usb_free_urb() already does the check for you.
| +static int adu_open (struct inode *inode, struct file *file)
| +{
| + struct adu_device *dev = NULL;
Why the NULL init here?
| + down (&disconnect_sem); /* not interruptible */
No need for the comment.
| + interface = usb_find_interface (&adu_driver, subminor);
| +
| + if (!interface) {
| + err ("%s - error, can't find device for minor %d",
| + __FUNCTION__, subminor);
| + retval = -ENODEV;
| + goto exit_no_device;
| + }
Why the blank line?
| + dev = usb_get_intfdata(interface);
| +
| + if (!dev) {
| + retval = -ENODEV;
| + goto exit_no_device;
| + }
Ditto.
| + int iCount;
| + iCount = atomic_read(&dev->sem.count);
| + dbg(2,"%s : sem down failed, count %d", __FUNCTION__, iCount);
Are you sure you need this?
| +/**
| + * adu_release
| + */
| +static int adu_release (struct inode *inode, struct file *file)
| +{
| + struct adu_device *dev = NULL;
| + int retval = 0;
| +
| + dbg(2," %s : enter", __FUNCTION__);
| +
| + if (file == NULL) {
| + dbg(1," %s : file is NULL", __FUNCTION__);
| + retval = -ENODEV;
| + goto exit;
| + }
'if (!file)' is preferred.
| + if (dev->open_count <= 0) {
| + dbg(1," %s : device not opened", __FUNCTION__);
| + retval = -ENODEV;
| + goto exit;
| + }
This is an error, you should print it with err() IMO.
Also, how could 'dev->open_count' become negative? Maybe you should
WARN_ON() here.
| +/**
| + * adu_abort_transfers
| + * aborts transfers and frees associated data structures
| + */
| +static void adu_abort_transfers (struct adu_device *dev)
| +{
| + dbg(2," %s : enter", __FUNCTION__);
| +
| + if (dev == NULL) {
| + dbg(1," %s : dev is null", __FUNCTION__);
| + goto exit;
| + }
| +
| + if (dev->udev == NULL) {
| + dbg(1," %s : udev is null", __FUNCTION__);
| + goto exit;
| + }
| +
| + dbg(2," %s : udev state %d", __FUNCTION__, dev->udev->state);
| + if (dev->udev->state == USB_STATE_NOTATTACHED) {
| + dbg(1," %s : udev is not attached", __FUNCTION__);
| + goto exit;
| + }
| +
| + /* shutdown transfer */
| +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
| + if (dev->interrupt_in_urb != NULL) {
| + usb_unlink_urb (dev->interrupt_in_urb);
| + }
| + if (dev->interrupt_out_urb != NULL) {
| + usb_unlink_urb (dev->interrupt_out_urb);
| + }
| +#else
| + if (dev->interrupt_in_urb != NULL) {
| + usb_kill_urb (dev->interrupt_in_urb);
| + }
| + if (dev->interrupt_out_urb != NULL) {
| + usb_kill_urb (dev->interrupt_out_urb);
| + }
| +#endif
Hmm. Why the #if/#endif?
| +/**
| + * adu_read
| + */
| +static ssize_t adu_read (struct file *file, char *buffer, size_t count,
loff_t *ppos)
| +{
| + struct adu_device *dev;
| + size_t bytes_read = 0;
| + size_t bytes_to_read = count;
| + int i;
| + int retval = 0;
| + int timeout = 0;
| + int should_submit = 0;
| + unsigned long flags;
| + DECLARE_WAITQUEUE(wait, current);
| +
| + dbg(2," %s : enter, count = %d, file=&%08x", __FUNCTION__, count, file);
| +
| + dev = (struct adu_device *)file->private_data;
| + dbg(2," %s : dev=%08x", __FUNCTION__, dev);
| + /* lock this object */
| + if (down_interruptible(&dev->sem))
| + return -ERESTARTSYS;
| +
| + /* verify that the device wasn't unplugged */
| + if (dev->udev == NULL || dev->minor == 0) {
| + retval = -ENODEV;
| + err("No device or device unplugged %d", retval);
| + goto exit;
| + }
| +
| + /* verify that some data was requested */
| + if (count == 0) {
| + dbg(1," %s : read request of 0 bytes", __FUNCTION__);
| + goto exit;
| + }
| +
| + timeout = COMMAND_TIMEOUT;
| + dbg(2," %s : about to start looping", __FUNCTION__);
| + while (bytes_to_read) {
| + int data_in_secondary = dev->secondary_tail -
dev->secondary_head;
| + dbg(2," %s : while, data_in_secondary=%d, status=%d",
__FUNCTION__, data_in_secondary,
| + dev->interrupt_in_urb->status);
| + if (data_in_secondary) { /* drain secondary buffer */
| + int amount = bytes_to_read < data_in_secondary ?
bytes_to_read : data_in_secondary;
| + i = copy_to_user (buffer,
dev->read_buffer_secondary+dev->secondary_head, amount);
| + dev->secondary_head += (amount - i);
| + bytes_read += (amount - i);
| + bytes_to_read -= (amount - i);
| + if (i) {
| + retval = bytes_read ? bytes_read : -EFAULT;
| + goto exit;
| + }
| + } else { /* we check the primary buffer */
| + spin_lock_irqsave (&dev->buflock, flags);
| + if (dev->read_buffer_length) { /* we secure access to
the primary */
| + char *tmp;
| + dbg(2," %s : swap, read_buffer_length = %d",
__FUNCTION__, dev->read_buffer_length);
| + tmp = dev->read_buffer_secondary;
| + dev->read_buffer_secondary =
dev->read_buffer_primary;
| + dev->read_buffer_primary = tmp;
| + dev->secondary_head = 0;
| + dev->secondary_tail = dev->read_buffer_length;
| + dev->read_buffer_length = 0;
| + spin_unlock_irqrestore (&dev->buflock, flags);
| + should_submit = 1; /* we have a free buffer so
use it */
| + } else { /* even the primary was empty - we may need to
do IO */
| + if (dev->interrupt_in_urb->status ==
-EINPROGRESS) { /*somebody is doing IO*/
| + spin_unlock_irqrestore (&dev->buflock,
flags);
| + dbg(2," %s : submitted already",
__FUNCTION__);
| + } else { /* we must initiate input */
| + dbg(2," %s : initiate input",
__FUNCTION__);
| + dev->read_urb_finished = 0;
| +
| + usb_fill_int_urb
(dev->interrupt_in_urb,dev->udev,
| + usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
| + dev->interrupt_in_buffer,
| +
dev->interrupt_in_endpoint->wMaxPacketSize,
| + adu_interrupt_in_callback,
| + dev,
| +
dev->interrupt_in_endpoint->bInterval);
| + retval =
usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
| + if (!retval) {
| + spin_unlock_irqrestore
(&dev->buflock, flags);
| + dbg(2," %s : submitted OK",
__FUNCTION__);
| + } else {
| + if (retval == -ENOMEM) {
| + retval = bytes_read ?
bytes_read : -ENOMEM;
| + }
| + spin_unlock_irqrestore
(&dev->buflock, flags);
| + dbg(2," %s : submit failed",
__FUNCTION__);
| + goto exit;
| + }
| + }
| +
| + /* we wait for I/O to complete */
| + set_current_state(TASK_INTERRUPTIBLE);
| + add_wait_queue(&dev->read_wait, &wait);
| + if (!dev->read_urb_finished) {
| + timeout =
schedule_timeout(COMMAND_TIMEOUT);
| + }
| + else
| + set_current_state(TASK_RUNNING);
| + remove_wait_queue(&dev->read_wait, &wait);
| +
| + if (timeout <= 0) {
| + dbg(2," %s : timeout", __FUNCTION__);
| + retval = bytes_read ? bytes_read :
-ETIMEDOUT;
| + goto exit;
| + }
| +
| + if (signal_pending(current)) {
| + dbg(2," %s : signal pending",
__FUNCTION__);
| + retval = bytes_read ? bytes_read :
-EINTR;
| + goto exit;
| + }
| + }
| + }
| + }
| +
| + retval = bytes_read;
| + /* if the primary buffer is empty then use it */
| + if (should_submit && !dev->interrupt_in_urb->status==-EINPROGRESS) {
| + usb_fill_int_urb (dev->interrupt_in_urb,dev->udev,
| + usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
| + dev->interrupt_in_buffer,
| + dev->interrupt_in_endpoint->wMaxPacketSize,
| + adu_interrupt_in_callback,
| + dev,
| + dev->interrupt_in_endpoint->bInterval);
| + /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
| + dev->read_urb_finished = 0;
| + usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
| + /* we ignore failure */
| + }
| +
| + exit:
| + /* unlock the device */
| + up (&dev->sem);
| +
| + dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
| + return retval;
| +} /* end adu_read */
At first, this function looks pretty big, and some 'if' bodies goes too
deep. You might consider breaking it in small pieces and/or review its
logic.
| +static int adu_ioctl (struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg)
| +{
| + int retval = -ENOTTY; /* default: we don't understand ioctl */
| +
| + return retval;
| +} /* end adu_ioctl */
Return -ENOIOCTLCMD please.
Hmmm can't you omit the ioctl()?
| +/**
| + * adu_probe
| + *
| + * Called by the usb core when a new device is connected that it thinks
| + * this driver might be interested in.
| + */
| +static int adu_probe (struct usb_interface *interface, const struct
usb_device_id *id)
| +{
| + struct usb_device *udev = interface_to_usbdev(interface);
| + struct adu_device *dev = NULL;
| + struct usb_host_interface *iface_desc;
| + struct usb_endpoint_descriptor *endpoint;
| + int i;
| + int iSize;
| + int retval = -ENOMEM;
| +
| + dbg(2," %s : enter", __FUNCTION__);
| +
| + if (udev == NULL) {
| + info ("udev is NULL.");
| + retval = -ENODEV;
| + goto exit;
| + }
| +
| + iSize = sizeof(device_table) / sizeof(device_table[0]);
| + for (i = 0; i < iSize; i++) {
| + if ((udev->descriptor.idVendor == device_table[i].idVendor) &&
| + (udev->descriptor.idProduct == device_table[i].idProduct))
| + break;
| + }
| + if (i >= iSize) return -ENODEV;
| +
| + /* allocate memory for our device state and intialize it */
| +
| + dev = kmalloc (sizeof(struct adu_device), GFP_KERNEL);
| +
| + if (dev == NULL) {
| + err ("Out of memory");
| + goto exit;
| + }
| +
| + init_MUTEX (&dev->sem);
| + spin_lock_init (&dev->buflock);
| +
| + dev->udev = udev;
| + dev->open_count = 0;
| +
| + dev->read_buffer_primary = NULL;
| + dev->read_buffer_secondary = NULL;
| + dev->read_buffer_length = 0;
| + dev->secondary_head = 0;
| + dev->secondary_tail = 0;
| +
| + init_waitqueue_head (&dev->read_wait);
| + init_waitqueue_head (&dev->write_wait);
| +
| + dev->interrupt_in_buffer = NULL;
| + dev->interrupt_in_endpoint = NULL;
| + dev->interrupt_in_urb = NULL;
| + dev->read_urb_finished = 0;
| +
| + dev->interrupt_out_buffer = NULL;
| + dev->interrupt_out_endpoint = NULL;
| + dev->interrupt_out_urb = NULL;
If you use kzalloc() here, you can drop most of this init code.
| + // JJH - debug code prime the buffer
| + memset(dev->read_buffer_primary, 'a',
dev->interrupt_in_endpoint->wMaxPacketSize);
| +
memset(dev->read_buffer_primary+dev->interrupt_in_endpoint->wMaxPacketSize, 'b',
| + dev->interrupt_in_endpoint->wMaxPacketSize);
| +
memset(dev->read_buffer_primary+2*dev->interrupt_in_endpoint->wMaxPacketSize,
'c',
| + dev->interrupt_in_endpoint->wMaxPacketSize);
| +
memset(dev->read_buffer_primary+3*dev->interrupt_in_endpoint->wMaxPacketSize,
'd',
| + dev->interrupt_in_endpoint->wMaxPacketSize);
| +
| + dev->read_buffer_secondary = kmalloc
((4*dev->interrupt_in_endpoint->wMaxPacketSize), GFP_KERNEL);
| + if (!dev->read_buffer_secondary) {
| + err("Couldn't allocate read_buffer_secondary");
| + goto error;
| + }
We do this already, don't we?
--
Luiz Fernando N. Capitulino
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel