summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-07-15 04:18:33 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-07-15 04:18:33 -0700
commit7fde4915a17dec953900e02252a013abcd37cdab (patch)
tree979378c5634df2afa0ffe27a5a0791c086bb135c
parent4ba438aa3dbbcf2da7cac26c11420d3d868adb7c (diff)
parent12c2451cfee6e25118fb3c8684ada795638ed9dd (diff)
Merge http://linuxusb.bkbits.net/linus-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--Documentation/usb/hiddev.txt15
-rw-r--r--drivers/usb/host/ohci-dbg.c29
-rw-r--r--drivers/usb/host/ohci-hcd.c10
-rw-r--r--drivers/usb/host/ohci-q.c68
-rw-r--r--drivers/usb/host/ohci-sa1111.c2
-rw-r--r--drivers/usb/host/ohci.h17
-rw-r--r--drivers/usb/input/hid-core.c168
-rw-r--r--drivers/usb/input/hid-debug.h6
-rw-r--r--drivers/usb/input/hid-input.c7
-rw-r--r--drivers/usb/input/hid.h12
-rw-r--r--drivers/usb/input/hiddev.c199
-rw-r--r--drivers/usb/storage/transport.c6
-rw-r--r--include/linux/hiddev.h27
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