vserver 1.9.3
[linux-2.6.git] / drivers / usb / input / hiddev.c
index 76b38de..44e466d 100644 (file)
@@ -66,9 +66,6 @@ struct hiddev_list {
 
 static struct hiddev *hiddev_table[HIDDEV_MINORS];
 
-/* forward reference to make our lives easier */
-extern struct usb_driver hiddev_driver;
-
 /*
  * Find a report, given the report's type and ID.  The ID can be specified
  * indirectly by REPORT_ID_FIRST (which returns the first report of the given
@@ -226,16 +223,6 @@ static int hiddev_fasync(int fd, struct file *file, int on)
        return retval < 0 ? retval : 0;
 }
 
-/*
- * De-allocate a hiddev structure
- */
-static struct usb_class_driver hiddev_class;
-static void hiddev_cleanup(struct hiddev *hiddev)
-{
-       hiddev_table[hiddev->hid->minor] = NULL;
-       usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
-       kfree(hiddev);
-}
 
 /*
  * release file op
@@ -256,7 +243,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
                if (list->hiddev->exist) 
                        hid_close(list->hiddev->hid);
                else
-                       hiddev_cleanup(list->hiddev);
+                       kfree(list->hiddev);
        }
 
        kfree(list);
@@ -295,7 +282,7 @@ static int hiddev_open(struct inode * inode, struct file * file) {
 /*
  * "write" file op
  */
-static ssize_t hiddev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 {
        return -EINVAL;
 }
@@ -303,7 +290,7 @@ static ssize_t hiddev_write(struct file * file, const char * buffer, size_t coun
 /*
  * "read" file op
  */
-static ssize_t hiddev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
+static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct hiddev_list *list = file->private_data;
@@ -406,6 +393,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        struct hiddev_devinfo dinfo;
        struct hid_report *report;
        struct hid_field *field;
+       void __user *user_arg = (void __user *)arg;
        int i;
 
        if (!hiddev->exist)
@@ -414,7 +402,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        switch (cmd) {
 
        case HIDIOCGVERSION:
-               return put_user(HID_VERSION, (int *) arg);
+               return put_user(HID_VERSION, (int __user *)arg);
 
        case HIDIOCAPPLICATION:
                if (arg < 0 || arg >= hid->maxapplication)
@@ -439,13 +427,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dinfo.product = dev->descriptor.idProduct;
                dinfo.version = dev->descriptor.bcdDevice;
                dinfo.num_applications = hid->maxapplication;
-               if (copy_to_user((void *) arg, &dinfo, sizeof(dinfo)))
+               if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
                        return -EFAULT;
 
                return 0;
 
        case HIDIOCGFLAG:
-               if (put_user(list->flags, (int *) arg))
+               if (put_user(list->flags, (int __user *)arg))
                        return -EFAULT;
 
                return 0;
@@ -453,7 +441,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        case HIDIOCSFLAG:
                {
                        int newflags;
-                       if (get_user(newflags, (int *) arg))
+                       if (get_user(newflags, (int __user *)arg))
                                return -EFAULT;
 
                        if ((newflags & ~HIDDEV_FLAGS) != 0 ||
@@ -471,7 +459,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                        int idx, len;
                        char *buf;
 
-                       if (get_user(idx, (int *) arg))
+                       if (get_user(idx, (int __user *)arg))
                                return -EFAULT;
 
                        if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
@@ -482,7 +470,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                                return -EINVAL;
                        }
 
-                       if (copy_to_user((void *) (arg+sizeof(int)), buf, len+1)) {
+                       if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
                                kfree(buf);
                                return -EFAULT;
                        }
@@ -498,7 +486,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                return 0;
 
        case HIDIOCGREPORT:
-               if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo)))
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
                        return -EFAULT;
 
                if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
@@ -513,7 +501,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                return 0;
 
        case HIDIOCSREPORT:
-               if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo)))
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
                        return -EFAULT;
 
                if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
@@ -527,7 +515,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                return 0;
 
        case HIDIOCGREPORTINFO:
-               if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo)))
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
                        return -EFAULT;
 
                if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
@@ -535,13 +523,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 
                rinfo.num_fields = report->maxfield;
 
-               if (copy_to_user((void *) arg, &rinfo, sizeof(rinfo)))
+               if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
                        return -EFAULT;
 
                return 0;
 
        case HIDIOCGFIELDINFO:
-               if (copy_from_user(&finfo, (void *) arg, sizeof(finfo)))
+               if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
                        return -EFAULT;
                rinfo.report_type = finfo.report_type;
                rinfo.report_id = finfo.report_id;
@@ -568,7 +556,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                finfo.unit_exponent = field->unit_exponent;
                finfo.unit = field->unit;
 
