#define USB_PRODUCT_LABPRO     0x0001
 #define USB_PRODUCT_LABQUEST   0x0005
 
+#define VST_MAXBUFFER          (64*1024)
+
 static struct usb_device_id id_table[] = {
        { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
        { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
 MODULE_DEVICE_TABLE(usb, id_table);
 
 struct vstusb_device {
+       struct kref                             kref;
        struct mutex            lock;
        struct usb_device       *usb_dev;
        char                    present;
        int                     wr_pipe;
        int                     wr_timeout_ms;
 };
+#define to_vst_dev(d) container_of(d, struct vstusb_device, kref)
 
 static struct usb_driver vstusb_driver;
 
+static void vstusb_delete(struct kref *kref)
+{
+       struct vstusb_device *vstdev = to_vst_dev(kref);
+
+       usb_put_dev(vstdev->usb_dev);
+       kfree(vstdev);
+}
+
 static int vstusb_open(struct inode *inode, struct file *file)
 {
        struct vstusb_device *vstdev;
                return -EBUSY;
        }
 
+       /* increment our usage count */
+       kref_get(&vstdev->kref);
+
        vstdev->isopen = 1;
 
        /* save device in the file's private structure */
        return 0;
 }
 
-static int vstusb_close(struct inode *inode, struct file *file)
+static int vstusb_release(struct inode *inode, struct file *file)
 {
        struct vstusb_device *vstdev;
 
        mutex_lock(&vstdev->lock);
 
        vstdev->isopen = 0;
-       file->private_data = NULL;
 
-       /* if device is no longer present */
-       if (!vstdev->present) {
-               mutex_unlock(&vstdev->lock);
-               kfree(vstdev);
-       } else
-               mutex_unlock(&vstdev->lock);
+       dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__);
+
+       mutex_unlock(&vstdev->lock);
+
+       kref_put(&vstdev->kref, vstusb_delete);
 
        return 0;
 }
                return -ENODEV;
 
        /* verify that we actually want to read some data */
-       if (count == 0)
+       if ((count == 0) || (count > VST_MAXBUFFER))
                return -EINVAL;
 
        /* lock this object */
                return -ENODEV;
 
        /* verify that we actually have some data to write */
-       if (count == 0)
+       if ((count == 0) || (count > VST_MAXBUFFER))
                return retval;
 
        /* lock this object */
 
        case IOCTL_VSTUSB_SEND_PIPE:
 
-               if (usb_data.count == 0) {
+               if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
                        mutex_unlock(&vstdev->lock);
                        retval = -EINVAL;
                        goto exit;
                break;
        case IOCTL_VSTUSB_RECV_PIPE:
 
-               if (usb_data.count == 0) {
+               if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
                        mutex_unlock(&vstdev->lock);
                        retval = -EINVAL;
                        goto exit;
        .unlocked_ioctl =       vstusb_ioctl,
        .compat_ioctl =         vstusb_ioctl,
        .open =                 vstusb_open,
-       .release =              vstusb_close,
+       .release =              vstusb_release,
 };
 
 static struct usb_class_driver usb_vstusb_class = {
        if (vstdev == NULL)
                return -ENOMEM;
 
+       /* must do usb_get_dev() prior to kref_init() since the kref_put()
+        * release function will do a usb_put_dev() */
+       usb_get_dev(dev);
+       kref_init(&vstdev->kref);
        mutex_init(&vstdev->lock);
 
        i = dev->descriptor.bcdDevice;
                        "%s: Not able to get a minor for this device.\n",
                        __func__);
                usb_set_intfdata(intf, NULL);
-               kfree(vstdev);
+               kref_put(&vstdev->kref, vstusb_delete);
                return retval;
        }
 
 
                usb_kill_anchored_urbs(&vstdev->submitted);
 
-               /* if the device is not opened, then we clean up right now */
-               if (!vstdev->isopen) {
-                       mutex_unlock(&vstdev->lock);
-                       kfree(vstdev);
-               } else
-                       mutex_unlock(&vstdev->lock);
+               mutex_unlock(&vstdev->lock);
 
+               kref_put(&vstdev->kref, vstusb_delete);
        }
+
 }
 
 static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)