ipg: use NULL, not zero, for pointers
[cascardo/linux.git] / drivers / usb / usb-skeleton.c
index a31fcfd..be76084 100644 (file)
@@ -57,6 +57,7 @@ struct usb_skel {
        __u8                    bulk_in_endpointAddr;   /* the address of the bulk in endpoint */
        __u8                    bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
        int                     errors;                 /* the last request tanked */
+       int                     open_count;             /* count the number of openers */
        spinlock_t              err_lock;               /* lock for errors */
        struct kref             kref;
        struct mutex            io_mutex;               /* synchronize I/O with disconnect */
@@ -87,7 +88,7 @@ static int skel_open(struct inode *inode, struct file *file)
        interface = usb_find_interface(&skel_driver, subminor);
        if (!interface) {
                err ("%s - error, can't find device for minor %d",
-                    __FUNCTION__, subminor);
+                    __func__, subminor);
                retval = -ENODEV;
                goto exit;
        }
@@ -101,15 +102,30 @@ static int skel_open(struct inode *inode, struct file *file)
        /* increment our usage count for the device */
        kref_get(&dev->kref);
 
-       /* prevent the device from being autosuspended */
-       retval = usb_autopm_get_interface(interface);
-       if (retval) {
+       /* lock the device to allow correctly handling errors
+        * in resumption */
+       mutex_lock(&dev->io_mutex);
+
+       if (!dev->open_count++) {
+               retval = usb_autopm_get_interface(interface);
+                       if (retval) {
+                               dev->open_count--;
+                               mutex_unlock(&dev->io_mutex);
+                               kref_put(&dev->kref, skel_delete);
+                               goto exit;
+                       }
+       } /* else { //uncomment this block if you want exclusive open
+               retval = -EBUSY;
+               dev->open_count--;
+               mutex_unlock(&dev->io_mutex);
                kref_put(&dev->kref, skel_delete);
                goto exit;
-       }
+       } */
+       /* prevent the device from being autosuspended */
 
        /* save our object in the file's private structure */
        file->private_data = dev;
+       mutex_unlock(&dev->io_mutex);
 
 exit:
        return retval;
@@ -125,7 +141,7 @@ static int skel_release(struct inode *inode, struct file *file)
 
        /* allow the device to be autosuspended */
        mutex_lock(&dev->io_mutex);
-       if (dev->interface)
+       if (!--dev->open_count && dev->interface)
                usb_autopm_put_interface(dev->interface);
        mutex_unlock(&dev->io_mutex);
 
@@ -196,7 +212,7 @@ static void skel_write_bulk_callback(struct urb *urb)
 {
        struct usb_skel *dev;
 
-       dev = (struct usb_skel *)urb->context;
+       dev = urb->context;
 
        /* sync/async unlink faults aren't errors */
        if (urb->status) {
@@ -204,7 +220,7 @@ static void skel_write_bulk_callback(struct urb *urb)
                    urb->status == -ECONNRESET ||
                    urb->status == -ESHUTDOWN))
                        err("%s - nonzero write bulk status received: %d",
-                           __FUNCTION__, urb->status);
+                           __func__, urb->status);
 
                spin_lock(&dev->err_lock);
                dev->errors = urb->status;
@@ -285,7 +301,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
        retval = usb_submit_urb(urb, GFP_KERNEL);
        mutex_unlock(&dev->io_mutex);
        if (retval) {
-               err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
+               err("%s - failed submitting write urb, error %d", __func__, retval);
                goto error_unanchor;
        }
 
@@ -420,6 +436,8 @@ static void skel_disconnect(struct usb_interface *interface)
        dev->interface = NULL;
        mutex_unlock(&dev->io_mutex);
 
+       usb_kill_anchored_urbs(&dev->submitted);
+
        /* decrement our usage count */
        kref_put(&dev->kref, skel_delete);
 
@@ -435,10 +453,50 @@ static void skel_draw_down(struct usb_skel *dev)
                usb_kill_anchored_urbs(&dev->submitted);
 }
 
+static int skel_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct usb_skel *dev = usb_get_intfdata(intf);
+
+       if (!dev)
+               return 0;
+       skel_draw_down(dev);
+       return 0;
+}
+
+static int skel_resume (struct usb_interface *intf)
+{
+       return 0;
+}
+
+static int skel_pre_reset(struct usb_interface *intf)
+{
+       struct usb_skel *dev = usb_get_intfdata(intf);
+
+       mutex_lock(&dev->io_mutex);
+       skel_draw_down(dev);
+
+       return 0;
+}
+
+static int skel_post_reset(struct usb_interface *intf)
+{
+       struct usb_skel *dev = usb_get_intfdata(intf);
+
+       /* we are sure no URBs are active - no locking needed */
+       dev->errors = -EPIPE;
+       mutex_unlock(&dev->io_mutex);
+
+       return 0;
+}
+
 static struct usb_driver skel_driver = {
        .name =         "skeleton",
        .probe =        skel_probe,
        .disconnect =   skel_disconnect,
+       .suspend =      skel_suspend,
+       .resume =       skel_resume,
+       .pre_reset =    skel_pre_reset,
+       .post_reset =   skel_post_reset,
        .id_table =     skel_table,
        .supports_autosuspend = 1,
 };