summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2008-03-11 10:47:55 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2008-03-11 10:47:55 +1100
commit2ec0ba17ae95b31d36cae6ba2814736219909607 (patch)
tree27dc4e77745928fe5aeff5fbd1a32f6da81bb102
parentc4fe7a182328680725091772f0684827d00467b6 (diff)
parent1856f3da109fd89209744fb5a47e04cc45354723 (diff)
Merge commit 'hid/mm'
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/hid/usbhid/hid-core.c42
-rw-r--r--drivers/hid/usbhid/hid-quirks.c9
-rw-r--r--drivers/hid/usbhid/hiddev.c286
-rw-r--r--include/linux/hid.h1
5 files changed, 186 insertions, 154 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index d73a768e176e..f0b00ec1e47e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -968,7 +968,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
size--;
}
- /* dump the report descriptor */
+ /* dump the report */
dbg_hid("report %d (size %u) = ", n, size);
for (i = 0; i < size; i++)
dbg_hid_line(" %02x", data[i]);
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b38e559b7a46..b4ad5d175280 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -278,7 +278,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
if (maxpacket > 0) {
- padlen = (len + maxpacket - 1) / maxpacket;
+ padlen = DIV_ROUND_UP(len, maxpacket);
padlen *= maxpacket;
if (padlen > usbhid->bufsize)
padlen = usbhid->bufsize;
@@ -800,6 +800,22 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
goto fail;
}
+ hid->name[0] = 0;
+
+ if (dev->manufacturer)
+ strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+ if (dev->product) {
+ if (dev->manufacturer)
+ strlcat(hid->name, " ", sizeof(hid->name));
+ strlcat(hid->name, dev->product, sizeof(hid->name));
+ }
+
+ if (!strlen(hid->name))
+ snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
for (n = 0; n < interface->desc.bNumEndpoints; n++) {
struct usb_endpoint_descriptor *endpoint;
@@ -812,6 +828,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
interval = endpoint->bInterval;
+ /* Some vendors give fullspeed interval on highspeed devides */
+ if (quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
+ dev->speed == USB_SPEED_HIGH) {
+ interval = fls(endpoint->bInterval*8);
+ printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
+ hid->name, endpoint->bInterval, interval);
+ }
+
/* Change the polling interval of mice. */
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval;
@@ -859,22 +883,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
usbhid->intf = intf;
usbhid->ifnum = interface->desc.bInterfaceNumber;
- hid->name[0] = 0;
-
- if (dev->manufacturer)
- strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
- if (dev->product) {
- if (dev->manufacturer)
- strlcat(hid->name, " ", sizeof(hid->name));
- strlcat(hid->name, dev->product, sizeof(hid->name));
- }
-
- if (!strlen(hid->name))
- snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
hid->bus = BUS_USB;
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
hid->product = le16_to_cpu(dev->descriptor.idProduct);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index e6d05f6b1c1c..e0f681ab33a6 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -32,6 +32,9 @@
#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
+#define USB_VENDOR_ID_AFATECH 0x15a4
+#define USB_DEVICE_ID_AFATECH_AF9016 0x9016
+
#define USB_VENDOR_ID_AIPTEK 0x08ca
#define USB_DEVICE_ID_AIPTEK_01 0x0001
#define USB_DEVICE_ID_AIPTEK_10 0x0010
@@ -345,6 +348,9 @@
#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
#define USB_DEVICE_ID_N_S_HARMONY 0xc359
+#define USB_VENDOR_ID_NATSU 0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
+
#define USB_VENDOR_ID_NEC 0x073e
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
@@ -426,12 +432,15 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
+ { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
+
{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 5fc4019956ba..95cc192bc7af 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
/*
* "ioctl" file op
*/
+static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
+{
+ struct hid_device *hid = hiddev->hid;
+ struct hiddev_report_info rinfo;
+ struct hiddev_usage_ref_multi *uref_multi = NULL;
+ struct hiddev_usage_ref *uref;
+ struct hid_report *report;
+ struct hid_field *field;
+ int i;
+
+ uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+ if (!uref_multi)
+ return -ENOMEM;
+ uref = &uref_multi->uref;
+ if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+ if (copy_from_user(uref_multi, user_arg,
+ sizeof(*uref_multi)))
+ goto fault;
+ } else {
+ if (copy_from_user(uref, user_arg, sizeof(*uref)))
+ goto fault;
+ }
+
+ switch (cmd) {
+ case HIDIOCGUCODE:
+ rinfo.report_type = uref->report_type;
+ rinfo.report_id = uref->report_id;
+ if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+ goto inval;
+
+ if (uref->field_index >= report->maxfield)
+ goto inval;
+
+ field = report->field[uref->field_index];
+ if (uref->usage_index >= field->maxusage)
+ goto inval;
+
+ uref->usage_code = field->usage[uref->usage_index].hid;
+
+ if (copy_to_user(user_arg, uref, sizeof(*uref)))
+ goto fault;
+
+ kfree(uref_multi);
+ return 0;
+
+ default:
+ if (cmd != HIDIOCGUSAGE &&
+ cmd != HIDIOCGUSAGES &&
+ uref->report_type == HID_REPORT_TYPE_INPUT)
+ goto inval;
+
+ if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+ field = hiddev_lookup_usage(hid, uref);
+ if (field == NULL)
+ goto inval;
+ } else {
+ rinfo.report_type = uref->report_type;
+ rinfo.report_id = uref->report_id;
+ if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+ goto inval;
+
+ if (uref->field_index >= report->maxfield)
+ goto inval;
+
+ field = report->field[uref->field_index];
+
+ 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))
+ goto inval;
+ }
+
+ switch (cmd) {
+ case HIDIOCGUSAGE:
+ uref->value = field->value[uref->usage_index];
+ if (copy_to_user(user_arg, uref, sizeof(*uref)))
+ goto fault;
+ goto goodreturn;
+
+ case HIDIOCSUSAGE:
+ field->value[uref->usage_index] = uref->value;
+ goto goodreturn;
+
+ case HIDIOCGCOLLECTIONINDEX:
+ kfree(uref_multi);
+ return field->usage[uref->usage_index].collection_index;
+ case HIDIOCGUSAGES:
+ for (i = 0; i < uref_multi->num_values; i++)
+ uref_multi->values[i] =
+ field->value[uref->usage_index + i];
+ if (copy_to_user(user_arg, uref_multi,
+ sizeof(*uref_multi)))
+ goto fault;
+ goto goodreturn;
+ case HIDIOCSUSAGES:
+ for (i = 0; i < uref_multi->num_values; i++)
+ field->value[uref->usage_index + i] =
+ uref_multi->values[i];
+ goto goodreturn;
+ }
+
+goodreturn:
+ kfree(uref_multi);
+ return 0;
+fault:
+ kfree(uref_multi);
+ return -EFAULT;
+inval:
+ kfree(uref_multi);
+ return -EINVAL;
+ }
+}
+
+static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
+{
+ struct hid_device *hid = hiddev->hid;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ int idx, len;
+ char *buf;
+
+ if (get_user(idx, (int __user *)user_arg))
+ return -EFAULT;
+
+ if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
+ kfree(buf);
+ return -EINVAL;
+ }
+
+ if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ kfree(buf);
+
+ return len;
+}
+
static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct hiddev_list *list = file->private_data;
@@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
- struct hiddev_usage_ref_multi *uref_multi = NULL;
- struct hiddev_usage_ref *uref;
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
@@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
case HIDIOCGSTRING:
- {
- int idx, len;
- char *buf;
-
- if (get_user(idx, (int __user *)arg))
- return -EFAULT;
-
- if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
- kfree(buf);
- return -EINVAL;
- }
-
- if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
- kfree(buf);
- return -EFAULT;
- }
-
- kfree(buf);
-
- return len;
- }
+ return hiddev_ioctl_string(hiddev, cmd, user_arg);
case HIDIOCINITREPORT:
usbhid_init_reports(hid);
@@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0;
case HIDIOCGUCODE:
- uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
- if (!uref_multi)
- return -ENOMEM;
- uref = &uref_multi->uref;
- if (copy_from_user(uref, user_arg, sizeof(*uref)))
- goto fault;
-
- rinfo.report_type = uref->report_type;
- rinfo.report_id = uref->report_id;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- goto inval;
-
- if (uref->field_index >= report->maxfield)
- goto inval;
-
- field = report->field[uref->field_index];
- if (uref->usage_index >= field->maxusage)
- goto inval;
-
- uref->usage_code = field->usage[uref->usage_index].hid;
-
- if (copy_to_user(user_arg, uref, sizeof(*uref)))
- goto fault;
-
- kfree(uref_multi);
- return 0;
-
+ /* fall through */
case HIDIOCGUSAGE:
case HIDIOCSUSAGE:
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX:
- uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
- if (!uref_multi)
- return -ENOMEM;
- uref = &uref_multi->uref;
- if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
- if (copy_from_user(uref_multi, user_arg,
- sizeof(*uref_multi)))
- goto fault;
- } else {
- if (copy_from_user(uref, user_arg, sizeof(*uref)))
- goto fault;
- }
-
- if (cmd != HIDIOCGUSAGE &&
- cmd != HIDIOCGUSAGES &&
- uref->report_type == HID_REPORT_TYPE_INPUT)
- goto inval;
-
- if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
- field = hiddev_lookup_usage(hid, uref);
- if (field == NULL)
- goto inval;
- } else {
- rinfo.report_type = uref->report_type;
- rinfo.report_id = uref->report_id;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- goto inval;
-
- if (uref->field_index >= report->maxfield)
- goto inval;
-
- field = report->field[uref->field_index];
-
- 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))
- goto inval;
- }
-
- switch (cmd) {
- case HIDIOCGUSAGE:
- uref->value = field->value[uref->usage_index];
- if (copy_to_user(user_arg, uref, sizeof(*uref)))
- goto fault;
- goto goodreturn;
-
- case HIDIOCSUSAGE:
- field->value[uref->usage_index] = uref->value;
- goto goodreturn;
-
- case HIDIOCGCOLLECTIONINDEX:
- kfree(uref_multi);
- return field->usage[uref->usage_index].collection_index;
- case HIDIOCGUSAGES:
- for (i = 0; i < uref_multi->num_values; i++)
- uref_multi->values[i] =
- field->value[uref->usage_index + i];
- if (copy_to_user(user_arg, uref_multi,
- sizeof(*uref_multi)))
- goto fault;
- goto goodreturn;
- case HIDIOCSUSAGES:
- for (i = 0; i < uref_multi->num_values; i++)
- field->value[uref->usage_index + i] =
- uref_multi->values[i];
- goto goodreturn;
- }
-
-goodreturn:
- kfree(uref_multi);
- return 0;
-fault:
- kfree(uref_multi);
- return -EFAULT;
-inval:
- kfree(uref_multi);
- return -EINVAL;
+ return hiddev_ioctl_usage(hiddev, cmd, user_arg);
case HIDIOCGCOLLECTIONINFO:
if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 74ff57596eb1..af1f7e57a12d 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -284,6 +284,7 @@ struct hid_item {
#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000
#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000
#define HID_QUIRK_MICROSOFT_KEYS 0x08000000
+#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
/*
* Separate quirks for runtime report descriptor fixup