-               if (copy_to_user((void *) arg, &finfo, sizeof(finfo)))
+               if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
                        return -EFAULT;
 
                return 0;
@@ -578,7 +566,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                if (!uref_multi)
                        return -ENOMEM;
                uref = &uref_multi->uref;
-               if (copy_from_user(uref, (void *) arg, sizeof(*uref))) 
+               if (copy_from_user(uref, user_arg, sizeof(*uref))) 
                        goto fault;
 
                rinfo.report_type = uref->report_type;
@@ -595,7 +583,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 
                uref->usage_code = field->usage[uref->usage_index].hid;
 
-               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
+               if (copy_to_user(user_arg, uref, sizeof(*uref)))
                        goto fault;
 
                kfree(uref_multi);
@@ -611,11 +599,11 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                        return -ENOMEM;
                uref = &uref_multi->uref;
                if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-                       if (copy_from_user(uref_multi, (void *) arg, 
-                                          sizeof(uref_multi)))
+                       if (copy_from_user(uref_multi, user_arg, 
+                                          sizeof(*uref_multi)))
                                goto fault;
                } else {
-                       if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
+                       if (copy_from_user(uref, user_arg, sizeof(*uref)))
                                goto fault;
                }
 
@@ -638,21 +626,24 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                                goto inval;
 
                        field = report->field[uref->field_index];
-                       if (uref->usage_index >= field->maxusage)
-                               goto inval;
 
-                       if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-                               if (uref_multi->num_values >= HID_MAX_USAGES || 
-                                   uref->usage_index >= field->maxusage || 
-                                  (uref->usage_index + uref_multi->num_values) >= field->maxusage)
+                       if (cmd == HIDIOCGCOLLECTIONINDEX) {
+                               if (uref->usage_index >= field->maxusage)
                                        goto inval;
+                       } else if (uref->usage_index >= field->report_count)
+                               goto inval;
+
+                       else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
+                                (uref_multi->num_values >= HID_MAX_MULTI_USAGES ||
+                                 uref->usage_index + uref_multi->num_values >= field->report_count ||
+                                 uref->usage_index + uref_multi->num_values < uref->usage_index))
+                               goto inval;
                        }
-               }
 
                switch (cmd) {
                        case HIDIOCGUSAGE:
                                uref->value = field->value[uref->usage_index];
-                               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
+                               if (copy_to_user(user_arg, uref, sizeof(*uref)))
                                        goto fault;
                                goto goodreturn;
 
@@ -667,7 +658,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                                for (i = 0; i < uref_multi->num_values; i++)
                                        uref_multi->values[i] = 
                                            field->value[uref->usage_index + i];
-                               if (copy_to_user((void *) arg, uref_multi, 
+                               if (copy_to_user(user_arg, uref_multi, 
                                                 sizeof(*uref_multi)))
                                        goto fault;
                                goto goodreturn;
@@ -689,7 +680,7 @@ inval:
                return -EINVAL;
 
        case HIDIOCGCOLLECTIONINFO:
-               if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo)))
+               if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
                        return -EFAULT;
 
                if (cinfo.index >= hid->maxcollection)
@@ -699,7 +690,7 @@ inval:
                cinfo.usage = hid->collection[cinfo.index].usage;
                cinfo.level = hid->collection[cinfo.index].level;
 
-               if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+               if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
                        return -EFAULT;
                return 0;
 
@@ -715,7 +706,7 @@ inval:
                        len = strlen(hid->name) + 1;
                        if (len > _IOC_SIZE(cmd))
                                 len = _IOC_SIZE(cmd);
-                       return copy_to_user((char *) arg, hid->name, len) ?
+                       return copy_to_user(user_arg, hid->name, len) ?
                                -EFAULT : len;
                }
 
@@ -726,7 +717,7 @@ inval:
                        len = strlen(hid->phys) + 1;
                        if (len > _IOC_SIZE(cmd))
                                len = _IOC_SIZE(cmd);
-                       return copy_to_user((char *) arg, hid->phys, len) ?
+                       return copy_to_user(user_arg, hid->phys, len) ?
                                -EFAULT : len;
                }
        }
@@ -797,17 +788,21 @@ int hiddev_connect(struct hid_device *hid)
  * This is where hid.c calls us to disconnect a hiddev device from the
  * corresponding hid device (usually because the usb device has disconnected)
  */
+static struct usb_class_driver hiddev_class;
 void hiddev_disconnect(struct hid_device *hid)
 {
        struct hiddev *hiddev = hid->hiddev;
 
        hiddev->exist = 0;
 
+       hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
+       usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
+
        if (hiddev->open) {
                hid_close(hiddev->hid);
                wake_up_interruptible(&hiddev->wait);
        } else {
-               hiddev_cleanup(hiddev);
+               kfree(hiddev);
        }
 }