Hi:
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.
Cheers,
--
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/input/hiddev.c
===================================================================
RCS file:
/home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/drivers/usb/input/hiddev.c,v
retrieving revision 1.1.1.12
diff -u -r1.1.1.12 hiddev.c
--- a/drivers/usb/input/hiddev.c 5 Apr 2004 09:49:36 -0000 1.1.1.12
+++ b/drivers/usb/input/hiddev.c 14 Apr 2004 10:07:25 -0000
@@ -575,33 +575,11 @@
return 0;
- 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;
-
- if (copy_to_user((void *) arg, uref, sizeof(*uref)))
- return -EFAULT;
-
- return 0;
-
case HIDIOCGUSAGE:
case HIDIOCSUSAGE:
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
+ case HIDIOCGUCODE:
case HIDIOCGCOLLECTIONINDEX:
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
if (copy_from_user(&uref_multi, (void *) arg,
@@ -617,7 +595,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;
@@ -631,28 +610,34 @@
return -EINVAL;
field = report->field[uref->field_index];
- if (uref->usage_index >= field->maxusage)
- return -EINVAL;
-
- 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 == HIDIOCGUCODE ||
+ cmd == HIDIOCGCOLLECTIONINDEX) {
+ if (uref->usage_index >= field->maxusage)
return -EINVAL;
- }
+ } else if (uref->usage_index >= field->report_count)
+ return -EINVAL;
+ else if ((cmd == HIDIOCGUSAGES ||
+ cmd == HIDIOCSUSAGES) &&
+ (uref->usage_index + uref_multi.num_values >=
+ field->report_count ||
+ uref->usage_index + uref_multi.num_values <
+ uref->usage_index))
+ return -EINVAL;
}
switch (cmd) {
case HIDIOCGUSAGE:
uref->value = field->value[uref->usage_index];
- if (copy_to_user((void *) arg, uref, sizeof(*uref)))
- return -EFAULT;
- return 0;
+ break;
case HIDIOCSUSAGE:
field->value[uref->usage_index] = uref->value;
return 0;
+ case HIDIOCGUCODE:
+ uref->usage_code = field->usage[uref->usage_index].hid;
+ break;
+
case HIDIOCGCOLLECTIONINDEX:
return
field->usage[uref->usage_index].collection_index;
case HIDIOCGUSAGES:
@@ -670,6 +655,8 @@
return 0;
}
+ if (copy_to_user((void *) arg, uref, sizeof(*uref)))
+ return -EFAULT;
return 0;
case HIDIOCGCOLLECTIONINFO: