Commit 7fde4915 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linuxusb.bkbits.net/linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 4ba438aa 12c2451c
...@@ -18,7 +18,7 @@ normalised event interface - see Documentation/input/input.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 data flow for a HID event produced by a device is something like
the following : 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 --> hiddev.c ----> POWER / MONITOR CONTROL
...@@ -106,6 +106,15 @@ returns -1. You can find out beforehand how many application ...@@ -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 collections the device has from the num_applications field from the
hiddev_devinfo structure. 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) HIDIOCGDEVINFO - struct hiddev_devinfo (read)
Gets a hiddev_devinfo structure which describes the device. 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 ...@@ -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 hiddev_usage_ref structure as above, but additionally fills in
the value field. 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) HIDIOCGFLAG - int (read)
HIDIOCSFLAG - int (write) HIDIOCSFLAG - int (write)
These operations respectively inspect and replace the mode flags These operations respectively inspect and replace the mode flags
......
...@@ -12,13 +12,14 @@ ...@@ -12,13 +12,14 @@
#ifdef DEBUG #ifdef DEBUG
#define pipestring(pipe) ({ char *temp; \ #define edstring(ed_type) ({ char *temp; \
switch (usb_pipetype (pipe)) { \ switch (ed_type) { \
case PIPE_CONTROL: temp = "CTRL"; break; \ case PIPE_CONTROL: temp = "CTRL"; break; \
case PIPE_BULK: temp = "BULK"; break; \ case PIPE_BULK: temp = "BULK"; break; \
case PIPE_INTERRUPT: temp = "INTR"; break; \ case PIPE_INTERRUPT: temp = "INTR"; break; \
default: temp = "ISOC"; break; \ default: temp = "ISOC"; break; \
}; temp;}) }; temp;})
#define pipestring(pipe) edstring(usb_pipetype(pipe))
/* debug| print the main components of an URB /* debug| print the main components of an URB
* small: 0) header + data packets 1) just header * small: 0) header + data packets 1) just header
...@@ -35,9 +36,9 @@ static void urb_print (struct urb * urb, char * str, int small) ...@@ -35,9 +36,9 @@ static void urb_print (struct urb * urb, char * str, int small)
#ifndef OHCI_VERBOSE_DEBUG #ifndef OHCI_VERBOSE_DEBUG
if (urb->status != 0) if (urb->status != 0)
#endif #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, str,
usb_get_current_frame_number (urb->dev), urb,
usb_pipedevice (pipe), usb_pipedevice (pipe),
usb_pipeendpoint (pipe), usb_pipeendpoint (pipe),
usb_pipeout (pipe)? 'O': 'I', usb_pipeout (pipe)? 'O': 'I',
...@@ -242,21 +243,25 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose) ...@@ -242,21 +243,25 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
ohci_dump_roothub (controller, 1); 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) static void ohci_dump_td (char *label, struct td *td)
{ {
u32 tmp = le32_to_cpup (&td->hwINFO); 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, label, td,
(tmp & TD_DONE) ? " (DONE)" : "",
td->urb, td->index, td->urb, td->index,
le32_to_cpup (&td->hwNextTD)); le32_to_cpup (&td->hwNextTD));
if ((tmp & TD_ISO) == 0) { if ((tmp & TD_ISO) == 0) {
char *toggle, *pid; const char *toggle, *pid;
u32 cbp, be; u32 cbp, be;
switch (tmp & TD_T) { switch (tmp & TD_T) {
case TD_T_DATA0: toggle = "DATA0"; break; case TD_T_DATA0: toggle = data0; break;
case TD_T_DATA1: toggle = "DATA1"; break; case TD_T_DATA1: toggle = data1; break;
case TD_T_TOGGLE: toggle = "(CARRY)"; break; case TD_T_TOGGLE: toggle = "(CARRY)"; break;
default: toggle = "(?)"; break; default: toggle = "(?)"; break;
} }
...@@ -297,9 +302,9 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose) ...@@ -297,9 +302,9 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
u32 tmp = ed->hwINFO; u32 tmp = ed->hwINFO;
char *type = ""; 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, ohci->hcd.self.bus_name, label,
ed, ed->state, ed->type, ed, ed->state, edstring (ed->type),
le32_to_cpup (&ed->hwNextED)); le32_to_cpup (&ed->hwNextED));
switch (tmp & (ED_IN|ED_OUT)) { switch (tmp & (ED_IN|ED_OUT)) {
case ED_OUT: type = "-OUT"; break; case ED_OUT: type = "-OUT"; break;
...@@ -314,10 +319,10 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose) ...@@ -314,10 +319,10 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
0x000f & (le32_to_cpu (tmp) >> 7), 0x000f & (le32_to_cpu (tmp) >> 7),
type, type,
0x007f & le32_to_cpu (tmp)); 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), tmp = le32_to_cpup (&ed->hwHeadP),
(ed->hwHeadP & ED_C) ? data1 : data0,
(ed->hwHeadP & ED_H) ? " HALT" : "", (ed->hwHeadP & ED_H) ? " HALT" : "",
(ed->hwHeadP & ED_C) ? " CARRY" : "",
le32_to_cpup (&ed->hwTailP), le32_to_cpup (&ed->hwTailP),
verbose ? "" : " (not listing)"); verbose ? "" : " (not listing)");
if (verbose) { if (verbose) {
......
...@@ -197,7 +197,7 @@ static int ohci_urb_enqueue ( ...@@ -197,7 +197,7 @@ static int ohci_urb_enqueue (
/* allocate the TDs (updating hash chains) */ /* allocate the TDs (updating hash chains) */
spin_lock_irqsave (&ohci->lock, flags); 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); urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC);
if (!urb_priv->td [i]) { if (!urb_priv->td [i]) {
urb_priv->length = i; urb_priv->length = i;
...@@ -208,6 +208,8 @@ static int ohci_urb_enqueue ( ...@@ -208,6 +208,8 @@ static int ohci_urb_enqueue (
} }
// FIXME: much of this switch should be generic, move to hcd code ... // 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 /* allocate and claim bandwidth if needed; ISO
* needs start frame index if it was't provided. * needs start frame index if it was't provided.
...@@ -247,14 +249,14 @@ static int ohci_urb_enqueue ( ...@@ -247,14 +249,14 @@ static int ohci_urb_enqueue (
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
return 0; return 0;
} }
/* /*
* decouple the URB from the HC queues (TDs, urb_priv); it's * 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 * 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) static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{ {
......
...@@ -465,6 +465,25 @@ static struct ed *ed_get ( ...@@ -465,6 +465,25 @@ static struct ed *ed_get (
* we know it's already a power of 2 * we know it's already a power of 2
*/ */
ed->interval = interval; 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: done:
...@@ -539,12 +558,15 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, ...@@ -539,12 +558,15 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
/* aim for only one interrupt per urb. mostly applies to control /* aim for only one interrupt per urb. mostly applies to control
* and iso; other urbs rarely need more than one TD per urb. * 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 * NOTE: could delay interrupts even for the last TD, and get fewer
* interrupts ... increasing per-urb latency by sharing interrupts. * interrupts ... increasing per-urb latency by sharing interrupts.
* Drivers that queue bulk urbs may request that behavior.
*/ */
if (index != (urb_priv->length - 1)) if (index != (urb_priv->length - 1)
info |= is_iso ? TD_DI_SET (7) : TD_DI_SET (1); || (urb->transfer_flags & URB_NO_INTERRUPT))
info |= TD_DI_SET (7);
/* use this td as the next dummy */ /* use this td as the next dummy */
td_pt = urb_priv->td [index]; td_pt = urb_priv->td [index];
...@@ -565,6 +587,7 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, ...@@ -565,6 +587,7 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
td->hwINFO = cpu_to_le32 (info); td->hwINFO = cpu_to_le32 (info);
if (is_iso) { if (is_iso) {
td->hwCBP = cpu_to_le32 (data & 0xFFFFF000); td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
td->ed->intriso.last_iso = info & 0xffff; td->ed->intriso.last_iso = info & 0xffff;
} else { } else {
td->hwCBP = cpu_to_le32 (data); td->hwCBP = cpu_to_le32 (data);
...@@ -574,7 +597,6 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, ...@@ -574,7 +597,6 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
else else
td->hwBE = 0; td->hwBE = 0;
td->hwNextTD = cpu_to_le32 (td_pt->td_dma); 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 ... */ /* HC might read the TD right after we link it ... */
wmb (); wmb ();
...@@ -596,17 +618,17 @@ static void td_submit_urb (struct urb *urb) ...@@ -596,17 +618,17 @@ static void td_submit_urb (struct urb *urb)
int cnt = 0; int cnt = 0;
__u32 info = 0; __u32 info = 0;
unsigned int toggle = 0; unsigned int toggle = 0;
int is_out = usb_pipeout (urb->pipe);
/* OHCI handles the DATA-toggles itself, we just use the /* OHCI handles the DATA-toggles itself, we just use the
* USB-toggle bits for resetting * USB-toggle bits for resetting
*/ */
if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
usb_pipeout (urb->pipe))) {
toggle = TD_T_TOGGLE; toggle = TD_T_TOGGLE;
} else { } else {
toggle = TD_T_DATA0; toggle = TD_T_DATA0;
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
usb_pipeout (urb->pipe), 1); is_out, 1);
} }
urb_priv->td_cnt = 0; urb_priv->td_cnt = 0;
...@@ -614,9 +636,9 @@ static void td_submit_urb (struct urb *urb) ...@@ -614,9 +636,9 @@ static void td_submit_urb (struct urb *urb)
if (data_len) { if (data_len) {
data = pci_map_single (ohci->hcd.pdev, data = pci_map_single (ohci->hcd.pdev,
urb->transfer_buffer, data_len, urb->transfer_buffer, data_len,
usb_pipeout (urb->pipe) is_out
? PCI_DMA_TODEVICE ? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE); : PCI_DMA_FROMDEVICE);
} else } else
data = 0; data = 0;
...@@ -625,18 +647,20 @@ static void td_submit_urb (struct urb *urb) ...@@ -625,18 +647,20 @@ static void td_submit_urb (struct urb *urb)
*/ */
switch (usb_pipetype (urb->pipe)) { switch (usb_pipetype (urb->pipe)) {
case PIPE_BULK: case PIPE_BULK:
info = usb_pipeout (urb->pipe) info = is_out
? TD_CC | TD_DP_OUT ? TD_CC | TD_DP_OUT
: TD_CC | TD_DP_IN ; : TD_CC | TD_DP_IN ;
/* TDs _could_ transfer up to 8K each */
while (data_len > 4096) { while (data_len > 4096) {
td_fill (ohci, td_fill (ohci,
info | (cnt? TD_T_TOGGLE:toggle), info | (cnt? TD_T_TOGGLE:toggle),
data, 4096, urb, cnt); data, 4096, urb, cnt);
data += 4096; data_len -= 4096; cnt++; data += 4096; data_len -= 4096; cnt++;
} }
info = usb_pipeout (urb->pipe)? /* maybe avoid ED halt on final TD short read */
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), info |= TD_R;
td_fill (ohci, info | (cnt ? TD_T_TOGGLE : toggle),
data, data_len, urb, cnt); data, data_len, urb, cnt);
cnt++; cnt++;
if ((urb->transfer_flags & USB_ZERO_PACKET) if ((urb->transfer_flags & USB_ZERO_PACKET)
...@@ -653,8 +677,11 @@ static void td_submit_urb (struct urb *urb) ...@@ -653,8 +677,11 @@ static void td_submit_urb (struct urb *urb)
break; break;
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
/* current policy: only one TD per request.
* otherwise identical to bulk, except for BLF
*/
info = TD_CC | toggle; info = TD_CC | toggle;
info |= usb_pipeout (urb->pipe) info |= is_out
? TD_DP_OUT ? TD_DP_OUT
: TD_R | TD_DP_IN; : TD_R | TD_DP_IN;
td_fill (ohci, info, data, data_len, urb, cnt++); td_fill (ohci, info, data, data_len, urb, cnt++);
...@@ -670,14 +697,12 @@ static void td_submit_urb (struct urb *urb) ...@@ -670,14 +697,12 @@ static void td_submit_urb (struct urb *urb)
8, urb, cnt++); 8, urb, cnt++);
if (data_len > 0) { if (data_len > 0) {
info = TD_CC | TD_R | TD_T_DATA1; info = TD_CC | TD_R | TD_T_DATA1;
info |= usb_pipeout (urb->pipe) info |= is_out ? TD_DP_OUT : TD_DP_IN;
? TD_DP_OUT
: TD_DP_IN;
/* NOTE: mishandles transfers >8K, some >4K */ /* NOTE: mishandles transfers >8K, some >4K */
td_fill (ohci, info, data, data_len, td_fill (ohci, info, data, data_len,
urb, cnt++); urb, cnt++);
} }
info = usb_pipeout (urb->pipe) info = is_out
? TD_CC | TD_DP_IN | TD_T_DATA1 ? TD_CC | TD_DP_IN | TD_T_DATA1
: TD_CC | TD_DP_OUT | TD_T_DATA1; : TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (ohci, info, data, 0, urb, cnt++); td_fill (ohci, info, data, 0, urb, cnt++);
...@@ -806,10 +831,13 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -806,10 +831,13 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
while (td_list_hc) { while (td_list_hc) {
td_list = dma_to_td (ohci, 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))) { if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
urb_priv = (urb_priv_t *) td_list->urb->hcpriv; urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
/* typically the endpoint halts on error; un-halt, /* Non-iso endpoints can halt on error; un-halt,
* and maybe dequeue other TDs from this urb * and dequeue any other TDs from this urb.
* No other TD could have caused the halt.
*/ */
if (td_list->ed->hwHeadP & ED_H) { if (td_list->ed->hwHeadP & ED_H) {
if (urb_priv && ((td_list->index + 1) if (urb_priv && ((td_list->index + 1)
......
...@@ -175,7 +175,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o ...@@ -175,7 +175,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
usb_bus_init (&hcd->self); usb_bus_init (&hcd->self);
hcd->self.op = &usb_hcd_operations; hcd->self.op = &usb_hcd_operations;
hcd->self.hcpriv = (void *) hcd; hcd->self.hcpriv = (void *) hcd;
hcd->self.bus_name = "SA-1111"; hcd->self.bus_name = "sa1111";
hcd->product_desc = "SA-1111 OHCI"; hcd->product_desc = "SA-1111 OHCI";
INIT_LIST_HEAD (&hcd->dev_list); INIT_LIST_HEAD (&hcd->dev_list);
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
/* /*
* OHCI Endpoint Descriptor (ED) ... holds TD queue * OHCI Endpoint Descriptor (ED) ... holds TD queue
* See OHCI spec, section 4.2 * 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 { struct ed {
/* first fields are hardware-specified, le32 */ /* first fields are hardware-specified, le32 */
...@@ -74,8 +77,8 @@ struct td { ...@@ -74,8 +77,8 @@ struct td {
/* these two bits are available for definition/use by HCDs in both /* these two bits are available for definition/use by HCDs in both
* general and iso tds ... others are available for only one type * general and iso tds ... others are available for only one type
*/ */
//#define TD____ 0x00020000 #define TD_DONE 0x00020000 /* retired to donelist */
#define TD_ISO 0x00010000 /* copy of ED_ISO */ #define TD_ISO 0x00010000 /* copy of ED_ISO */
/* hwINFO bits for general tds: */ /* hwINFO bits for general tds: */
#define TD_EC 0x0C000000 /* error count */ #define TD_EC 0x0C000000 /* error count */
...@@ -349,12 +352,14 @@ struct ohci_hcd { ...@@ -349,12 +352,14 @@ struct ohci_hcd {
struct device *parent_dev; 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; 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; struct ohci_hcca *hcca;
dma_addr_t hcca_dma; dma_addr_t hcca_dma;
...@@ -365,6 +370,9 @@ struct ohci_hcd { ...@@ -365,6 +370,9 @@ struct ohci_hcd {
struct ed *ed_controltail; /* last in ctrl list */ struct ed *ed_controltail; /* last in ctrl list */
struct ed *ed_isotail; /* last in iso list */ struct ed *ed_isotail; /* last in iso list */
/*
* memory management for queue data structures
*/
struct pci_pool *td_cache; struct pci_pool *td_cache;
struct pci_pool *ed_cache; struct pci_pool *ed_cache;
struct hash_list_t td_hash [TD_HASH_SIZE]; struct hash_list_t td_hash [TD_HASH_SIZE];
...@@ -380,6 +388,7 @@ struct ohci_hcd { ...@@ -380,6 +388,7 @@ struct ohci_hcd {
unsigned long flags; /* for HC bugs */ unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
// there are also chip quirks/bugs in init logic
/* /*
* framework state * framework state
......
This diff is collapsed.
...@@ -352,12 +352,6 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { ...@@ -352,12 +352,6 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
unsigned i,k; unsigned i,k;
static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; 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++) { for (i = 0; i < HID_REPORT_TYPES; i++) {
report_enum = device->report_enum + i; report_enum = device->report_enum + i;
list = report_enum->report_list.next; list = report_enum->report_list.next;
......
...@@ -474,11 +474,12 @@ int hidinput_connect(struct hid_device *hid) ...@@ -474,11 +474,12 @@ int hidinput_connect(struct hid_device *hid)
struct list_head *list; struct list_head *list;
int i, j, k; int i, j, k;
for (i = 0; i < hid->maxapplication; i++) for (i = 0; i < hid->maxcollection; i++)
if (IS_INPUT_APPLICATION(hid->application[i])) if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
IS_INPUT_APPLICATION(hid->collection[i].usage))
break; break;
if (i == hid->maxapplication) if (i == hid->maxcollection)
return -1; return -1;
hid->input.private = hid; hid->input.private = hid;
......
...@@ -205,6 +205,7 @@ struct hid_item { ...@@ -205,6 +205,7 @@ struct hid_item {
#define HID_QUIRK_NOTOUCH 0x02 #define HID_QUIRK_NOTOUCH 0x02
#define HID_QUIRK_IGNORE 0x04 #define HID_QUIRK_IGNORE 0x04
#define HID_QUIRK_NOGET 0x08 #define HID_QUIRK_NOGET 0x08
#define HID_QUIRK_HIDDEV 0x10
/* /*
* This is the global enviroment of the parser. This information is * This is the global enviroment of the parser. This information is
...@@ -231,10 +232,11 @@ struct hid_global { ...@@ -231,10 +232,11 @@ struct hid_global {
#define HID_MAX_DESCRIPTOR_SIZE 4096 #define HID_MAX_DESCRIPTOR_SIZE 4096
#define HID_MAX_USAGES 1024 #define HID_MAX_USAGES 1024
#define HID_MAX_APPLICATIONS 16 #define HID_DEFAULT_NUM_COLLECTIONS 16
struct hid_local { struct hid_local {
unsigned usage[HID_MAX_USAGES]; /* usage array */ unsigned usage[HID_MAX_USAGES]; /* usage array */
unsigned collection_index[HID_MAX_USAGES]; /* collection index array */
unsigned usage_index; unsigned usage_index;
unsigned usage_minimum; unsigned usage_minimum;
unsigned delimiter_depth; unsigned delimiter_depth;
...@@ -249,10 +251,12 @@ struct hid_local { ...@@ -249,10 +251,12 @@ struct hid_local {
struct hid_collection { struct hid_collection {
unsigned type; unsigned type;
unsigned usage; unsigned usage;
unsigned level;
}; };
struct hid_usage { struct hid_usage {
unsigned hid; /* hid usage code */ unsigned hid; /* hid usage code */
unsigned collection_index; /* index into collection array */
__u16 code; /* input driver code */ __u16 code; /* input driver code */
__u8 type; /* input driver type */ __u8 type; /* input driver type */
__s8 hat_min; /* hat switch fun */ __s8 hat_min; /* hat switch fun */
...@@ -319,7 +323,9 @@ struct hid_control_fifo { ...@@ -319,7 +323,9 @@ struct hid_control_fifo {
struct hid_device { /* device report descriptor */ struct hid_device { /* device report descriptor */
__u8 *rdesc; __u8 *rdesc;
unsigned rsize; 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 maxapplication; /* Number of applications */
unsigned version; /* HID version */ unsigned version; /* HID version */
unsigned country; /* HID country */ unsigned country; /* HID country */
...@@ -374,7 +380,7 @@ struct hid_parser { ...@@ -374,7 +380,7 @@ struct hid_parser {
struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; struct hid_global global_stack[HID_GLOBAL_STACK_SIZE];
unsigned global_stack_ptr; unsigned global_stack_ptr;
struct hid_local local; struct hid_local local;
struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE]; unsigned collection_stack[HID_COLLECTION_STACK_SIZE];
unsigned collection_stack_ptr; unsigned collection_stack_ptr;
struct hid_device *device; struct hid_device *device;
}; };
......
This diff is collapsed.
...@@ -344,6 +344,12 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb) ...@@ -344,6 +344,12 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
len = srb->request_bufflen; 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; return len;
} }
......
...@@ -49,6 +49,13 @@ struct hiddev_devinfo { ...@@ -49,6 +49,13 @@ struct hiddev_devinfo {
unsigned num_applications; unsigned num_applications;
}; };
struct hiddev_collection_info {
unsigned index;
unsigned type;
unsigned usage;
unsigned level;
};
#define HID_STRING_SIZE 256 #define HID_STRING_SIZE 256
struct hiddev_string_descriptor { struct hiddev_string_descriptor {
int index; int index;
...@@ -64,9 +71,9 @@ struct hiddev_report_info { ...@@ -64,9 +71,9 @@ struct hiddev_report_info {
/* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and /* 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 * 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 * 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 * successful GUSAGE call to save time. To actually send a value to the
* to the device, perform a SUSAGE first, followed by a SREPORT. If an * device, perform a SUSAGE first, followed by a SREPORT. An INITREPORT or a
* INITREPORT is done, a GREPORT isn't necessary before a GUSAGE. * GREPORT isn't necessary for a GUSAGE to return valid data.
*/ */
#define HID_REPORT_ID_UNKNOWN 0xffffffff #define HID_REPORT_ID_UNKNOWN 0xffffffff
#define HID_REPORT_ID_FIRST 0x00000100 #define HID_REPORT_ID_FIRST 0x00000100
...@@ -129,7 +136,7 @@ struct hiddev_usage_ref { ...@@ -129,7 +136,7 @@ struct hiddev_usage_ref {
* Protocol version. * Protocol version.
*/ */
#define HID_VERSION 0x010003 #define HID_VERSION 0x010004
/* /*
* IOCTLs (0x00 - 0x7f) * IOCTLs (0x00 - 0x7f)
...@@ -150,6 +157,8 @@ struct hiddev_usage_ref { ...@@ -150,6 +157,8 @@ struct hiddev_usage_ref {
#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) #define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref)
#define HIDIOCGFLAG _IOR('H', 0x0E, int) #define HIDIOCGFLAG _IOR('H', 0x0E, int)
#define HIDIOCSFLAG _IOW('H', 0x0F, 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 * Flags to be used in HIDIOCSFLAG
...@@ -193,13 +202,17 @@ struct hiddev_usage_ref { ...@@ -193,13 +202,17 @@ struct hiddev_usage_ref {
#ifdef CONFIG_USB_HIDDEV #ifdef CONFIG_USB_HIDDEV
int hiddev_connect(struct hid_device *); int hiddev_connect(struct hid_device *);
void hiddev_disconnect(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); int __init hiddev_init(void);
void __exit hiddev_exit(void); void __exit hiddev_exit(void);
#else #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_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 int hiddev_init(void) { return 0; }
static inline void hiddev_exit(void) { } static inline void hiddev_exit(void) { }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment