On Wed, Apr 14, 2004 at 08:22:17PM +1000, herbert wrote:
> 
> The current code is applying the maxusage limit to GUSAGE/SUSAGE.  This
> is incorrect as the number of values is stored in field->report_count,
> not field->maxusage.  The USB phone from www.virbiage.com is one device
> where report_count exceeds maxusage.
> 
> The following patch corrects the check for 2.6.

And here is the corresponding patch for 2.4.
-- 
Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ )
Email:  Herbert Xu ~{PmV>HI~} <[EMAIL PROTECTED]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: drivers/usb/hiddev.c
===================================================================
RCS file: 
/home/gondolin/herbert/src/CVS/debian/kernel-source-2.4/drivers/usb/hiddev.c,v
retrieving revision 1.1.1.3
retrieving revision 1.2
diff -u -r1.1.1.3 -r1.2
--- a/drivers/usb/hiddev.c      30 Aug 2003 06:01:42 -0000      1.1.1.3
+++ b/drivers/usb/hiddev.c      14 Apr 2004 09:30:15 -0000      1.2
@@ -553,28 +553,9 @@
 
                return copy_to_user((void *) arg, &finfo, sizeof(finfo));
 
-       case HIDIOCGUCODE:
-               if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
-                       return -EFAULT;
-
-               rinfo.report_type = uref.report_type;
-               rinfo.report_id = uref.report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
-
-               if (uref.field_index >= report->maxfield)
-                       return -EINVAL;
-
-               field = report->field[uref.field_index];
-               if (uref.usage_index >= field->maxusage)
-                       return -EINVAL;
-
-               uref.usage_code = field->usage[uref.usage_index].hid;
-
-               return copy_to_user((void *) arg, &uref, sizeof(uref));
-
        case HIDIOCGUSAGE:
        case HIDIOCSUSAGE:
+       case HIDIOCGUCODE:
        case HIDIOCGCOLLECTIONINDEX:
                if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
                        return -EFAULT;
@@ -583,7 +564,8 @@
                    uref.report_type == HID_REPORT_TYPE_INPUT)
                        return -EINVAL;
 
-               if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
+               if (cmd != HIDIOCGUCODE &&
+                   uref.report_id == HID_REPORT_ID_UNKNOWN) {
                        field = hiddev_lookup_usage(hid, &uref);
                        if (field == NULL)
                                return -EINVAL;
@@ -597,23 +579,29 @@
                                return -EINVAL;
 
                        field = report->field[uref.field_index];
-                       if (uref.usage_index >= field->maxusage)
-                               return -EINVAL;
+                       if (cmd == HIDIOCGUCODE ||
+                           cmd == HIDIOCGCOLLECTIONINDEX) {
+                               if (uref.usage_index >= field->maxusage)
+                                       return -EINVAL;
+                       } else {
+                               if (uref.usage_index >= field->report_count)
+                                       return -EINVAL;
+                       }
                }
 
-               switch (cmd) {
-               case HIDIOCGUSAGE:
+               if (cmd == HIDIOCGUCODE)
+                       uref.usage_code = field->usage[uref.usage_index].hid;
+               else if (cmd == HIDIOCGUSAGE)
                        uref.value = field->value[uref.usage_index];
-                       return copy_to_user((void *) arg, &uref, sizeof(uref));
-
-               case HIDIOCSUSAGE:
+               else if (cmd == HIDIOCSUSAGE) {
                        field->value[uref.usage_index] = uref.value;
                        return 0;
-
-               case HIDIOCGCOLLECTIONINDEX:
+               } else {
+                       /* cmd == HIDIOCGCOLLECTIONINDEX */
                        return field->usage[uref.usage_index].collection_index;
                }
-               break;
+
+               return copy_to_user((void *) arg, &uref, sizeof(uref));
 
        case HIDIOCGCOLLECTIONINFO:
                if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo)))

Reply via email to