]> exis.tech > repos - linux.git/blobdiff - drivers/usb/misc/idmouse.c
Merge tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groec...
[linux.git] / drivers / usb / misc / idmouse.c
index 0f6b3464c2d6a81f52aba31f8d82ea8ed79e2eeb..3e37adf2bb5734db10516b097e176f4ff6de8a56 100644 (file)
@@ -63,6 +63,7 @@ MODULE_DEVICE_TABLE(usb, idmouse_table);
 
 /* structure to hold all of our device specific stuff */
 struct usb_idmouse {
+       struct kref kref;
 
        struct usb_device *udev; /* save off the usb device pointer */
        struct usb_interface *interface; /* the interface for this device */
@@ -209,8 +210,10 @@ static int idmouse_resume(struct usb_interface *intf)
        return 0;
 }
 
-static inline void idmouse_delete(struct usb_idmouse *dev)
+static inline void idmouse_delete(struct kref *kref)
 {
+       struct usb_idmouse *dev = container_of(kref, struct usb_idmouse, kref);
+
        kfree(dev->bulk_in_buffer);
        kfree(dev);
 }
@@ -254,6 +257,8 @@ static int idmouse_open(struct inode *inode, struct file *file)
                /* increment our usage count for the driver */
                ++dev->open;
 
+               kref_get(&dev->kref);
+
                /* save our object in the file's private structure */
                file->private_data = dev;
 
@@ -277,16 +282,11 @@ static int idmouse_release(struct inode *inode, struct file *file)
 
        /* lock our device */
        mutex_lock(&dev->lock);
-
        --dev->open;
+       mutex_unlock(&dev->lock);
+
+       kref_put(&dev->kref, idmouse_delete);
 
-       if (!dev->present) {
-               /* the device was unplugged before the file was released */
-               mutex_unlock(&dev->lock);
-               idmouse_delete(dev);
-       } else {
-               mutex_unlock(&dev->lock);
-       }
        return 0;
 }
 
@@ -334,6 +334,7 @@ static int idmouse_probe(struct usb_interface *interface,
        if (dev == NULL)
                return -ENOMEM;
 
+       kref_init(&dev->kref);
        mutex_init(&dev->lock);
        dev->udev = udev;
        dev->interface = interface;
@@ -342,8 +343,7 @@ static int idmouse_probe(struct usb_interface *interface,
        result = usb_find_bulk_in_endpoint(iface_desc, &endpoint);
        if (result) {
                dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
-               idmouse_delete(dev);
-               return result;
+               goto err_put_kref;
        }
 
        dev->orig_bi_size = usb_endpoint_maxp(endpoint);
@@ -351,8 +351,8 @@ static int idmouse_probe(struct usb_interface *interface,
        dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
        dev->bulk_in_buffer = kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
        if (!dev->bulk_in_buffer) {
-               idmouse_delete(dev);
-               return -ENOMEM;
+               result = -ENOMEM;
+               goto err_put_kref;
        }
 
        /* allow device read, write and ioctl */
@@ -364,14 +364,18 @@ static int idmouse_probe(struct usb_interface *interface,
        if (result) {
                /* something prevented us from registering this device */
                dev_err(&interface->dev, "Unable to allocate minor number.\n");
-               idmouse_delete(dev);
-               return result;
+               goto err_put_kref;
        }
 
        /* be noisy */
        dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC);
 
        return 0;
+
+err_put_kref:
+       kref_put(&dev->kref, idmouse_delete);
+
+       return result;
 }
 
 static void idmouse_disconnect(struct usb_interface *interface)
@@ -387,14 +391,9 @@ static void idmouse_disconnect(struct usb_interface *interface)
        /* prevent device read, write and ioctl */
        dev->present = 0;
 
-       /* if the device is opened, idmouse_release will clean this up */
-       if (!dev->open) {
-               mutex_unlock(&dev->lock);
-               idmouse_delete(dev);
-       } else {
-               /* unlock */
-               mutex_unlock(&dev->lock);
-       }
+       mutex_unlock(&dev->lock);
+
+       kref_put(&dev->kref, idmouse_delete);
 
        dev_info(&interface->dev, "disconnected\n");
 }