Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / misc / legousbtower.c
index cd7b548..779bcf0 100644 (file)
@@ -71,6 +71,8 @@
  *   - make device locking interruptible
  * 2004-04-30 - 0.95 Juergen Stuber <starblue@users.sourceforge.net>
  *   - check for valid udev on resubmitting and unlinking urbs
+ * 2004-08-03 - 0.96 Juergen Stuber <starblue@users.sourceforge.net>
+ *   - move reset into open to clean out spurious data
  */
 
 #include <linux/config.h>
@@ -81,6 +83,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.95"
+#define DRIVER_VERSION "v0.96"
 #define DRIVER_AUTHOR "Juergen Stuber <starblue@sourceforge.net>"
 #define DRIVER_DESC "LEGO USB Tower Driver"
 
 /* Module parameters */
-MODULE_PARM(debug, "i");
+module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 /* The defaults are chosen to work with the latest versions of leJOS and NQC.
@@ -113,8 +116,8 @@ MODULE_PARM_DESC(debug, "Debug enabled or not");
  * In this case read_buffer_size should exceed the maximal packet length
  * (417 for datalog uploads), and packet_timeout should be set.
  */
-static size_t read_buffer_size = 480;
-MODULE_PARM(read_buffer_size, "i");
+static int read_buffer_size = 480;
+module_param(read_buffer_size, int, 0);
 MODULE_PARM_DESC(read_buffer_size, "Read buffer size");
 
 /* Some legacy software likes to send packets in one piece.
@@ -123,8 +126,8 @@ MODULE_PARM_DESC(read_buffer_size, "Read buffer size");
  * A problem with long writes is that the following read may time out
  * if the software is not prepared to wait long enough.
  */
-static size_t write_buffer_size = 480;
-MODULE_PARM(write_buffer_size, "i");
+static int write_buffer_size = 480;
+module_param(write_buffer_size, int, 0);
 MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
 
 /* Some legacy software expects reads to contain whole LASM packets.
@@ -138,7 +141,7 @@ MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
  * Set it to 0 to disable.
  */
 static int packet_timeout = 50;
-MODULE_PARM(packet_timeout, "i");
+module_param(packet_timeout, int, 0);
 MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms");
 
 /* Some legacy software expects blocking reads to time out.
@@ -146,7 +149,7 @@ MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms");
  * Set it to 0 to disable.
  */
 static int read_timeout = 200;
-MODULE_PARM(read_timeout, "i");
+module_param(read_timeout, int, 0);
 MODULE_PARM_DESC(read_timeout, "Read timeout in ms");
 
 /* As of kernel version 2.6.4 ehci-hcd uses an
@@ -159,11 +162,11 @@ MODULE_PARM_DESC(read_timeout, "Read timeout in ms");
  * or set to 0 to use the standard interval from the endpoint descriptors.
  */
 static int interrupt_in_interval = 2;
-MODULE_PARM(interrupt_in_interval, "i");
+module_param(interrupt_in_interval, int, 0);
 MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms");
 
 static int interrupt_out_interval = 8;
-MODULE_PARM(interrupt_out_interval, "i");
+module_param(interrupt_out_interval, int, 0);
 MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms");
 
 /* Define these values to match your device */
@@ -175,18 +178,18 @@ MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms");
 #define LEGO_USB_TOWER_REQUEST_GET_VERSION     0xFD
 
 struct tower_reset_reply {
-       __u16 size;             /* little-endian */
+       __le16 size;            /* little-endian */
        __u8 err_code;
        __u8 spare;
 } __attribute__ ((packed));
 
 struct tower_get_version_reply {
-       __u16 size;             /* little-endian */
+       __le16 size;            /* little-endian */
        __u8 err_code;
        __u8 spare;
        __u8 major;
        __u8 minor;
-       __u16 build_no;         /* little-endian */
+       __le16 build_no;                /* little-endian */
 } __attribute__ ((packed));
 
 
@@ -254,7 +257,7 @@ static void tower_disconnect        (struct usb_interface *interface);
 
 
 /* prevent races between open() and disconnect */
