diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-07-15 04:18:33 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-07-15 04:18:33 -0700 |
| commit | 7fde4915a17dec953900e02252a013abcd37cdab (patch) | |
| tree | 979378c5634df2afa0ffe27a5a0791c086bb135c | |
| parent | 4ba438aa3dbbcf2da7cac26c11420d3d868adb7c (diff) | |
| parent | 12c2451cfee6e25118fb3c8684ada795638ed9dd (diff) | |
Merge http://linuxusb.bkbits.net/linus-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
| -rw-r--r-- | Documentation/usb/hiddev.txt | 15 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-dbg.c | 29 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 10 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-q.c | 68 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-sa1111.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/ohci.h | 17 | ||||
| -rw-r--r-- | drivers/usb/input/hid-core.c | 168 | ||||
| -rw-r--r-- | drivers/usb/input/hid-debug.h | 6 | ||||
| -rw-r--r-- | drivers/usb/input/hid-input.c | 7 | ||||
| -rw-r--r-- | drivers/usb/input/hid.h | 12 | ||||
| -rw-r--r-- | drivers/usb/input/hiddev.c | 199 | ||||
| -rw-r--r-- | drivers/usb/storage/transport.c | 6 | ||||
| -rw-r--r-- | include/linux/hiddev.h | 27 |
13 files changed, 364 insertions, 202 deletions
diff --git a/Documentation/usb/hiddev.txt b/Documentation/usb/hiddev.txt index 31250f38b45f..470840b5be5f 100644 --- a/Documentation/usb/hiddev.txt +++ b/Documentation/usb/hiddev.txt @@ -18,7 +18,7 @@ normalised event interface - see Documentation/input/input.txt The data flow for a HID event produced by a device is something like the following : - usb.c ---> hid-core.c ----> input.c ----> [keyboard/mouse/joystick/event] + usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event] | | --> hiddev.c ----> POWER / MONITOR CONTROL @@ -106,6 +106,15 @@ returns -1. You can find out beforehand how many application collections the device has from the num_applications field from the hiddev_devinfo structure. +HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write) +This returns a superset of the information above, providing not only +application collections, but all the collections the device has. It +also returns the level the collection lives in the hierarchy. +The user passes in a hiddev_collection_info struct with the index +field set to the index that should be returned. The ioctl fills in +the other fields. If the index is larger than the last collection +index, the ioctl returns -1 and sets errno to -EINVAL. + HIDIOCGDEVINFO - struct hiddev_devinfo (read) Gets a hiddev_devinfo structure which describes the device. @@ -172,6 +181,10 @@ Sets the value of a usage in an output report. The user fills in the hiddev_usage_ref structure as above, but additionally fills in the value field. +HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write) +Returns the collection index associated with this usage. This +indicates where in the collection hierarchy this usage sits. + HIDIOCGFLAG - int (read) HIDIOCSFLAG - int (write) These operations respectively inspect and replace the mode flags diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 1d9bd9c37300..b968cfe92d35 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -12,13 +12,14 @@ #ifdef DEBUG -#define pipestring(pipe) ({ char *temp; \ - switch (usb_pipetype (pipe)) { \ +#define edstring(ed_type) ({ char *temp; \ + switch (ed_type) { \ case PIPE_CONTROL: temp = "CTRL"; break; \ case PIPE_BULK: temp = "BULK"; break; \ case PIPE_INTERRUPT: temp = "INTR"; break; \ default: temp = "ISOC"; break; \ }; temp;}) +#define pipestring(pipe) edstring(usb_pipetype(pipe)) /* debug| print the main components of an URB * small: 0) header + data packets 1) just header @@ -35,9 +36,9 @@ static void urb_print (struct urb * urb, char * str, int small) #ifndef OHCI_VERBOSE_DEBUG if (urb->status != 0) #endif - dbg("%s:[%4x] dev:%d,ep=%d-%c,%s,flags:%4x,len:%d/%d,stat:%d", + dbg("%s %p dev:%d,ep=%d-%c,%s,flags:%x,len:%d/%d,stat:%d", str, - usb_get_current_frame_number (urb->dev), + urb, usb_pipedevice (pipe), usb_pipeendpoint (pipe), usb_pipeout (pipe)? 'O': 'I', @@ -242,21 +243,25 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose) ohci_dump_roothub (controller, 1); } +static const char data0 [] = "DATA0"; +static const char data1 [] = "DATA1"; + static void ohci_dump_td (char *label, struct td *td) { u32 tmp = le32_to_cpup (&td->hwINFO); - dbg ("%s td %p; urb %p index %d; hw next td %08x", + dbg ("%s td %p%s; urb %p index %d; hw next td %08x", label, td, + (tmp & TD_DONE) ? " (DONE)" : "", td->urb, td->index, le32_to_cpup (&td->hwNextTD)); if ((tmp & TD_ISO) == 0) { - char *toggle, *pid; + const char *toggle, *pid; u32 cbp, be; switch (tmp & TD_T) { - case TD_T_DATA0: toggle = "DATA0"; break; - case TD_T_DATA1: toggle = "DATA1"; break; + case TD_T_DATA0: toggle = data0; break; + case TD_T_DATA1: toggle = data1; break; case TD_T_TOGGLE: toggle = "(CARRY)"; break; default: toggle = "(?)"; break; } @@ -297,9 +302,9 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose) u32 tmp = ed->hwINFO; char *type = ""; - dbg ("%s: %s, ed %p state 0x%x type %d; next ed %08x", + dbg ("%s: %s, ed %p state 0x%x type %s; next ed %08x", ohci->hcd.self.bus_name, label, - ed, ed->state, ed->type, + ed, ed->state, edstring (ed->type), le32_to_cpup (&ed->hwNextED)); switch (tmp & (ED_IN|ED_OUT)) { case ED_OUT: type = "-OUT"; break; @@ -314,10 +319,10 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose) 0x000f & (le32_to_cpu (tmp) >> 7), type, 0x007f & le32_to_cpu (tmp)); - dbg (" tds: head %08x%s%s tail %08x%s", + dbg (" tds: head %08x %s%s tail %08x%s", tmp = le32_to_cpup (&ed->hwHeadP), + (ed->hwHeadP & ED_C) ? data1 : data0, (ed->hwHeadP & ED_H) ? " HALT" : "", - (ed->hwHeadP & ED_C) ? " CARRY" : "", le32_to_cpup (&ed->hwTailP), verbose ? "" : " (not listing)"); if (verbose) { diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index db4276ead92c..a56ae64e60cc 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -197,7 +197,7 @@ static int ohci_urb_enqueue ( /* allocate the TDs (updating hash chains) */ spin_lock_irqsave (&ohci->lock, flags); - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) { urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC); if (!urb_priv->td [i]) { urb_priv->length = i; @@ -208,6 +208,8 @@ static int ohci_urb_enqueue ( } // FIXME: much of this switch should be generic, move to hcd code ... +// ... and what's not generic can't really be handled this way. +// need to consider periodicity for both types! /* allocate and claim bandwidth if needed; ISO * needs start frame index if it was't provided. @@ -247,14 +249,14 @@ static int ohci_urb_enqueue ( spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + return 0; } /* * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked for deletion. reporting is always done + * already marked using urb->status. reporting is always done * asynchronously, and we might be dealing with an urb that's - * almost completed anyway... + * partially transferred, or an ED with other urbs being unlinked. */ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index c3f19885b4bc..1d3de55b90b9 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -465,6 +465,25 @@ static struct ed *ed_get ( * we know it's already a power of 2 */ ed->interval = interval; +#ifdef DEBUG + /* + * There are two other cases we ought to change hwINFO, both during + * enumeration. There, the control request completes, unlinks, and + * the next request gets queued before the unlink completes, so it + * uses old/wrong hwINFO. How much of a problem is this? khubd is + * already retrying after such failures... + */ + } else if (type == PIPE_CONTROL) { + u32 info = le32_to_cpup (&ed->hwINFO); + + if (!(info & 0x7f)) + dbg ("RETRY ctrl: address != 0"); + info >>= 16; + if (info != udev->epmaxpacketin [0]) + dbg ("RETRY ctrl: maxpacket %d != 8", + udev->epmaxpacketin [0]); + +#endif /* DEBUG */ } done: @@ -539,12 +558,15 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, /* aim for only one interrupt per urb. mostly applies to control * and iso; other urbs rarely need more than one TD per urb. + * this way, only final tds (or ones with an error) cause IRQs. * * NOTE: could delay interrupts even for the last TD, and get fewer * interrupts ... increasing per-urb latency by sharing interrupts. + * Drivers that queue bulk urbs may request that behavior. */ - if (index != (urb_priv->length - 1)) - info |= is_iso ? TD_DI_SET (7) : TD_DI_SET (1); + if (index != (urb_priv->length - 1) + || (urb->transfer_flags & URB_NO_INTERRUPT)) + info |= TD_DI_SET (7); /* use this td as the next dummy */ td_pt = urb_priv->td [index]; @@ -565,6 +587,7 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, td->hwINFO = cpu_to_le32 (info); if (is_iso) { td->hwCBP = cpu_to_le32 (data & 0xFFFFF000); + td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000); td->ed->intriso.last_iso = info & 0xffff; } else { td->hwCBP = cpu_to_le32 (data); @@ -574,7 +597,6 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, else td->hwBE = 0; td->hwNextTD = cpu_to_le32 (td_pt->td_dma); - td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000); /* HC might read the TD right after we link it ... */ wmb (); @@ -596,17 +618,17 @@ static void td_submit_urb (struct urb *urb) int cnt = 0; __u32 info = 0; unsigned int toggle = 0; + int is_out = usb_pipeout (urb->pipe); /* OHCI handles the DATA-toggles itself, we just use the * USB-toggle bits for resetting */ - if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe))) { + if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { toggle = TD_T_TOGGLE; } else { toggle = TD_T_DATA0; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe), 1); + is_out, 1); } urb_priv->td_cnt = 0; @@ -614,9 +636,9 @@ static void td_submit_urb (struct urb *urb) if (data_len) { data = pci_map_single (ohci->hcd.pdev, urb->transfer_buffer, data_len, - usb_pipeout (urb->pipe) - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); + is_out + ? PCI_DMA_TODEVICE + : PCI_DMA_FROMDEVICE); } else data = 0; @@ -625,18 +647,20 @@ static void td_submit_urb (struct urb *urb) */ switch (usb_pipetype (urb->pipe)) { case PIPE_BULK: - info = usb_pipeout (urb->pipe) + info = is_out ? TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ; + /* TDs _could_ transfer up to 8K each */ while (data_len > 4096) { td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt); data += 4096; data_len -= 4096; cnt++; } - info = usb_pipeout (urb->pipe)? - TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; - td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), + /* maybe avoid ED halt on final TD short read */ + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + info |= TD_R; + td_fill (ohci, info | (cnt ? TD_T_TOGGLE : toggle), data, data_len, urb, cnt); cnt++; if ((urb->transfer_flags & USB_ZERO_PACKET) @@ -653,8 +677,11 @@ static void td_submit_urb (struct urb *urb) break; case PIPE_INTERRUPT: + /* current policy: only one TD per request. + * otherwise identical to bulk, except for BLF + */ info = TD_CC | toggle; - info |= usb_pipeout (urb->pipe) + info |= is_out ? TD_DP_OUT : TD_R | TD_DP_IN; td_fill (ohci, info, data, data_len, urb, cnt++); @@ -670,14 +697,12 @@ static void td_submit_urb (struct urb *urb) 8, urb, cnt++); if (data_len > 0) { info = TD_CC | TD_R | TD_T_DATA1; - info |= usb_pipeout (urb->pipe) - ? TD_DP_OUT - : TD_DP_IN; + info |= is_out ? TD_DP_OUT : TD_DP_IN; /* NOTE: mishandles transfers >8K, some >4K */ td_fill (ohci, info, data, data_len, urb, cnt++); } - info = usb_pipeout (urb->pipe) + info = is_out ? TD_CC | TD_DP_IN | TD_T_DATA1 : TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill (ohci, info, data, 0, urb, cnt++); @@ -806,10 +831,13 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) while (td_list_hc) { td_list = dma_to_td (ohci, td_list_hc); + td_list->hwINFO |= cpu_to_le32 (TD_DONE); + if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) { urb_priv = (urb_priv_t *) td_list->urb->hcpriv; - /* typically the endpoint halts on error; un-halt, - * and maybe dequeue other TDs from this urb + /* Non-iso endpoints can halt on error; un-halt, + * and dequeue any other TDs from this urb. + * No other TD could have caused the halt. */ if (td_list->ed->hwHeadP & ED_H) { if (urb_priv && ((td_list->index + 1) diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 11967b45be07..95fc8b82af57 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -175,7 +175,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o usb_bus_init (&hcd->self); hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = (void *) hcd; - hcd->self.bus_name = "SA-1111"; + hcd->self.bus_name = "sa1111"; hcd->product_desc = "SA-1111 OHCI"; INIT_LIST_HEAD (&hcd->dev_list); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index d5fc9517f132..7969e669052d 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -11,6 +11,9 @@ /* * OHCI Endpoint Descriptor (ED) ... holds TD queue * See OHCI spec, section 4.2 + * + * This is a "Queue Head" for those transfers, which is why + * both EHCI and UHCI call similar structures a "QH". */ struct ed { /* first fields are hardware-specified, le32 */ @@ -74,8 +77,8 @@ struct td { /* these two bits are available for definition/use by HCDs in both * general and iso tds ... others are available for only one type */ -//#define TD____ 0x00020000 -#define TD_ISO 0x00010000 /* copy of ED_ISO */ +#define TD_DONE 0x00020000 /* retired to donelist */ +#define TD_ISO 0x00010000 /* copy of ED_ISO */ /* hwINFO bits for general tds: */ #define TD_EC 0x0C000000 /* error count */ @@ -349,12 +352,14 @@ struct ohci_hcd { struct device *parent_dev; /* - * I/O memory used to communicate with the HC (uncached); + * I/O memory used to communicate with the HC (dma-consistent) */ struct ohci_regs *regs; /* - * main memory used to communicate with the HC (uncached) + * main memory used to communicate with the HC (dma-consistent). + * hcd adds to schedule for a live hc any time, but removals finish + * only at the start of the next frame. */ struct ohci_hcca *hcca; dma_addr_t hcca_dma; @@ -365,6 +370,9 @@ struct ohci_hcd { struct ed *ed_controltail; /* last in ctrl list */ struct ed *ed_isotail; /* last in iso list */ + /* + * memory management for queue data structures + */ struct pci_pool *td_cache; struct pci_pool *ed_cache; struct hash_list_t td_hash [TD_HASH_SIZE]; @@ -380,6 +388,7 @@ struct ohci_hcd { unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ + // there are also chip quirks/bugs in init logic /* * framework state diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index ca7b3f198390..068417749db6 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -127,18 +127,41 @@ static int open_collection(struct hid_parser *parser, unsigned type) usage = parser->local.usage[0]; - if (type == HID_COLLECTION_APPLICATION - && parser->device->maxapplication < HID_MAX_APPLICATIONS) - parser->device->application[parser->device->maxapplication++] = usage; - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { dbg("collection stack overflow"); return -1; } - collection = parser->collection_stack + parser->collection_stack_ptr++; + if (parser->device->maxcollection == parser->device->collection_size) { + collection = kmalloc(sizeof(struct hid_collection) * + parser->device->collection_size * 2, + GFP_KERNEL); + if (collection == NULL) { + dbg("failed to reallocate collection array"); + return -1; + } + memcpy(collection, parser->device->collection, + sizeof(struct hid_collection) * + parser->device->collection_size); + memset(collection + parser->device->collection_size, 0, + sizeof(struct hid_collection) * + parser->device->collection_size); + kfree(parser->device->collection); + parser->device->collection = collection; + parser->device->collection_size *= 2; + } + + parser->collection_stack[parser->collection_stack_ptr++] = + parser->device->maxcollection; + + collection = parser->device->collection + + parser->device->maxcollection++; collection->type = type; collection->usage = usage; + collection->level = parser->collection_stack_ptr - 1; + + if (type == HID_COLLECTION_APPLICATION) + parser->device->maxapplication++; return 0; } @@ -166,8 +189,8 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) { int n; for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->collection_stack[n].type == type) - return parser->collection_stack[n].usage; + if (parser->device->collection[parser->collection_stack[n]].type == type) + return parser->device->collection[parser->collection_stack[n]].usage; return 0; /* we know nothing about this usage type */ } @@ -181,7 +204,11 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage) dbg("usage index exceeded"); return -1; } - parser->local.usage[parser->local.usage_index++] = usage; + parser->local.usage[parser->local.usage_index] = usage; + parser->local.collection_index[parser->local.usage_index] = + parser->collection_stack_ptr ? + parser->collection_stack[parser->collection_stack_ptr - 1] : 0; + parser->local.usage_index++; return 0; } @@ -221,8 +248,11 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - for (i = 0; i < usages; i++) + for (i = 0; i < usages; i++) { field->usage[i].hid = parser->local.usage[i]; + field->usage[i].collection_index = + parser->local.collection_index[i]; + } field->maxusage = usages; field->flags = flags; @@ -460,7 +490,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) switch (item->tag) { case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 3); + ret = open_collection(parser, data & 0xff); break; case HID_MAIN_ITEM_TAG_END_COLLECTION: ret = close_collection(parser); @@ -621,17 +651,30 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) return NULL; memset(device, 0, sizeof(struct hid_device)); + if (!(device->collection = kmalloc(sizeof(struct hid_collection) * + HID_DEFAULT_NUM_COLLECTIONS, + GFP_KERNEL))) { + kfree(device); + return NULL; + } + memset(device->collection, 0, sizeof(struct hid_collection) * + HID_DEFAULT_NUM_COLLECTIONS); + device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; + for (i = 0; i < HID_REPORT_TYPES; i++) INIT_LIST_HEAD(&device->report_enum[i].report_list); if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { + kfree(device->collection); kfree(device); return NULL; } memcpy(device->rdesc, start, size); + device->rsize = size; if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { kfree(device->rdesc); + kfree(device->collection); kfree(device); return NULL; } @@ -643,6 +686,8 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); + kfree(device->rdesc); + kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -651,6 +696,8 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) 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); + kfree(device->rdesc); + kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -659,12 +706,16 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (start == end) { if (parser->collection_stack_ptr) { dbg("unbalanced collection at end of report description"); + kfree(device->rdesc); + kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; } if (parser->local.delimiter_depth) { dbg("unbalanced delimiter at end of report description"); + kfree(device->rdesc); + kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -675,6 +726,8 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) } dbg("item fetching failed at offset %d\n", (int)(end - start)); + kfree(device->rdesc); + kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -740,22 +793,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s hid_dump_input(usage, value); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value); -#ifdef CONFIG_USB_HIDDEV - if (hid->claimed & HID_CLAIMED_HIDDEV) { - struct hiddev_usage_ref uref; - unsigned type = field->report_type; - uref.report_type = - (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : - ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : - ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); - uref.report_id = field->report->id; - uref.field_index = field->index; - uref.usage_index = (usage - field->usage); - uref.usage_code = usage->hid; - uref.value = value; - hiddev_hid_event(hid, &uref); - } -#endif + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_hid_event(hid, field, usage, value); } /* @@ -851,21 +890,6 @@ static int hid_input_report(int type, struct urb *urb) return -1; } -#ifdef CONFIG_USB_HIDDEV - /* Notify listeners that a report has been received */ - if (hid->claimed & HID_CLAIMED_HIDDEV) { - struct hiddev_usage_ref uref; - memset(&uref, 0, sizeof(uref)); - uref.report_type = - (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : - ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : - ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); - uref.report_id = report->id; - uref.field_index = HID_FIELD_INDEX_NONE; - hiddev_hid_event(hid, &uref); - } -#endif - size = ((report->size - 1) >> 3) + 1; if (len < size) { @@ -873,6 +897,9 @@ static int hid_input_report(int type, struct urb *urb) return -1; } + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_report_event(hid, report); + for (n = 0; n < report->maxfield; n++) hid_input_field(hid, report->field[n], data); @@ -1284,6 +1311,10 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 #define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 +#define USB_VENDOR_ID_MGE 0x0463 +#define USB_DEVICE_ID_MGE_UPS 0xffff +#define USB_DEVICE_ID_MGE_UPS1 0x0001 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1301,6 +1332,8 @@ struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, { 0, 0 } }; @@ -1438,6 +1471,27 @@ fail: return NULL; } +static void hid_disconnect(struct usb_device *dev, void *ptr) +{ + struct hid_device *hid = ptr; + + usb_unlink_urb(hid->urbin); + usb_unlink_urb(hid->urbout); + usb_unlink_urb(hid->urbctrl); + + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_disconnect(hid); + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_disconnect(hid); + + usb_free_urb(hid->urbin); + usb_free_urb(hid->urbctrl); + if (hid->urbout) + usb_free_urb(hid->urbout); + + hid_free_device(hid); +} + static void* hid_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { @@ -1462,7 +1516,7 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum, hid->claimed |= HID_CLAIMED_HIDDEV; if (!hid->claimed) { - hid_free_device(hid); + hid_disconnect(dev, hid); return NULL; } @@ -1476,11 +1530,14 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum, printk("hiddev%d", hid->minor); c = "Device"; - for (i = 0; i < hid->maxapplication; i++) - if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) { - c = hid_types[hid->application[i] & 0xffff]; + for (i = 0; i < hid->maxcollection; i++) { + if (hid->collection[i].type == HID_COLLECTION_APPLICATION && + (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK && + (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) { + c = hid_types[hid->collection[i].usage & 0xffff]; break; } + } usb_make_path(dev, path, 63); @@ -1490,27 +1547,6 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum, return hid; } -static void hid_disconnect(struct usb_device *dev, void *ptr) -{ - struct hid_device *hid = ptr; - - usb_unlink_urb(hid->urbin); - usb_unlink_urb(hid->urbout); - usb_unlink_urb(hid->urbctrl); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_disconnect(hid); - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_disconnect(hid); - - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbctrl); - if (hid->urbout) - usb_free_urb(hid->urbout); - - hid_free_device(hid); -} - static struct usb_device_id hid_usb_ids [] = { { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, bInterfaceClass: USB_INTERFACE_CLASS_HID }, diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index 62757fa2fe05..9ae94a95d7d3 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h @@ -352,12 +352,6 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { unsigned i,k; static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - for (i = 0; i < device->maxapplication; i++) { - printk("Application("); - resolv_usage(device->application[i]); - printk(")\n"); - } - for (i = 0; i < HID_REPORT_TYPES; i++) { report_enum = device->report_enum + i; list = report_enum->report_list.next; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 37f12424cb6f..a036b23f6fa6 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -474,11 +474,12 @@ int hidinput_connect(struct hid_device *hid) struct list_head *list; int i, j, k; - for (i = 0; i < hid->maxapplication; i++) - if (IS_INPUT_APPLICATION(hid->application[i])) + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == HID_COLLECTION_APPLICATION && + IS_INPUT_APPLICATION(hid->collection[i].usage)) break; - if (i == hid->maxapplication) + if (i == hid->maxcollection) return -1; hid->input.private = hid; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 7862be448938..93075dee2db7 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -205,6 +205,7 @@ struct hid_item { #define HID_QUIRK_NOTOUCH 0x02 #define HID_QUIRK_IGNORE 0x04 #define HID_QUIRK_NOGET 0x08 +#define HID_QUIRK_HIDDEV 0x10 /* * This is the global enviroment of the parser. This information is @@ -231,10 +232,11 @@ struct hid_global { #define HID_MAX_DESCRIPTOR_SIZE 4096 #define HID_MAX_USAGES 1024 -#define HID_MAX_APPLICATIONS 16 +#define HID_DEFAULT_NUM_COLLECTIONS 16 struct hid_local { unsigned usage[HID_MAX_USAGES]; /* usage array */ + unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ unsigned usage_index; unsigned usage_minimum; unsigned delimiter_depth; @@ -249,10 +251,12 @@ struct hid_local { struct hid_collection { unsigned type; unsigned usage; + unsigned level; }; struct hid_usage { unsigned hid; /* hid usage code */ + unsigned collection_index; /* index into collection array */ __u16 code; /* input driver code */ __u8 type; /* input driver type */ __s8 hat_min; /* hat switch fun */ @@ -319,7 +323,9 @@ struct hid_control_fifo { struct hid_device { /* device report descriptor */ __u8 *rdesc; unsigned rsize; - unsigned application[HID_MAX_APPLICATIONS]; /* List of HID applications */ + struct hid_collection *collection; /* List of HID collections */ + unsigned collection_size; /* Number of allocated hid_collections */ + unsigned maxcollection; /* Number of parsed collections */ unsigned maxapplication; /* Number of applications */ unsigned version; /* HID version */ unsigned country; /* HID country */ @@ -374,7 +380,7 @@ struct hid_parser { struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; unsigned global_stack_ptr; struct hid_local local; - struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE]; + unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; unsigned collection_stack_ptr; struct hid_device *device; }; diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 8b93b2f0a1bc..563285d58541 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -80,6 +80,7 @@ extern struct usb_driver hiddev_driver; static struct hid_report * hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) { + unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK; struct hid_report_enum *report_enum; struct list_head *list; @@ -88,27 +89,28 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) report_enum = hid->report_enum + (rinfo->report_type - HID_REPORT_TYPE_MIN); - if ((rinfo->report_id & ~HID_REPORT_ID_MASK) != 0) { - switch (rinfo->report_id & ~HID_REPORT_ID_MASK) { - case HID_REPORT_ID_FIRST: - list = report_enum->report_list.next; - if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; - break; - - case HID_REPORT_ID_NEXT: - list = (struct list_head *) - report_enum->report_id_hash[rinfo->report_id & - HID_REPORT_ID_MASK]; - if (list == NULL) return NULL; - list = list->next; - if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; - break; - default: - return NULL; - } + switch (flags) { + case 0: /* Nothing to do -- report_id is already set correctly */ + break; + + case HID_REPORT_ID_FIRST: + list = report_enum->report_list.next; + if (list == &report_enum->report_list) return NULL; + rinfo->report_id = ((struct hid_report *) list)->id; + break; + + case HID_REPORT_ID_NEXT: + list = (struct list_head *) + report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK]; + if (list == NULL) return NULL; + list = list->next; + if (list == &report_enum->report_list) return NULL; + rinfo->report_id = ((struct hid_report *) list)->id; + break; + + default: + return NULL; } return report_enum->report_id_hash[rinfo->report_id]; @@ -152,11 +154,8 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) return NULL; } -/* - * This is where hid.c calls into hiddev to pass an event that occurred over - * the interrupt pipe - */ -void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref) +static void hiddev_send_event(struct hid_device *hid, + struct hiddev_usage_ref *uref) { struct hiddev *hiddev = hid->hiddev; struct hiddev_list *list = hiddev->list; @@ -177,6 +176,44 @@ void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref) } /* + * This is where hid.c calls into hiddev to pass an event that occurred over + * the interrupt pipe + */ +void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + unsigned type = field->report_type; + struct hiddev_usage_ref uref; + + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = field->report->id; + uref.field_index = field->index; + uref.usage_index = (usage - field->usage); + uref.usage_code = usage->hid; + uref.value = value; + + hiddev_send_event(hid, &uref); +} + + +void hiddev_report_event(struct hid_device *hid, struct hid_report *report) +{ + unsigned type = report->type; + struct hiddev_usage_ref uref; + + memset(&uref, 0, sizeof(uref)); + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = report->id; + + hiddev_send_event(hid, &uref); +} +/* * fasync file op */ static int hiddev_fasync(int fd, struct file *file, int on) @@ -256,8 +293,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 * buffer, size_t count, loff_t *ppos) { return -EINVAL; } @@ -265,8 +301,7 @@ static ssize_t hiddev_write(struct file * file, const char * buffer, /* * "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 * buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); struct hiddev_list *list = file->private_data; @@ -354,17 +389,20 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait) /* * "ioctl" file op */ -static int hiddev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; struct usb_device *dev = hid->dev; + struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; + struct hiddev_field_info finfo; struct hiddev_usage_ref uref; + struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; + int i; if (!hiddev->exist) return -EIO; @@ -376,11 +414,18 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, case HIDIOCAPPLICATION: if (arg < 0 || arg >= hid->maxapplication) return -EINVAL; - return hid->application[arg]; + + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == + HID_COLLECTION_APPLICATION && arg-- == 0) + break; + + if (i == hid->maxcollection) + return -EINVAL; + + return hid->collection[i].usage; case HIDIOCGDEVINFO: - { - struct hiddev_devinfo dinfo; dinfo.bustype = BUS_USB; dinfo.busnum = dev->bus->busnum; dinfo.devnum = dev->devnum; @@ -389,11 +434,12 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, dinfo.product = dev->descriptor.idProduct; dinfo.version = dev->descriptor.bcdDevice; dinfo.num_applications = hid->maxapplication; - return copy_to_user((void *) arg, &dinfo, sizeof(dinfo)); - } + if (copy_to_user((void *) arg, &dinfo, sizeof(dinfo))) + return -EFAULT; case HIDIOCGFLAG: - return put_user(list->flags, (int *) arg); + if (put_user(list->flags, (int *) arg)) + return -EFAULT; case HIDIOCSFLAG: { @@ -438,7 +484,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, } case HIDIOCINITREPORT: - hid_init_reports(hid); return 0; @@ -480,11 +525,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, rinfo.num_fields = report->maxfield; - return copy_to_user((void *) arg, &rinfo, sizeof(rinfo)); + if (copy_to_user((void *) arg, &rinfo, sizeof(rinfo))) + return -EFAULT; case HIDIOCGFIELDINFO: - { - struct hiddev_field_info finfo; if (copy_from_user(&finfo, (void *) arg, sizeof(finfo))) return -EFAULT; rinfo.report_type = finfo.report_type; @@ -512,8 +556,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, finfo.unit_exponent = field->unit_exponent; finfo.unit = field->unit; - return copy_to_user((void *) arg, &finfo, sizeof(finfo)); - } + if (copy_to_user((void *) arg, &finfo, sizeof(finfo))) + return -EFAULT; case HIDIOCGUCODE: if (copy_from_user(&uref, (void *) arg, sizeof(uref))) @@ -533,12 +577,18 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, uref.usage_code = field->usage[uref.usage_index].hid; - return copy_to_user((void *) arg, &uref, sizeof(uref)); + if (copy_to_user((void *) arg, &uref, sizeof(uref))) + return -EFAULT; case HIDIOCGUSAGE: + case HIDIOCSUSAGE: + case HIDIOCGCOLLECTIONINDEX: if (copy_from_user(&uref, (void *) arg, sizeof(uref))) return -EFAULT; + if (cmd != HIDIOCGUSAGE && uref.report_type == HID_REPORT_TYPE_INPUT) + return -EINVAL; + if (uref.report_id == HID_REPORT_ID_UNKNOWN) { field = hiddev_lookup_usage(hid, &uref); if (field == NULL) @@ -557,37 +607,36 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, return -EINVAL; } - uref.value = field->value[uref.usage_index]; - - return copy_to_user((void *) arg, &uref, sizeof(uref)); + switch (cmd) { + case HIDIOCGUSAGE: + uref.value = field->value[uref.usage_index]; + if (copy_to_user((void *) arg, &uref, sizeof(uref))) + return -EFAULT; + return 0; - case HIDIOCSUSAGE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; + case HIDIOCSUSAGE: + field->value[uref.usage_index] = uref.value; + return 0; - if (uref.report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + case HIDIOCGCOLLECTIONINDEX: + return field->usage[uref.usage_index].collection_index; + } - if (uref.report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, &uref); - if (field == NULL) - return -EINVAL; - } else { - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + return 0; - if (uref.field_index >= report->maxfield) - return -EINVAL; + case HIDIOCGCOLLECTIONINFO: + if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) + return -EFAULT; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) - return -EINVAL; - } + if (cinfo.index >= hid->maxcollection) + return -EINVAL; - field->value[uref.usage_index] = uref.value; + cinfo.type = hid->collection[cinfo.index].type; + cinfo.usage = hid->collection[cinfo.index].usage; + cinfo.level = hid->collection[cinfo.index].level; + if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo))) + return -EFAULT; return 0; default: @@ -628,11 +677,13 @@ int hiddev_connect(struct hid_device *hid) int retval; char devfs_name[16]; - for (i = 0; i < hid->maxapplication; i++) - if (!IS_INPUT_APPLICATION(hid->application[i])) + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == + HID_COLLECTION_APPLICATION && + !IS_INPUT_APPLICATION(hid->collection[i].usage)) break; - if (i == hid->maxapplication) + if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0) return -1; retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor); @@ -657,10 +708,8 @@ int hiddev_connect(struct hid_device *hid) sprintf(devfs_name, "hiddev%d", minor); hiddev->devfs = devfs_register(hiddev_devfs_handle, devfs_name, - DEVFS_FL_DEFAULT, USB_MAJOR, - minor + HIDDEV_MINOR_BASE, - S_IFCHR | S_IRUGO | S_IWUSR, - &hiddev_fops, NULL); + DEVFS_FL_DEFAULT, USB_MAJOR, minor + HIDDEV_MINOR_BASE, + S_IFCHR | S_IRUGO | S_IWUSR, &hiddev_fops, NULL); hid->minor = minor; hid->hiddev = hiddev; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 9b22b2acb40c..8c3baaabfb02 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -344,6 +344,12 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb) len = srb->request_bufflen; } + /* According to the linux-scsi people, any command sent which + * violates this invariant is a bug. In the hopes of removing + * all the complex logic above, let's find them and eliminate them. + */ + BUG_ON(len != srb->request_bufflen); + return len; } diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h index eb948560836d..0077b58559f5 100644 --- a/include/linux/hiddev.h +++ b/include/linux/hiddev.h @@ -49,6 +49,13 @@ struct hiddev_devinfo { unsigned num_applications; }; +struct hiddev_collection_info { + unsigned index; + unsigned type; + unsigned usage; + unsigned level; +}; + #define HID_STRING_SIZE 256 struct hiddev_string_descriptor { int index; @@ -64,9 +71,9 @@ struct hiddev_report_info { /* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and * report_id. Set report_id to REPORT_ID_UNKNOWN if the rest of the fields * are unknown. Otherwise use a usage_ref struct filled in from a previous - * successful GUSAGE/SUSAGE call to save time. To actually send a value - * to the device, perform a SUSAGE first, followed by a SREPORT. If an - * INITREPORT is done, a GREPORT isn't necessary before a GUSAGE. + * successful GUSAGE call to save time. To actually send a value to the + * device, perform a SUSAGE first, followed by a SREPORT. An INITREPORT or a + * GREPORT isn't necessary for a GUSAGE to return valid data. */ #define HID_REPORT_ID_UNKNOWN 0xffffffff #define HID_REPORT_ID_FIRST 0x00000100 @@ -129,7 +136,7 @@ struct hiddev_usage_ref { * Protocol version. */ -#define HID_VERSION 0x010003 +#define HID_VERSION 0x010004 /* * IOCTLs (0x00 - 0x7f) @@ -150,6 +157,8 @@ struct hiddev_usage_ref { #define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) #define HIDIOCGFLAG _IOR('H', 0x0E, int) #define HIDIOCSFLAG _IOW('H', 0x0F, int) +#define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref) +#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) /* * Flags to be used in HIDIOCSFLAG @@ -193,13 +202,17 @@ struct hiddev_usage_ref { #ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); -void hiddev_hid_event(struct hid_device *, struct hiddev_usage_ref *ref); +void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value); +void hiddev_report_event(struct hid_device *hid, struct hid_report *report); int __init hiddev_init(void); void __exit hiddev_exit(void); #else -static inline void *hiddev_connect(struct hid_device *hid) { return NULL; } +static inline int hiddev_connect(struct hid_device *hid) { return -1; } static inline void hiddev_disconnect(struct hid_device *hid) { } -static inline void hiddev_event(struct hid_device *hid, unsigned int usage, int value) { } +static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) { } +static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { } static inline int hiddev_init(void) { return 0; } static inline void hiddev_exit(void) { } #endif |
