# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.294 -> 1.295 # drivers/usb/hid.h 1.8 -> 1.9 # drivers/usb/hid-debug.h 1.2 -> 1.3 # drivers/usb/wacom.c 1.8 -> 1.9 # drivers/usb/usbmouse.c 1.8 -> 1.9 # drivers/usb/usbkbd.c 1.10 -> 1.11 # drivers/usb/hid-input.c 1.2 -> 1.3 # drivers/usb/hiddev.c 1.4 -> 1.5 # drivers/usb/hid-core.c 1.11 -> 1.12 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/02/11 vojtech@suse.cz 1.295 # [PATCH] Update of USB input drivers to the latest versions # # Now that the input core changes have made it into 2.5 I can finally # update the USB input drivers to their latest versions. # # Here is a patch that does that. # # In detail: # # HID driver: # Fix a bug in descriptor parsing (array/variable), # namely visible with Logitech new joysticks and mice # Fix bugs in logical/physical min/max parsing # Fix bugs in exponent parsing # Remove workaround for low-speed devices with >8 byte # reports, fix this in a correct way (bigger irq # request) # Untangle some code (fetc_item()) # Implement asynchronous input/output/feature report # reading and writing # Implement (hopefully) proper locking in the above # Implement support for devices with an output endpoint # Add some support functions for force feedback support # currently in development # Add entries to the debug dump code, including FF and # exponents # Add more mappings into the hid-input interface # Cleanups here and there # # usbkbd driver: # # Make LED URBS use GFP_ATOMIC, they'll be called from a # completion handler # Remove dependency on hid.h # # usbmouse driver: # # Just conversion to the new input core, minor cleanups # # wacom driver: # # Just conversion to the new input core. # -------------------------------------------- # diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c --- a/drivers/usb/hid-core.c Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/hid-core.c Mon Feb 11 23:34:47 2002 @@ -1,12 +1,10 @@ /* - * $Id: hid-core.c,v 1.8 2001/05/23 12:02:18 vojtech Exp $ + * $Id: hid-core.c,v 1.42 2002/01/27 00:22:46 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2001 Vojtech Pavlik * * USB HID support for Linux - * - * Sponsored by SuSE */ /* @@ -25,8 +23,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -56,9 +54,10 @@ * Version Information */ -#define DRIVER_VERSION "v1.8" -#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " -#define DRIVER_DESC "USB HID support drivers" +#define DRIVER_VERSION "v1.31" +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " +#define DRIVER_DESC "USB HID core driver" +#define DRIVER_LICENSE "GPL" static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; @@ -205,16 +204,11 @@ return -1; } - if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */ - if (parser->global.logical_maximum <= parser->global.logical_minimum) { - dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); - return -1; - } - usages = parser->local.usage_index; - /* Hint: we can assume usages < MAX_USAGE here */ - } else { /* VARIABLE */ - usages = parser->global.report_count; + if (parser->global.logical_maximum <= parser->global.logical_minimum) { + dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); + return -1; } + usages = parser->local.usage_index; offset = report->size; report->size += parser->global.report_size * parser->global.report_count; @@ -311,7 +305,10 @@ return 0; case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - parser->global.logical_maximum = item_sdata(item); + if (parser->global.logical_minimum < 0) + parser->global.logical_maximum = item_sdata(item); + else + parser->global.logical_maximum = item_udata(item); return 0; case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: @@ -319,11 +316,14 @@ return 0; case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - parser->global.physical_maximum = item_sdata(item); + if (parser->global.physical_minimum < 0) + parser->global.physical_maximum = item_sdata(item); + else + parser->global.physical_maximum = item_udata(item); return 0; case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - parser->global.unit_exponent = item_udata(item); + parser->global.unit_exponent = item_sdata(item); return 0; case HID_GLOBAL_ITEM_TAG_UNIT: @@ -508,8 +508,6 @@ for (n = 0; n < report->maxfield; n++) kfree(report->field[n]); - if (report->data) - kfree(report->data); kfree(report); } @@ -538,60 +536,64 @@ * items, though they are not used yet. */ -static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) +static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) { - if ((end - start) > 0) { + u8 b; - __u8 b = *start++; - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; + if ((end - start) <= 0) + return NULL; - if (item->tag == HID_ITEM_TAG_LONG) { + b = *start++; - item->format = HID_ITEM_FORMAT_LONG; + item->type = (b >> 2) & 3; + item->tag = (b >> 4) & 15; - if ((end - start) >= 2) { + if (item->tag == HID_ITEM_TAG_LONG) { - item->size = *start++; - item->tag = *start++; + item->format = HID_ITEM_FORMAT_LONG; - if ((end - start) >= item->size) { - item->data.longdata = start; - start += item->size; - return start; - } - } - } else { + if ((end - start) < 2) + return NULL; - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - switch (item->size) { - - case 0: - return start; - - case 1: - if ((end - start) >= 1) { - item->data.u8 = *start++; - return start; - } - break; - - case 2: - if ((end - start) >= 2) { - item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++)); - return start; - } - - case 3: - item->size++; - if ((end - start) >= 4) { - item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++)); - return start; - } - } - } + item->size = *start++; + item->tag = *start++; + + if ((end - start) < item->size) + return NULL; + + item->data.longdata = start; + start += item->size; + return start; + } + + item->format = HID_ITEM_FORMAT_SHORT; + item->size = b & 3; + + switch (item->size) { + + case 0: + return start; + + case 1: + if ((end - start) < 1) + return NULL; + item->data.u8 = *start++; + return start; + + case 2: + if ((end - start) < 2) + return NULL; + item->data.u16 = le16_to_cpu(get_unaligned(((__u16*)start)++)); + return start; + + case 3: + item->size++; + if ((end - start) < 4) + return NULL; + item->data.u32 = le32_to_cpu(get_unaligned(((__u32*)start)++)); + return start; } + return NULL; } @@ -638,12 +640,14 @@ end = start + size; while ((start = fetch_item(start, end, &item)) != 0) { + if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); hid_free_device(device); kfree(parser); return NULL; } + if (dispatch_type[item.type](parser, &item)) { dbg("item %u %u %u %u parsing failed\n", item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); @@ -742,7 +746,6 @@ #endif } - /* * Analyse a received field, and fetch the data from it. The field * content is stored for next report processing (we do differential @@ -797,9 +800,12 @@ memcpy(field->value, value, count * sizeof(__s32)); } -static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid) +static int hid_input_report(int type, struct urb *urb) { + struct hid_device *hid = urb->context; struct hid_report_enum *report_enum = hid->report_enum + type; + u8 *data = urb->transfer_buffer; + int len = urb->actual_length; struct hid_report *report; int n, size; @@ -818,92 +824,46 @@ len--; } - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); -#ifdef DEBUG - printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len); - for (n = 0; n < len; n++) - printk(" %02x", data[n]); - printk("\n"); +#ifdef DEBUG_DATA + { + int i; + printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); + for (i = 0; i < n; i++) + printk(" %02x", data[i]); + printk("\n"); + } #endif + if (!(report = report_enum->report_id_hash[n])) { + dbg("undefined report_id %d received", n); return -1; } size = ((report->size - 1) >> 3) + 1; if (len < size) { - - if (size <= 8) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - return -1; - } - - /* - * Some low-speed devices have large reports and maxpacketsize 8. - * We buffer the data in that case and parse it when we got it all. - * Works only for unnumbered reports. Doesn't make sense for numbered - * reports anyway - then they don't need to be large. - */ - - if (!report->data) - if (!(report->data = kmalloc(size, GFP_ATOMIC))) { - dbg("couldn't allocate report buffer"); - return -1; - } - - if (report->idx + len > size) { - dbg("report data buffer overflow"); - report->idx = 0; - return -1; - } - - memcpy(report->data + report->idx, data, len); - report->idx += len; - - if (report->idx < size) - return 0; - - data = report->data; + dbg("report %d is too short, (%d < %d)", report->id, len, size); + return -1; } for (n = 0; n < report->maxfield; n++) hid_input_field(hid, report->field[n], data); - report->idx = 0; return 0; } /* - * Interrupt input handler. + * Input interrupt completion handler. */ -static void hid_irq(struct urb *urb) +static void hid_irq_in(struct urb *urb) { if (urb->status) { - dbg("nonzero status in irq %d", urb->status); - return; - } - - hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, urb->context); -} - -/* - * hid_read_report() reads in report values without waiting for an irq urb. - */ - -void hid_read_report(struct hid_device *hid, struct hid_report *report) -{ - int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered; - u8 data[len]; - int read; - - if ((read = hid_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) { - dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read); + dbg("nonzero status in input irq %d", urb->status); return; } - hid_input_report(report->type, data, len, hid); + hid_input_report(HID_INPUT_REPORT, urb); } /* @@ -949,7 +909,8 @@ hid_dump_input(field->usage + offset, value); if (offset >= field->report_count) { - dbg("offset exceeds report_count"); + dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); + hid_dump_field(field, 8); return -1; } if (field->logical_minimum < 0) { @@ -958,11 +919,6 @@ return -1; } } - if ( (value > field->logical_maximum) - || (value < field->logical_minimum)) { - dbg("value %d is invalid", value); - return -1; - } field->value[offset] = value; return 0; } @@ -986,14 +942,56 @@ return -1; } +/* + * Find a report with a specified HID usage. + */ + +int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type) +{ + struct hid_report_enum *report_enum = hid->report_enum + type; + struct list_head *list = report_enum->report_list.next; + int i, j; + + while (list != &report_enum->report_list) { + *report = (struct hid_report *) list; + list = list->next; + for (i = 0; i < (*report)->maxfield; i++) { + struct hid_field *field = (*report)->field[i]; + for (j = 0; j < field->maxusage; j++) + if (field->logical == wanted_usage) + return j; + } + } + return -1; +} + +int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field) +{ + int i, j; + + for (i = 0; i < report->maxfield; i++) { + *field = report->field[i]; + for (j = 0; j < (*field)->maxusage; j++) + if ((*field)->usage[j].hid == wanted_usage) + return j; + } + + return -1; +} + static int hid_submit_out(struct hid_device *hid) { - hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength); - hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; - hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); - hid->urbout.dev = hid->dev; + struct hid_report *report; + + report = hid->out[hid->outtail]; + + hid_output_report(report, hid->outbuf); + hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1; + hid->urbout->dev = hid->dev; - if (usb_submit_urb(&hid->urbout, GFP_KERNEL)) { + dbg("submitting out urb"); + + if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) { err("usb_submit_urb(out) failed"); return -1; } @@ -1001,33 +999,168 @@ return 0; } +static int hid_submit_ctrl(struct hid_device *hid) +{ + struct hid_report *report; + unsigned char dir; + + report = hid->ctrl[hid->ctrltail].report; + dir = hid->ctrl[hid->ctrltail].dir; + + if (dir == USB_DIR_OUT) + hid_output_report(report, hid->ctrlbuf); + + hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT)); + hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); + hid->urbctrl->dev = hid->dev; + + hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; + hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; + hid->cr.wValue = ((report->type + 1) << 8) | report->id; + hid->cr.wIndex = cpu_to_le16(hid->ifnum); + hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); + + dbg("submitting ctrl urb"); + + if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { + err("usb_submit_urb(ctrl) failed"); + return -1; + } + + return 0; +} + +/* + * Output interrupt completion handler. + */ + +static void hid_irq_out(struct urb *urb) +{ + struct hid_device *hid = urb->context; + unsigned long flags; + + if (urb->status) + warn("output irq status %d received", urb->status); + + spin_lock_irqsave(&hid->outlock, flags); + + hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); + + if (hid->outhead != hid->outtail) { + hid_submit_out(hid); + return; + } + + clear_bit(HID_OUT_RUNNING, &hid->iofl); + + spin_unlock_irqrestore(&hid->outlock, flags); + + wake_up(&hid->wait); +} + +/* + * Control pipe completion handler. + */ + static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; + unsigned long flags; if (urb->status) warn("ctrl urb status %d received", urb->status); - hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + spin_lock_irqsave(&hid->ctrllock, flags); - if (hid->outhead != hid->outtail) - hid_submit_out(hid); + if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb); + + hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + + if (hid->ctrlhead != hid->ctrltail) { + hid_submit_ctrl(hid); + return; + } + + clear_bit(HID_CTRL_RUNNING, &hid->iofl); + + spin_unlock_irqrestore(&hid->ctrllock, flags); + + wake_up(&hid->wait); } -void hid_write_report(struct hid_device *hid, struct hid_report *report) +void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { - hid_output_report(report, hid->out[hid->outhead].buffer); + int head; + unsigned long flags; - hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id); - hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3); + if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { - hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); + spin_lock_irqsave(&hid->outlock, flags); - if (hid->outhead == hid->outtail) - hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { + spin_unlock_irqrestore(&hid->outlock, flags); + warn("output queue full"); + return; + } - if (hid->urbout.status != -EINPROGRESS) - hid_submit_out(hid); + hid->out[hid->outhead] = report; + hid->outhead = head; + + if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) + hid_submit_out(hid); + + spin_unlock_irqrestore(&hid->outlock, flags); + return; + } + + spin_lock_irqsave(&hid->ctrllock, flags); + + if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { + spin_unlock_irqrestore(&hid->ctrllock, flags); + warn("control queue full"); + return; + } + + hid->ctrl[hid->ctrlhead].report = report; + hid->ctrl[hid->ctrlhead].dir = dir; + hid->ctrlhead = head; + + if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) + hid_submit_ctrl(hid); + + spin_unlock_irqrestore(&hid->ctrllock, flags); +} + +int hid_wait_io(struct hid_device *hid) +{ + DECLARE_WAITQUEUE(wait, current); + int timeout = 10*HZ; + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&hid->wait, &wait); + + while (timeout && test_bit(HID_CTRL_RUNNING, &hid->iofl) && + test_bit(HID_OUT_RUNNING, &hid->iofl)) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&hid->wait, &wait); + + if (!timeout) { + dbg("timeout waiting for ctrl or out queue to clear"); + return -1; + } + + return 0; +} + +static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, + unsigned char type, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, + (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT); } int hid_open(struct hid_device *hid) @@ -1035,9 +1168,9 @@ if (hid->open++) return 0; - hid->urb.dev = hid->dev; + hid->urbin->dev = hid->dev; - if (usb_submit_urb(&hid->urb, GFP_KERNEL)) + if (usb_submit_urb(hid->urbin, GFP_KERNEL)) return -EIO; return 0; @@ -1046,30 +1179,52 @@ void hid_close(struct hid_device *hid) { if (!--hid->open) - usb_unlink_urb(&hid->urb); + usb_unlink_urb(hid->urbin); } /* - * Initialize all readable reports + * Initialize all reports */ + void hid_init_reports(struct hid_device *hid) { - int i; - struct hid_report *report; struct hid_report_enum *report_enum; + struct hid_report *report; struct list_head *list; + int len; - for (i = 0; i < HID_REPORT_TYPES; i++) { - if (i == HID_FEATURE_REPORT || i == HID_INPUT_REPORT) { - report_enum = hid->report_enum + i; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - hid_set_idle(hid->dev, hid->ifnum, 0, report->id); - hid_read_report(hid, report); - list = list->next; - } - } + report_enum = hid->report_enum + HID_INPUT_REPORT; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + hid_submit_report(hid, report, USB_DIR_IN); + list = list->next; + } + + report_enum = hid->report_enum + HID_FEATURE_REPORT; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + hid_submit_report(hid, report, USB_DIR_IN); + list = list->next; + } + + if (hid_wait_io(hid)) { + warn("timeout initializing reports\n"); + return; + } + + report_enum = hid->report_enum + HID_INPUT_REPORT; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + len = ((report->size - 1) >> 3) + 1 + report_enum->numbered; + if (len > hid->urbin->transfer_buffer_length) + hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE; + usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), + 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, + hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + list = list->next; } } @@ -1077,6 +1232,10 @@ #define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 #define USB_DEVICE_ID_WACOM_INTUOS 0x0020 +#define USB_VENDOR_ID_GRIFFIN 0x077d +#define USB_DEVICE_ID_POWERMATE 0x0410 +#define USB_DEVICE_ID_SOUNDKNOB 0x04AA + struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1087,19 +1246,11 @@ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB }, { 0, 0 } }; -static int get_class_descriptor(struct usb_device *dev, int ifnum, - unsigned char type, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, - (type << 8), ifnum, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); -} - - static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) { struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; @@ -1131,7 +1282,7 @@ { __u8 rdesc[rsize]; - if ((n = get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { + if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { dbg("reading report descriptor failed"); return NULL; } @@ -1152,73 +1303,83 @@ for (n = 0; n < interface->bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; - int pipe, maxp; + int pipe; if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ continue; - if (!(endpoint->bEndpointAddress & 0x80)) /* Not an input endpoint */ - continue; - - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval); - - break; + if (endpoint->bEndpointAddress & USB_DIR_IN) { + if (hid->urbin) + continue; + if (!(hid->urbin = usb_alloc_urb(0))) + goto fail; + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); + } else { + if (hid->urbout) + continue; + if (!(hid->urbout = usb_alloc_urb(0))) + goto fail; + pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress); + FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); + } } - if (n == interface->bNumEndpoints) { - dbg("couldn't find an input interrupt endpoint"); - hid_free_device(hid); - return NULL; + if (!hid->urbin) { + err("couldn't find an input interrupt endpoint"); + goto fail; } + init_waitqueue_head(&hid->wait); + + hid->outlock = SPIN_LOCK_UNLOCKED; + hid->ctrllock = SPIN_LOCK_UNLOCKED; + hid->version = hdesc->bcdHID; hid->country = hdesc->bCountryCode; hid->dev = dev; hid->ifnum = interface->bInterfaceNumber; - for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { - hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - hid->out[n].dr.bRequest = HID_REQ_SET_REPORT; - hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum); - } - hid->name[0] = 0; - if (!(buf = kmalloc(63, GFP_KERNEL))) - return NULL; + if (!(buf = kmalloc(64, GFP_KERNEL))) + goto fail; - if (usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) { + if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) { strcat(hid->name, buf); - if (usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) sprintf(hid->name, "%s %s", hid->name, buf); } else sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); - kfree(buf); + usb_make_path(dev, buf, 63); + sprintf(hid->phys, "%s/input%d", buf, ifnum); - FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0), - (void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid); + if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) + hid->uniq[0] = 0; -/* - * Some devices don't like this and crash. I don't know of any devices - * needing this, so it is disabled for now. - */ + kfree(buf); -#if 0 - if (interface->bInterfaceSubClass == 1) - hid_set_protocol(dev, hid->ifnum, 1); -#endif + hid->urbctrl = usb_alloc_urb(0); + FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid); return hid; + +fail: + + hid_free_device(hid); + if (hid->urbin) usb_free_urb(hid->urbin); + if (hid->urbout) usb_free_urb(hid->urbout); + if (hid->urbctrl) usb_free_urb(hid->urbctrl); + + return NULL; } static void* hid_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { struct hid_device *hid; + char path[64]; int i; char *c; @@ -1236,10 +1397,16 @@ if (!hiddev_connect(hid)) hid->claimed |= HID_CLAIMED_HIDDEV; #endif + + if (!hid->claimed) { + hid_free_device(hid); + return NULL; + } + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) - printk("input%d", hid->input.number); + printk("input"); if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) printk(","); if (hid->claimed & HID_CLAIMED_HIDDEV) @@ -1252,9 +1419,10 @@ break; } - printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n", - hid->version >> 8, hid->version & 0xff, c, hid->name, - dev->bus->busnum, dev->devnum, ifnum); + usb_make_path(dev, path, 63); + + printk(": USB HID v%x.%02x %s [%s] on %s\n", + hid->version >> 8, hid->version & 0xff, c, hid->name, path); return hid; } @@ -1264,7 +1432,14 @@ struct hid_device *hid = ptr; dbg("cleanup called"); - usb_unlink_urb(&hid->urb); + usb_unlink_urb(hid->urbin); + usb_unlink_urb(hid->urbout); + usb_unlink_urb(hid->urbctrl); + + usb_free_urb(hid->urbin); + usb_free_urb(hid->urbctrl); + if (hid->urbout) + usb_free_urb(hid->urbout); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); @@ -1276,8 +1451,7 @@ } static struct usb_device_id hid_usb_ids [] = { - { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass: USB_INTERFACE_CLASS_HID }, + { bInterfaceClass: USB_INTERFACE_CLASS_HID }, { } /* Terminating entry */ }; @@ -1296,8 +1470,7 @@ hiddev_init(); #endif usb_register(&hid_driver); - info(DRIVER_VERSION " " DRIVER_AUTHOR); - info(DRIVER_DESC); + info(DRIVER_VERSION ":" DRIVER_DESC); return 0; } @@ -1313,6 +1486,6 @@ module_init(hid_init); module_exit(hid_exit); -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); diff -Nru a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h --- a/drivers/usb/hid-debug.h Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/hid-debug.h Mon Feb 11 23:34:47 2002 @@ -1,12 +1,10 @@ /* - * $Id: hid-debug.h,v 1.3 2001/05/10 15:56:07 vojtech Exp $ + * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ * * (c) 1999 Andreas Gal - * (c) 2000-2001 Vojtech Pavlik + * (c) 2000-2001 Vojtech Pavlik * * Some debug stuff for the HID parser. - * - * Sponsored by SuSE */ /* @@ -25,8 +23,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ struct hid_usage_entry { @@ -36,6 +34,7 @@ }; static struct hid_usage_entry hid_usage_table[] = { + { 0, 0, "Undefined" }, { 1, 0, "GenericDesktop" }, {0, 0x01, "Pointer"}, {0, 0x02, "Mouse"}, @@ -87,6 +86,7 @@ { 7, 0, "Keyboard" }, { 8, 0, "LED" }, { 9, 0, "Button" }, + { 10, 0, "Ordinal" }, { 12, 0, "Hotkey" }, { 13, 0, "Digitizers" }, {0, 0x01, "Digitizer"}, @@ -112,6 +112,112 @@ {0, 0x45, "Eraser"}, {0, 0x46, "TabletPick"}, { 15, 0, "PhysicalInterfaceDevice" }, + {0, 0x00, "Undefined"}, + {0, 0x01, "Physical_Interface_Device"}, + {0, 0x20, "Normal"}, + {0, 0x21, "Set_Effect_Report"}, + {0, 0x22, "Effect_Block_Index"}, + {0, 0x23, "Parameter_Block_Offset"}, + {0, 0x24, "ROM_Flag"}, + {0, 0x25, "Effect_Type"}, + {0, 0x26, "ET_Constant_Force"}, + {0, 0x27, "ET_Ramp"}, + {0, 0x28, "ET_Custom_Force_Data"}, + {0, 0x30, "ET_Square"}, + {0, 0x31, "ET_Sine"}, + {0, 0x32, "ET_Triangle"}, + {0, 0x33, "ET_Sawtooth_Up"}, + {0, 0x34, "ET_Sawtooth_Down"}, + {0, 0x40, "ET_Spring"}, + {0, 0x41, "ET_Damper"}, + {0, 0x42, "ET_Inertia"}, + {0, 0x43, "ET_Friction"}, + {0, 0x50, "Duration"}, + {0, 0x51, "Sample_Period"}, + {0, 0x52, "Gain"}, + {0, 0x53, "Trigger_Button"}, + {0, 0x54, "Trigger_Repeat_Interval"}, + {0, 0x55, "Axes_Enable"}, + {0, 0x56, "Direction_Enable"}, + {0, 0x57, "Direction"}, + {0, 0x58, "Type_Specific_Block_Offset"}, + {0, 0x59, "Block_Type"}, + {0, 0x5A, "Set_Envelope_Report"}, + {0, 0x5B, "Attack_Level"}, + {0, 0x5C, "Attack_Time"}, + {0, 0x5D, "Fade_Level"}, + {0, 0x5E, "Fade_Time"}, + {0, 0x5F, "Set_Condition_Report"}, + {0, 0x60, "CP_Offset"}, + {0, 0x61, "Positive_Coefficient"}, + {0, 0x62, "Negative_Coefficient"}, + {0, 0x63, "Positive_Saturation"}, + {0, 0x64, "Negative_Saturation"}, + {0, 0x65, "Dead_Band"}, + {0, 0x66, "Download_Force_Sample"}, + {0, 0x67, "Isoch_Custom_Force_Enable"}, + {0, 0x68, "Custom_Force_Data_Report"}, + {0, 0x69, "Custom_Force_Data"}, + {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, + {0, 0x6B, "Set_Custom_Force_Report"}, + {0, 0x6C, "Custom_Force_Data_Offset"}, + {0, 0x6D, "Sample_Count"}, + {0, 0x6E, "Set_Periodic_Report"}, + {0, 0x6F, "Offset"}, + {0, 0x70, "Magnitude"}, + {0, 0x71, "Phase"}, + {0, 0x72, "Period"}, + {0, 0x73, "Set_Constant_Force_Report"}, + {0, 0x74, "Set_Ramp_Force_Report"}, + {0, 0x75, "Ramp_Start"}, + {0, 0x76, "Ramp_End"}, + {0, 0x77, "Effect_Operation_Report"}, + {0, 0x78, "Effect_Operation"}, + {0, 0x79, "Op_Effect_Start"}, + {0, 0x7A, "Op_Effect_Start_Solo"}, + {0, 0x7B, "Op_Effect_Stop"}, + {0, 0x7C, "Loop_Count"}, + {0, 0x7D, "Device_Gain_Report"}, + {0, 0x7E, "Device_Gain"}, + {0, 0x7F, "PID_Pool_Report"}, + {0, 0x80, "RAM_Pool_Size"}, + {0, 0x81, "ROM_Pool_Size"}, + {0, 0x82, "ROM_Effect_Block_Count"}, + {0, 0x83, "Simultaneous_Effects_Max"}, + {0, 0x84, "Pool_Alignment"}, + {0, 0x85, "PID_Pool_Move_Report"}, + {0, 0x86, "Move_Source"}, + {0, 0x87, "Move_Destination"}, + {0, 0x88, "Move_Length"}, + {0, 0x89, "PID_Block_Load_Report"}, + {0, 0x8B, "Block_Load_Status"}, + {0, 0x8C, "Block_Load_Success"}, + {0, 0x8D, "Block_Load_Full"}, + {0, 0x8E, "Block_Load_Error"}, + {0, 0x8F, "Block_Handle"}, + {0, 0x90, "PID_Block_Free_Report"}, + {0, 0x91, "Type_Specific_Block_Handle"}, + {0, 0x92, "PID_State_Report"}, + {0, 0x94, "Effect_Playing"}, + {0, 0x95, "PID_Device_Control_Report"}, + {0, 0x96, "PID_Device_Control"}, + {0, 0x97, "DC_Enable_Actuators"}, + {0, 0x98, "DC_Disable_Actuators"}, + {0, 0x99, "DC_Stop_All_Effects"}, + {0, 0x9A, "DC_Device_Reset"}, + {0, 0x9B, "DC_Device_Pause"}, + {0, 0x9C, "DC_Device_Continue"}, + {0, 0x9F, "Device_Paused"}, + {0, 0xA0, "Actuators_Enabled"}, + {0, 0xA4, "Safety_Switch"}, + {0, 0xA5, "Actuator_Override_Switch"}, + {0, 0xA6, "Actuator_Power"}, + {0, 0xA7, "Start_Delay"}, + {0, 0xA8, "Parameter_Block_Size"}, + {0, 0xA9, "Device_Managed_Pool"}, + {0, 0xAA, "Shared_Parameter_Blocks"}, + {0, 0xAB, "Create_New_Effect_Report"}, + {0, 0xAC, "RAM_Pool_Available"}, { 0, 0, NULL } }; @@ -176,7 +282,50 @@ tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); } if (field->unit) { - tab(n); printk("Unit(%u)\n", field->unit); + char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; + char *units[5][8] = { + { "None", "None", "None", "None", "None", "None", "None", "None" }, + { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, + { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } + }; + + int i; + int sys; + __u32 data = field->unit; + + /* First nibble tells us which system we're in. */ + sys = data & 0xf; + data >>= 4; + + if(sys > 4) { + tab(n); printk("Unit(Invalid)\n"); + } + else { + int earlier_unit = 0; + + tab(n); printk("Unit(%s : ", systems[sys]); + + for (i=1 ; i>= 4; + if (nibble != 0) { + if(earlier_unit++ > 0) + printk("*"); + printk("%s", units[sys][i]); + if(nibble != 1) { + /* This is a _signed_ nibble(!) */ + + int val = nibble & 0x7; + if(nibble & 0x08) + val = -((0x7 & ~val) +1); + printk("^%d", val); + } + } + } + printk(")\n"); + } } tab(n); printk("Report Size(%u)\n", field->report_size); tab(n); printk("Report Count(%u)\n", field->report_count); diff -Nru a/drivers/usb/hid-input.c b/drivers/usb/hid-input.c --- a/drivers/usb/hid-input.c Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/hid-input.c Mon Feb 11 23:34:47 2002 @@ -1,11 +1,9 @@ /* - * $Id: hid-input.c,v 1.5 2001/05/23 09:25:02 vojtech Exp $ + * $Id: hid-input.c,v 1.18 2001/11/07 09:01:18 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * - * USB HID to Linux Input mapping module - * - * Sponsored by SuSE + * USB HID to Linux Input mapping */ /* @@ -24,13 +22,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include #include -#include #include #include #include @@ -61,12 +58,13 @@ static struct { __s32 x; __s32 y; -} hid_hat_to_axis[] = {{0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; +} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage) { struct input_dev *input = &device->input; int max; + int is_abs = 0; unsigned long *bit; switch (usage->hid & HID_USAGE_PAGE) { @@ -198,6 +196,7 @@ case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ + set_bit(EV_REP, input->evbit); switch (usage->hid & HID_USAGE) { case 0x000: usage->code = 0; break; case 0x034: usage->code = KEY_SLEEP; break; @@ -205,14 +204,21 @@ case 0x08a: usage->code = KEY_WWW; break; case 0x095: usage->code = KEY_HELP; break; + case 0x0b0: usage->code = KEY_PLAY; break; + case 0x0b1: usage->code = KEY_PAUSE; break; + case 0x0b2: usage->code = KEY_RECORD; break; + case 0x0b3: usage->code = KEY_FASTFORWARD; break; case 0x0b4: usage->code = KEY_REWIND; break; case 0x0b5: usage->code = KEY_NEXTSONG; break; case 0x0b6: usage->code = KEY_PREVIOUSSONG; break; case 0x0b7: usage->code = KEY_STOPCD; break; case 0x0b8: usage->code = KEY_EJECTCD; break; case 0x0cd: usage->code = KEY_PLAYPAUSE; break; - + case 0x0e0: is_abs = 1; + usage->code = ABS_VOLUME; + break; case 0x0e2: usage->code = KEY_MUTE; break; + case 0x0e5: usage->code = KEY_BASSBOOST; break; case 0x0e9: usage->code = KEY_VOLUMEUP; break; case 0x0ea: usage->code = KEY_VOLUMEDOWN; break; @@ -220,7 +226,6 @@ case 0x18a: usage->code = KEY_MAIL; break; case 0x192: usage->code = KEY_CALC; break; case 0x194: usage->code = KEY_FILE; break; - case 0x21a: usage->code = KEY_UNDO; break; case 0x21b: usage->code = KEY_COPY; break; case 0x21c: usage->code = KEY_CUT; break; @@ -235,6 +240,34 @@ case 0x22a: usage->code = KEY_BOOKMARKS; break; default: usage->code = KEY_UNKNOWN; break; + } + + if (is_abs) { + usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; + } else { + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + } + break; + + case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ + + set_bit(EV_REP, input->evbit); + switch (usage->hid & HID_USAGE) { + case 0x021: usage->code = KEY_PRINT; break; + case 0x070: usage->code = KEY_HP; break; + case 0x071: usage->code = KEY_CAMERA; break; + case 0x072: usage->code = KEY_SOUND; break; + case 0x073: usage->code = KEY_QUESTION; break; + + case 0x080: usage->code = KEY_EMAIL; break; + case 0x081: usage->code = KEY_CHAT; break; + case 0x082: usage->code = KEY_SEARCH; break; + case 0x083: usage->code = KEY_CONNECT; break; + case 0x084: usage->code = KEY_FINANCE; break; + case 0x085: usage->code = KEY_SPORT; break; + case 0x086: usage->code = KEY_SHOP; break; + + default: usage->code = KEY_UNKNOWN; break; } @@ -353,7 +386,7 @@ } hid_set_field(field, offset, value); - hid_write_report(hid, field->report); + hid_submit_report(hid, field->report, USB_DIR_OUT); return 0; } @@ -397,6 +430,8 @@ hid->input.close = hidinput_close; hid->input.name = hid->name; + hid->input.phys = hid->phys; + hid->input.uniq = hid->uniq; hid->input.idbus = BUS_USB; hid->input.idvendor = dev->descriptor.idVendor; hid->input.idproduct = dev->descriptor.idProduct; diff -Nru a/drivers/usb/hid.h b/drivers/usb/hid.h --- a/drivers/usb/hid.h Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/hid.h Mon Feb 11 23:34:47 2002 @@ -2,12 +2,10 @@ #define __HID_H /* - * $Id: hid.h,v 1.10 2001/05/10 15:56:07 vojtech Exp $ + * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* @@ -26,13 +24,24 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#include +#include +#include + +/* + * USB HID (Human Interface Device) interface class code + */ + +#define USB_INTERFACE_CLASS_HID 3 + /* * HID class requests */ + #define HID_REQ_GET_REPORT 0x01 #define HID_REQ_GET_IDLE 0x02 #define HID_REQ_GET_PROTOCOL 0x03 @@ -43,86 +52,12 @@ /* * HID class descriptor types */ + #define HID_DT_HID (USB_TYPE_CLASS | 0x01) #define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) #define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) /* - * Utilities for class control messaging - */ -static inline int -hid_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (duration << 8) | report_id, ifnum, NULL, 0, - HZ * USB_CTRL_SET_TIMEOUT); -} - -static inline int -hid_get_protocol(struct usb_device *dev, int ifnum) -{ - unsigned char type; - int ret; - - if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - HID_REQ_GET_PROTOCOL, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, ifnum, &type, 1, - HZ * USB_CTRL_GET_TIMEOUT)) < 0) - return ret; - - return type; -} - -static inline int -hid_set_protocol(struct usb_device *dev, int ifnum, int protocol) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - HID_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - protocol, ifnum, NULL, 0, - HZ * USB_CTRL_SET_TIMEOUT); -} - -static inline int -hid_get_report(struct usb_device *dev, int ifnum, unsigned char type, - unsigned char id, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - HID_REQ_GET_REPORT, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, ifnum, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); -} - -static inline int -hid_set_report(struct usb_device *dev, int ifnum, unsigned char type, - unsigned char id, void *buf, int size) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - HID_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, ifnum, buf, size, HZ); - // FIXME USB_CTRL_SET_TIMEOUT -} - - -/* - * "Boot Protocol" keyboard/mouse drivers use don't use all of HID; - * they're a lot smaller but can't support all the device features. - */ -#ifndef _HID_BOOT_PROTOCOL - -#include -#include -#include - -/* - * USB HID (Human Interface Device) interface class code - */ - -#define USB_INTERFACE_CLASS_HID 3 - -/* * We parse each description item into this structure. Short items data * values are expanded to 32-bit signed int, long items contain a pointer * into the data area. @@ -240,9 +175,11 @@ #define HID_UP_KEYBOARD 0x00070000 #define HID_UP_LED 0x00080000 #define HID_UP_BUTTON 0x00090000 +#define HID_UP_ORDINAL 0x000a0000 #define HID_UP_CONSUMER 0x000c0000 #define HID_UP_DIGITIZER 0x000d0000 #define HID_UP_PID 0x000f0000 +#define HID_UP_HPVENDOR 0xff7f0000 #define HID_USAGE 0x0000ffff @@ -279,7 +216,7 @@ __s32 logical_maximum; __s32 physical_minimum; __s32 physical_maximum; - unsigned unit_exponent; + __s32 unit_exponent; unsigned unit; unsigned report_id; unsigned report_size; @@ -336,7 +273,7 @@ __s32 logical_maximum; __s32 physical_minimum; __s32 physical_maximum; - unsigned unit_exponent; + __s32 unit_exponent; unsigned unit; struct hid_report *report; /* associated report */ }; @@ -350,8 +287,6 @@ struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ unsigned maxfield; /* maximum valid field index */ unsigned size; /* size of the report (bits) */ - unsigned idx; /* where we're in data */ - unsigned char *data; /* data for multi-packet reports */ struct hid_device *device; /* associated device */ }; @@ -364,16 +299,20 @@ #define HID_REPORT_TYPES 3 #define HID_BUFFER_SIZE 32 -#define HID_CONTROL_FIFO_SIZE 8 +#define HID_CONTROL_FIFO_SIZE 64 +#define HID_OUTPUT_FIFO_SIZE 64 struct hid_control_fifo { - struct usb_ctrlrequest dr; - char buffer[HID_BUFFER_SIZE]; + unsigned char dir; + struct hid_report *report; }; #define HID_CLAIMED_INPUT 1 #define HID_CLAIMED_HIDDEV 2 +#define HID_CTRL_RUNNING 1 +#define HID_OUT_RUNNING 2 + struct hid_device { /* device report descriptor */ __u8 *rdesc; unsigned rsize; @@ -386,12 +325,23 @@ struct usb_device *dev; /* USB device */ int ifnum; /* USB interface number */ - struct urb urb; /* USB URB structure */ - char buffer[HID_BUFFER_SIZE]; /* Rx buffer */ + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ - struct urb urbout; /* Output URB */ - struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */ - unsigned char outhead, outtail; /* Tx buffer head & tail */ + struct urb *urbin; /* Input URB */ + char inbuf[HID_BUFFER_SIZE]; /* Input buffer */ + + struct urb *urbctrl; /* Control URB */ + struct usb_ctrlrequest cr; /* Control request struct */ + struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ + unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ + char ctrlbuf[HID_BUFFER_SIZE]; /* Control buffer */ + spinlock_t ctrllock; /* Control fifo spinlock */ + + struct urb *urbout; /* Output URB */ + struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ + unsigned char outhead, outtail; /* Output pipe fifo head & tail */ + char outbuf[HID_BUFFER_SIZE]; /* Output buffer */ + spinlock_t outlock; /* Output fifo spinlock */ unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */ @@ -400,8 +350,12 @@ void *hiddev; /* The hiddev structure */ int minor; /* Hiddev minor number */ + wait_queue_head_t wait; /* For sleeping */ + int open; /* is the device open by anyone? */ char name[128]; /* Device name */ + char phys[64]; /* Device physical location */ + char uniq[64]; /* Device unique identifier (serial #) */ }; #define HID_GLOBAL_STACK_SIZE 4 @@ -441,19 +395,18 @@ #else #define hid_dump_input(a,b) do { } while (0) #define hid_dump_device(c) do { } while (0) -#endif /* DEBUG */ +#define hid_dump_field(a,b) do { } while (0) +#endif -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || ( a == 0x000c0001)) +#endif + +/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ +/* We ignore a few input applications that are not widely used */ +#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001)) int hid_open(struct hid_device *); void hid_close(struct hid_device *); int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **); int hid_set_field(struct hid_field *, unsigned, __s32); -void hid_write_report(struct hid_device *, struct hid_report *); -void hid_read_report(struct hid_device *, struct hid_report *); +void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); void hid_init_reports(struct hid_device *hid); - -#endif /* !_HID_BOOT_PROTOCOL */ - -#endif /* !__HID_H */ - diff -Nru a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c --- a/drivers/usb/hiddev.c Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/hiddev.c Mon Feb 11 23:34:47 2002 @@ -400,7 +400,7 @@ if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_read_report(hid, report); + hid_submit_report(hid, report, USB_DIR_IN); return 0; @@ -414,7 +414,7 @@ if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_write_report(hid, report); + hid_submit_report(hid, report, USB_DIR_OUT); return 0; diff -Nru a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c --- a/drivers/usb/usbkbd.c Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/usbkbd.c Mon Feb 11 23:34:47 2002 @@ -1,11 +1,9 @@ /* - * $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $ + * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Keyboard support - * - * Sponsored by SuSE */ /* @@ -24,8 +22,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -35,19 +33,17 @@ #include #include -#define _HID_BOOT_PROTOCOL -#include "hid.h" - /* * Version Information */ #define DRIVER_VERSION "" -#define DRIVER_AUTHOR "Vojtech Pavlik " +#define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB HID Boot Protocol keyboard driver" +#define DRIVER_LICENSE "GPL" -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); static unsigned char usb_kbd_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, @@ -74,9 +70,10 @@ unsigned char new[8]; unsigned char old[8]; struct urb *irq, *led; - struct usb_ctrlrequest dr; + struct usb_ctrlrequest cr; unsigned char leds, newleds; char name[128]; + char phys[64]; int open; }; @@ -129,7 +126,7 @@ kbd->leds = kbd->newleds; kbd->led->dev = kbd->usbdev; - if (usb_submit_urb(kbd->led, GFP_KERNEL)) + if (usb_submit_urb(kbd->led, GFP_ATOMIC)) err("usb_submit_urb(leds) failed"); return 0; @@ -147,7 +144,7 @@ kbd->leds = kbd->newleds; kbd->led->dev = kbd->usbdev; - if (usb_submit_urb(kbd->led, GFP_KERNEL)) + if (usb_submit_urb(kbd->led, GFP_ATOMIC)) err("usb_submit_urb(leds) failed"); } @@ -181,6 +178,7 @@ struct usb_endpoint_descriptor *endpoint; struct usb_kbd *kbd; int i, pipe, maxp; + char path[64]; char *buf; iface = &dev->actconfig->interface[ifnum]; @@ -195,9 +193,6 @@ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - hid_set_protocol(dev, interface->bInterfaceNumber, 0); - hid_set_idle(dev, interface->bInterfaceNumber, 0, 0); - if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL; memset(kbd, 0, sizeof(struct usb_kbd)); @@ -230,13 +225,17 @@ FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, usb_kbd_irq, kbd, endpoint->bInterval); - kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kbd->dr.bRequest = HID_REQ_SET_REPORT; - kbd->dr.wValue = 0x200; - kbd->dr.wIndex = interface->bInterfaceNumber; - kbd->dr.wLength = 1; + kbd->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kbd->cr.bRequest = 0x09; + kbd->cr.wValue = 0x200; + kbd->cr.wIndex = interface->bInterfaceNumber; + kbd->cr.wLength = 1; + + usb_make_path(dev, path, 64); + sprintf(kbd->phys, "%s/input0", path); kbd->dev.name = kbd->name; + kbd->dev.phys = kbd->phys; kbd->dev.idbus = BUS_USB; kbd->dev.idvendor = dev->descriptor.idVendor; kbd->dev.idproduct = dev->descriptor.idProduct; @@ -261,12 +260,11 @@ kfree(buf); FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0), - (void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd); + (void*) &kbd->cr, &kbd->leds, 1, usb_kbd_led, kbd); input_register_device(&kbd->dev); - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum); + printk(KERN_INFO "input: %s on %s\n", kbd->name, path); return kbd; } diff -Nru a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c --- a/drivers/usb/usbmouse.c Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/usbmouse.c Mon Feb 11 23:34:47 2002 @@ -1,11 +1,9 @@ /* - * $Id: usbmouse.c,v 1.6 2000/08/14 21:05:26 vojtech Exp $ + * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Mouse support - * - * Sponsored by SuSE */ /* @@ -24,8 +22,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -35,23 +33,22 @@ #include #include -#define _HID_BOOT_PROTOCOL -#include "hid.h" - /* * Version Information */ #define DRIVER_VERSION "v1.6" -#define DRIVER_AUTHOR "Vojtech Pavlik " +#define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB HID Boot Protocol mouse driver" +#define DRIVER_LICENSE "GPL" -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); struct usb_mouse { signed char data[8]; char name[128]; + char phys[64]; struct usb_device *usbdev; struct input_dev dev; struct urb *irq; @@ -107,6 +104,7 @@ struct usb_endpoint_descriptor *endpoint; struct usb_mouse *mouse; int pipe, maxp; + char path[64]; char *buf; iface = &dev->actconfig->interface[ifnum]; @@ -121,8 +119,6 @@ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - hid_set_idle(dev, interface->bInterfaceNumber, 0, 0); - if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL; memset(mouse, 0, sizeof(struct usb_mouse)); @@ -144,7 +140,11 @@ mouse->dev.open = usb_mouse_open; mouse->dev.close = usb_mouse_close; + usb_make_path(dev, path, 64); + sprintf(mouse->phys, "%s/input0", path); + mouse->dev.name = mouse->name; + mouse->dev.phys = mouse->phys; mouse->dev.idbus = BUS_USB; mouse->dev.idvendor = dev->descriptor.idVendor; mouse->dev.idproduct = dev->descriptor.idProduct; @@ -173,8 +173,7 @@ input_register_device(&mouse->dev); - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum); + printk(KERN_INFO "input: %s on %s\n", mouse->name, path); return mouse; } diff -Nru a/drivers/usb/wacom.c b/drivers/usb/wacom.c --- a/drivers/usb/wacom.c Mon Feb 11 23:34:47 2002 +++ b/drivers/usb/wacom.c Mon Feb 11 23:34:47 2002 @@ -1,7 +1,7 @@ /* - * $Id: wacom.c,v 1.22 2001/04/26 11:26:09 vojtech Exp $ + * $Id: wacom.c,v 1.28 2001/09/25 10:12:07 vojtech Exp $ * - * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Andreas Bach Aaen * Copyright (c) 2000 Clifford Wolf * Copyright (c) 2000 Sam Mosel @@ -11,8 +11,6 @@ * * USB Wacom Graphire and Wacom Intuos tablet support * - * Sponsored by SuSE - * * ChangeLog: * v0.1 (vp) - Initial release * v0.2 (aba) - Support for all buttons / combinations @@ -57,8 +55,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -72,12 +70,13 @@ * Version Information */ #define DRIVER_VERSION "v1.21" -#define DRIVER_AUTHOR "Vojtech Pavlik " +#define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" +#define DRIVER_LICENSE "GPL" -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); #define USB_VENDOR_ID_WACOM 0x056a @@ -106,6 +105,7 @@ int open; int x, y; __u32 serial[2]; + char phys[32]; }; static void wacom_pl_irq(struct urb *urb) @@ -354,6 +354,7 @@ { struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; + char path[64]; if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL; memset(wacom, 0, sizeof(struct wacom)); @@ -394,7 +395,11 @@ wacom->dev.open = wacom_open; wacom->dev.close = wacom_close; + usb_make_path(dev, path, 64); + sprintf(wacom->phys, "%s/input0", path); + wacom->dev.name = wacom->features->name; + wacom->dev.phys = wacom->phys; wacom->dev.idbus = BUS_USB; wacom->dev.idvendor = dev->descriptor.idVendor; wacom->dev.idproduct = dev->descriptor.idProduct; @@ -408,8 +413,7 @@ input_register_device(&wacom->dev); - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); + printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path); return wacom; }