]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/misc/legousbtower.c
Pull bugzilla-9345 into release branch
[linux-2.6-omap-h63xx.git] / drivers / usb / misc / legousbtower.c
index 1713e19a789974b086fe96cd458136f37df5175f..aab320085ebf007af652cfa797d93c5ac09de1ce 100644 (file)
@@ -198,6 +198,7 @@ static struct usb_device_id tower_table [] = {
 };
 
 MODULE_DEVICE_TABLE (usb, tower_table);
+static DEFINE_MUTEX(open_disc_mutex);
 
 #define LEGO_USB_TOWER_MINOR_BASE      160
 
@@ -254,9 +255,6 @@ static int  tower_probe     (struct usb_interface *interface, const struct usb_devic
 static void tower_disconnect   (struct usb_interface *interface);
 
 
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX (disconnect_mutex);
-
 /* file operations needed when we register this driver */
 static const struct file_operations tower_fops = {
        .owner =        THIS_MODULE,
@@ -344,36 +342,40 @@ static int tower_open (struct inode *inode, struct file *file)
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       mutex_lock (&disconnect_mutex);
-
        interface = usb_find_interface (&tower_driver, subminor);
 
        if (!interface) {
                err ("%s - error, can't find device for minor %d",
                     __FUNCTION__, subminor);
                retval = -ENODEV;
-               goto unlock_disconnect_exit;
+               goto exit;
        }
 
+       mutex_lock(&open_disc_mutex);
        dev = usb_get_intfdata(interface);
 
        if (!dev) {
+               mutex_unlock(&open_disc_mutex);
                retval = -ENODEV;
-               goto unlock_disconnect_exit;
+               goto exit;
        }
 
        /* lock this device */
        if (down_interruptible (&dev->sem)) {
+               mutex_unlock(&open_disc_mutex);
                retval = -ERESTARTSYS;
-               goto unlock_disconnect_exit;
+               goto exit;
        }
 
+
        /* allow opening only once */
        if (dev->open_count) {
+               mutex_unlock(&open_disc_mutex);
                retval = -EBUSY;
                goto unlock_exit;
        }
        dev->open_count = 1;
+       mutex_unlock(&open_disc_mutex);
 
        /* reset the tower */
        result = usb_control_msg (dev->udev,
@@ -421,9 +423,7 @@ static int tower_open (struct inode *inode, struct file *file)
 unlock_exit:
        up (&dev->sem);
 
-unlock_disconnect_exit:
-       mutex_unlock (&disconnect_mutex);
-
+exit:
        dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 
        return retval;
@@ -444,9 +444,10 @@ static int tower_release (struct inode *inode, struct file *file)
        if (dev == NULL) {
                dbg(1, "%s: object is NULL", __FUNCTION__);
                retval = -ENODEV;
-               goto exit;
+               goto exit_nolock;
        }
 
+       mutex_lock(&open_disc_mutex);
        if (down_interruptible (&dev->sem)) {
                retval = -ERESTARTSYS;
                goto exit;
@@ -475,6 +476,8 @@ unlock_exit:
        up (&dev->sem);
 
 exit:
+       mutex_unlock(&open_disc_mutex);
+exit_nolock:
        dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
        return retval;
 }
@@ -749,19 +752,20 @@ exit:
 static void tower_interrupt_in_callback (struct urb *urb)
 {
        struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+       int status = urb->status;
        int retval;
 
-       dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
-                       dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+                       dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
                        goto resubmit; /* maybe we can recover */
                }
        }
@@ -795,7 +799,7 @@ exit:
        wake_up_interruptible (&dev->read_wait);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
@@ -805,23 +809,24 @@ exit:
 static void tower_interrupt_out_callback (struct urb *urb)
 {
        struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+       int status = urb->status;
 
-       dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: enter, status %d", __FUNCTION__, status);
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN)) {
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN)) {
                dbg(1, "%s - nonzero write bulk status received: %d",
-                   __FUNCTION__, urb->status);
+                   __FUNCTION__, status);
        }
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
@@ -993,19 +998,18 @@ static void tower_disconnect (struct usb_interface *interface)
 
        dbg(2, "%s: enter", __FUNCTION__);
 
-       mutex_lock (&disconnect_mutex);
-
        dev = usb_get_intfdata (interface);
+       mutex_lock(&open_disc_mutex);
        usb_set_intfdata (interface, NULL);
 
-
-       down (&dev->sem);
-
        minor = dev->minor;
 
        /* give back our minor */
        usb_deregister_dev (interface, &tower_class);
 
+       down (&dev->sem);
+       mutex_unlock(&open_disc_mutex);
+
        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
                up (&dev->sem);
@@ -1015,8 +1019,6 @@ static void tower_disconnect (struct usb_interface *interface)
                up (&dev->sem);
        }
 
-       mutex_unlock (&disconnect_mutex);
-
        info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
 
        dbg(2, "%s: leave", __FUNCTION__);