-static DECLARE_MUTEX (disconnect_sem);
+static DEFINE_MUTEX (disconnect_mutex);
 
 /* file operations needed when we register this driver */
 static struct file_operations tower_fops = {
@@ -269,19 +272,17 @@ static struct file_operations tower_fops = {
 
 /*
  * usb class driver info in order to get a minor number from the usb core,
- * and to have the device registered with devfs and the driver core
+ * and to have the device registered with the driver core
  */
 static struct usb_class_driver tower_class = {
-       .name =         "usb/legousbtower%d",
+       .name =         "legousbtower%d",
        .fops =         &tower_fops,
-       .mode =         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
        .minor_base =   LEGO_USB_TOWER_MINOR_BASE,
 };
 
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver tower_driver = {
-       .owner =        THIS_MODULE,
        .name =         "legousbtower",
        .probe =        tower_probe,
        .disconnect =   tower_disconnect,
@@ -341,13 +342,15 @@ static int tower_open (struct inode *inode, struct file *file)
        int subminor;
        int retval = 0;
        struct usb_interface *interface;
+       struct tower_reset_reply reset_reply;
+       int result;
 
        dbg(2, "%s: enter", __FUNCTION__);
 
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       down (&disconnect_sem);
+       mutex_lock (&disconnect_mutex);
 
        interface = usb_find_interface (&tower_driver, subminor);
 
@@ -378,6 +381,22 @@ static int tower_open (struct inode *inode, struct file *file)
        }
        dev->open_count = 1;
 
+       /* reset the tower */
+       result = usb_control_msg (dev->udev,
+                                 usb_rcvctrlpipe(dev->udev, 0),
+                                 LEGO_USB_TOWER_REQUEST_RESET,
+                                 USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+                                 0,
+                                 0,
+                                 &reset_reply,
+                                 sizeof(reset_reply),
+                                 1000);
+       if (result < 0) {
+               err("LEGO USB Tower reset control request failed");
+               retval = result;
+               goto unlock_exit;
+       }
+
        /* initialize in direction */
        dev->read_buffer_length = 0;
        dev->read_packet_length = 0;
@@ -385,7 +404,7 @@ static int tower_open (struct inode *inode, struct file *file)
                          dev->udev,
                          usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
                          dev->interrupt_in_buffer,
-                         dev->interrupt_in_endpoint->wMaxPacketSize,
+                         le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
                          tower_interrupt_in_callback,
                          dev,
                          dev->interrupt_in_interval);
@@ -409,7 +428,7 @@ unlock_exit:
        up (&dev->sem);
 
 unlock_disconnect_exit:
-       up (&disconnect_sem);
+       mutex_unlock (&disconnect_mutex);
 
        dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 
@@ -485,12 +504,12 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
                dev->interrupt_in_running = 0;
                mb();
                if (dev->interrupt_in_urb != NULL && dev->udev) {
-                       usb_unlink_urb (dev->interrupt_in_urb);
+                       usb_kill_urb (dev->interrupt_in_urb);
                }
        }
        if (dev->interrupt_out_busy) {
                if (dev->interrupt_out_urb != NULL && dev->udev) {
-                       usb_unlink_urb (dev->interrupt_out_urb);
+                       usb_kill_urb (dev->interrupt_out_urb);
                }
        }
 
@@ -694,7 +713,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
        }
 
        /* write the data into interrupt_out_buffer from userspace */
-       bytes_to_write = min(count, write_buffer_size);
+       bytes_to_write = min_t(int, count, write_buffer_size);
        dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __FUNCTION__, count, bytes_to_write);
 
        if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
@@ -828,7 +847,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
        struct lego_usb_tower *dev = NULL;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor* endpoint;
-       struct tower_reset_reply reset_reply;
        struct tower_get_version_reply get_version_reply;
        int i;
        int retval = -ENOMEM;
@@ -840,14 +858,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
                info ("udev is NULL.");
        }
 
-       /* See if the device offered us matches what we can accept */
-       if ((udev->descriptor.idVendor != LEGO_USB_TOWER_VENDOR_ID) ||
-           (udev->descriptor.idProduct != LEGO_USB_TOWER_PRODUCT_ID)) {
-               return -ENODEV;
-       }
-
-
-       /* allocate memory for our device state and intialize it */
+       /* allocate memory for our device state and initialize it */
 
        dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
 
@@ -912,7 +923,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
                err("Couldn't allocate read_buffer");
                goto error;
        }
-       dev->interrupt_in_buffer = kmalloc (dev->interrupt_in_endpoint->wMaxPacketSize, GFP_KERNEL);
+       dev->interrupt_in_buffer = kmalloc (le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), GFP_KERNEL);
        if (!dev->interrupt_in_buffer) {
                err("Couldn't allocate interrupt_in_buffer");
                goto error;
@@ -951,22 +962,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
        /* let the user know what node this device is now attached to */
        info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor);
 
-       /* reset the tower */
-       result = usb_control_msg (udev,
-                                 usb_rcvctrlpipe(udev, 0),
-                                 LEGO_USB_TOWER_REQUEST_RESET,
-                                 USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
-                                 0,
-                                 0,
-                                 &reset_reply,
-                                 sizeof(reset_reply),
-                                 HZ);
-       if (result < 0) {
-               err("LEGO USB Tower reset control request failed");
-               retval = result;
-               goto error;
-       }
-
        /* get the firmware version and log it */
        result = usb_control_msg (udev,
                                  usb_rcvctrlpipe(udev, 0),
@@ -976,7 +971,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
                                  0,
                                  &get_version_reply,
                                  sizeof(get_version_reply),
-                                 HZ);
+                                 1000);
        if (result < 0) {
                err("LEGO USB Tower get version control request failed");
                retval = result;
@@ -1011,7 +1006,7 @@ static void tower_disconnect (struct usb_interface *interface)
 
        dbg(2, "%s: enter", __FUNCTION__);
 
-       down (&disconnect_sem);
+       mutex_lock (&disconnect_mutex);
 
        dev = usb_get_intfdata (interface);
        usb_set_intfdata (interface, NULL);
@@ -1033,7 +1028,7 @@ static void tower_disconnect (struct usb_interface *interface)
                up (&dev->sem);
        }
 
-       up (&disconnect_sem);
+       mutex_unlock (&disconnect_mutex);
 
        info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));