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
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
......
......@@ -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) {
......
......@@ -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.
......@@ -252,9 +254,9 @@ static int ohci_urb_enqueue (
/*
* 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)
{
......
......@@ -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,7 +636,7 @@ 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)
is_out
? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE);
} else
......@@ -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)
......
......@@ -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);
......
......@@ -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,7 +77,7 @@ 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_DONE 0x00020000 /* retired to donelist */
#define TD_ISO 0x00010000 /* copy of ED_ISO */
/* hwINFO bits for general tds: */
......@@ -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
......
......@@ -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 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
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 },
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
};
......
......@@ -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,8 +89,11 @@ 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) {
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;
......@@ -98,8 +102,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
case HID_REPORT_ID_NEXT:
list = (struct list_head *)
report_enum->report_id_hash[rinfo->report_id &
HID_REPORT_ID_MASK];
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;
......@@ -109,7 +112,6 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
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;
......@@ -176,6 +175,44 @@ void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref)
wake_up_interruptible(&hiddev->wait);
}
/*
* 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
*/
......@@ -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;
}
switch (cmd) {
case HIDIOCGUSAGE:
uref.value = field->value[uref.usage_index];
return copy_to_user((void *) arg, &uref, sizeof(uref));
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;
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)
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;
......
......@@ -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;
}
......
......@@ -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
......
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