[PATCH] Generic HID layer - code split
authorJiri Kosina <jkosina@suse.cz>
Fri, 8 Dec 2006 17:40:44 +0000 (18:40 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 8 Dec 2006 18:43:01 +0000 (10:43 -0800)
The "big main" split of USB HID code into generic HID code and
USB-transport specific HID handling.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
14 files changed:
drivers/hid/hid-core.c [new file with mode: 0644]
drivers/hid/hid-input.c [new file with mode: 0644]
drivers/usb/input/hid-core.c
drivers/usb/input/hid-debug.h [deleted file]
drivers/usb/input/hid-ff.c
drivers/usb/input/hid-input.c
drivers/usb/input/hid-lgff.c
drivers/usb/input/hid-pidff.c
drivers/usb/input/hid-tmff.c
drivers/usb/input/hid-zpff.c
drivers/usb/input/hid.h [deleted file]
drivers/usb/input/hiddev.c
include/linux/hid-debug.h [new file with mode: 0644]
include/linux/hid.h [new file with mode: 0644]

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
new file mode 100644 (file)
index 0000000..689ae16
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ *  USB HID support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/input.h>
+#include <linux/wait.h>
+
+#undef DEBUG
+#undef DEBUG_DATA
+
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+
+/*
+ * Version Information
+ */
+
+#define DRIVER_VERSION "v2.6"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_DESC "USB HID core driver"
+#define DRIVER_LICENSE "GPL"
+
+/*
+ * Module parameters.
+ */
+
+static unsigned int hid_mousepoll_interval;
+module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+
+/*
+ * Register a new report for a device.
+ */
+
+static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+{
+       struct hid_report_enum *report_enum = device->report_enum + type;
+       struct hid_report *report;
+
+       if (report_enum->report_id_hash[id])
+               return report_enum->report_id_hash[id];
+
+       if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+               return NULL;
+
+       if (id != 0)
+               report_enum->numbered = 1;
+
+       report->id = id;
+       report->type = type;
+       report->size = 0;
+       report->device = device;
+       report_enum->report_id_hash[id] = report;
+
+       list_add_tail(&report->list, &report_enum->report_list);
+
+       return report;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
+{
+       struct hid_field *field;
+
+       if (report->maxfield == HID_MAX_FIELDS) {
+               dbg("too many fields in report");
+               return NULL;
+       }
+
+       if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+               + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+
+       field->index = report->maxfield++;
+       report->field[field->index] = field;
+       field->usage = (struct hid_usage *)(field + 1);
+       field->value = (unsigned *)(field->usage + usages);
+       field->report = report;
+
+       return field;
+}
+
+/*
+ * Open a collection. The type/usage is pushed on the stack.
+ */
+
+static int open_collection(struct hid_parser *parser, unsigned type)
+{
+       struct hid_collection *collection;
+       unsigned usage;
+
+       usage = parser->local.usage[0];
+
+       if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
+               dbg("collection stack overflow");
+               return -1;
+       }
+
+       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;
+}
+
+/*
+ * Close a collection.
+ */
+
+static int close_collection(struct hid_parser *parser)
+{
+       if (!parser->collection_stack_ptr) {
+               dbg("collection stack underflow");
+               return -1;
+       }
+       parser->collection_stack_ptr--;
+       return 0;
+}
+
+/*
+ * Climb up the stack, search for the specified collection type
+ * and return the usage.
+ */
+
+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->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 */
+}
+
+/*
+ * Add a usage to the temporary parser table.
+ */
+
+static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+{
+       if (parser->local.usage_index >= HID_MAX_USAGES) {
+               dbg("usage index exceeded");
+               return -1;
+       }
+       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;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
+{
+       struct hid_report *report;
+       struct hid_field *field;
+       int usages;
+       unsigned offset;
+       int i;
+
+       if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+               dbg("hid_register_report failed");
+               return -1;
+       }
+
+       if (parser->global.logical_maximum < parser->global.logical_minimum) {
+               dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+               return -1;
+       }
+
+       offset = report->size;
+       report->size += parser->global.report_size * parser->global.report_count;
+
+       if (!parser->local.usage_index) /* Ignore padding fields */
+               return 0;
+
+       usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+
+       if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+               return 0;
+
+       field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
+       field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
+       field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
+
+       for (i = 0; i < usages; i++) {
+               int j = i;
+               /* Duplicate the last usage we parsed if we have excess values */
+               if (i >= parser->local.usage_index)
+                       j = parser->local.usage_index - 1;
+               field->usage[i].hid = parser->local.usage[j];
+               field->usage[i].collection_index =
+                       parser->local.collection_index[j];
+       }
+
+       field->maxusage = usages;
+       field->flags = flags;
+       field->report_offset = offset;
+       field->report_type = report_type;
+       field->report_size = parser->global.report_size;
+       field->report_count = parser->global.report_count;
+       field->logical_minimum = parser->global.logical_minimum;
+       field->logical_maximum = parser->global.logical_maximum;
+       field->physical_minimum = parser->global.physical_minimum;
+       field->physical_maximum = parser->global.physical_maximum;
+       field->unit_exponent = parser->global.unit_exponent;
+       field->unit = parser->global.unit;
+
+       return 0;
+}
+
+/*
+ * Read data value from item.
+ */
+
+static u32 item_udata(struct hid_item *item)
+{
+       switch (item->size) {
+               case 1: return item->data.u8;
+               case 2: return item->data.u16;
+               case 4: return item->data.u32;
+       }
+       return 0;
+}
+
+static s32 item_sdata(struct hid_item *item)
+{
+       switch (item->size) {
+               case 1: return item->data.s8;
+               case 2: return item->data.s16;
+               case 4: return item->data.s32;
+       }
+       return 0;
+}
+
+/*
+ * Process a global item.
+ */
+
+static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
+{
+       switch (item->tag) {
+
+               case HID_GLOBAL_ITEM_TAG_PUSH:
+
+                       if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+                               dbg("global enviroment stack overflow");
+                               return -1;
+                       }
+
+                       memcpy(parser->global_stack + parser->global_stack_ptr++,
+                               &parser->global, sizeof(struct hid_global));
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_POP:
+
+                       if (!parser->global_stack_ptr) {
+                               dbg("global enviroment stack underflow");
+                               return -1;
+                       }
+
+                       memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
+                               sizeof(struct hid_global));
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+                       parser->global.usage_page = item_udata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+                       parser->global.logical_minimum = item_sdata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+                       if (parser->global.logical_minimum < 0)
+                               parser->global.logical_maximum = item_sdata(item);
+                       else
+                               parser->global.logical_maximum = item_udata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+                       parser->global.physical_minimum = item_sdata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+                       if (parser->global.physical_minimum < 0)
+                               parser->global.physical_maximum = item_sdata(item);
+                       else
+                               parser->global.physical_maximum = item_udata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+                       parser->global.unit_exponent = item_sdata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_UNIT:
+                       parser->global.unit = item_udata(item);
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+                       if ((parser->global.report_size = item_udata(item)) > 32) {
+                               dbg("invalid report_size %d", parser->global.report_size);
+                               return -1;
+                       }
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+                       if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
+                               dbg("invalid report_count %d", parser->global.report_count);
+                               return -1;
+                       }
+                       return 0;
+
+               case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+                       if ((parser->global.report_id = item_udata(item)) == 0) {
+                               dbg("report_id 0 is invalid");
+                               return -1;
+                       }
+                       return 0;
+
+               default:
+                       dbg("unknown global tag 0x%x", item->tag);
+                       return -1;
+       }
+}
+
+/*
+ * Process a local item.
+ */
+
+static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
+{
+       __u32 data;
+       unsigned n;
+
+       if (item->size == 0) {
+               dbg("item data expected for local item");
+               return -1;
+       }
+
+       data = item_udata(item);
+
+       switch (item->tag) {
+
+               case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+                       if (data) {
+                               /*
+                                * We treat items before the first delimiter
+                                * as global to all usage sets (branch 0).
+                                * In the moment we process only these global
+                                * items and the first delimiter set.
+                                */
+                               if (parser->local.delimiter_depth != 0) {
+                                       dbg("nested delimiters");
+                                       return -1;
+                               }
+                               parser->local.delimiter_depth++;
+                               parser->local.delimiter_branch++;
+                       } else {
+                               if (parser->local.delimiter_depth < 1) {
+                                       dbg("bogus close delimiter");
+                                       return -1;
+                               }
+                               parser->local.delimiter_depth--;
+                       }
+                       return 1;
+
+               case HID_LOCAL_ITEM_TAG_USAGE:
+
+                       if (parser->local.delimiter_branch > 1) {
+                               dbg("alternative usage ignored");
+                               return 0;
+                       }
+
+                       if (item->size <= 2)
+                               data = (parser->global.usage_page << 16) + data;
+
+                       return hid_add_usage(parser, data);
+
+               case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+
+                       if (parser->local.delimiter_branch > 1) {
+                               dbg("alternative usage ignored");
+                               return 0;
+                       }
+
+                       if (item->size <= 2)
+                               data = (parser->global.usage_page << 16) + data;
+
+                       parser->local.usage_minimum = data;
+                       return 0;
+
+               case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+
+                       if (parser->local.delimiter_branch > 1) {
+                               dbg("alternative usage ignored");
+                               return 0;
+                       }
+
+                       if (item->size <= 2)
+                               data = (parser->global.usage_page << 16) + data;
+
+                       for (n = parser->local.usage_minimum; n <= data; n++)
+                               if (hid_add_usage(parser, n)) {
+                                       dbg("hid_add_usage failed\n");
+                                       return -1;
+                               }
+                       return 0;
+
+               default:
+
+                       dbg("unknown local item tag 0x%x", item->tag);
+                       return 0;
+       }
+       return 0;
+}
+
+/*
+ * Process a main item.
+ */
+
+static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
+{
+       __u32 data;
+       int ret;
+
+       data = item_udata(item);
+
+       switch (item->tag) {
+               case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+                       ret = open_collection(parser, data & 0xff);
+                       break;
+               case HID_MAIN_ITEM_TAG_END_COLLECTION:
+                       ret = close_collection(parser);
+                       break;
+               case HID_MAIN_ITEM_TAG_INPUT:
+                       ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+                       break;
+               case HID_MAIN_ITEM_TAG_OUTPUT:
+                       ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+                       break;
+               case HID_MAIN_ITEM_TAG_FEATURE:
+                       ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+                       break;
+               default:
+                       dbg("unknown main item tag 0x%x", item->tag);
+                       ret = 0;
+       }
+
+       memset(&parser->local, 0, sizeof(parser->local));       /* Reset the local parser environment */
+
+       return ret;
+}
+
+/*
+ * Process a reserved item.
+ */
+
+static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
+{
+       dbg("reserved item type, tag 0x%x", item->tag);
+       return 0;
+}
+
+/*
+ * Free a report and all registered fields. The field->usage and
+ * field->value table's are allocated behind the field, so we need
+ * only to free(field) itself.
+ */
+
+static void hid_free_report(struct hid_report *report)
+{
+       unsigned n;
+
+       for (n = 0; n < report->maxfield; n++)
+               kfree(report->field[n]);
+       kfree(report);
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_free_device(struct hid_device *device)
+{
+       unsigned i,j;
+
+       for (i = 0; i < HID_REPORT_TYPES; i++) {
+               struct hid_report_enum *report_enum = device->report_enum + i;
+
+               for (j = 0; j < 256; j++) {
+                       struct hid_report *report = report_enum->report_id_hash[j];
+                       if (report)
+                               hid_free_report(report);
+               }
+       }
+
+       kfree(device->rdesc);
+       kfree(device);
+}
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
+{
+       u8 b;
+
+       if ((end - start) <= 0)
+               return NULL;
+
+       b = *start++;
+
+       item->type = (b >> 2) & 3;
+       item->tag  = (b >> 4) & 15;
+
+       if (item->tag == HID_ITEM_TAG_LONG) {
+
+               item->format = HID_ITEM_FORMAT_LONG;
+
+               if ((end - start) < 2)
+                       return NULL;
+
+               item->size = *start++;
+               item->tag  = *start++;
+
+               if ((end - start) < item->size)
+                       return NULL;
+
+               item->data.longdata = start;
+               start += item->size;
+               return start;
+       }
+
+       item->format = HID_ITEM_FORMAT_SHORT;
+       item->size = b & 3;
+
+       switch (item->size) {
+
+               case 0:
+                       return start;
+
+               case 1:
+                       if ((end - start) < 1)
+                               return NULL;
+                       item->data.u8 = *start++;
+                       return start;
+
+               case 2:
+                       if ((end - start) < 2)
+                               return NULL;
+                       item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
+                       start = (__u8 *)((__le16 *)start + 1);
+                       return start;
+
+               case 3:
+                       item->size++;
+                       if ((end - start) < 4)
+                               return NULL;
+                       item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
+                       start = (__u8 *)((__le32 *)start + 1);
+                       return start;
+       }
+
+       return NULL;
+}
+
+/*
+ * Parse a report description into a hid_device structure. Reports are
+ * enumerated, fields are attached to these reports.
+ */
+
+static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+{
+       struct hid_device *device;
+       struct hid_parser *parser;
+       struct hid_item item;
+       __u8 *end;
+       unsigned i;
+       static int (*dispatch_type[])(struct hid_parser *parser,
+                                     struct hid_item *item) = {
+               hid_parser_main,
+               hid_parser_global,
+               hid_parser_local,
+               hid_parser_reserved
+       };
+
+       if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
+               return NULL;
+
+       if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
+                                  HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
+               kfree(device);
+               return NULL;
+       }
+       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 = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+               kfree(device->rdesc);
+               kfree(device->collection);
+               kfree(device);
+               return NULL;
+       }
+       parser->device = device;
+
+       end = start + size;
+       while ((start = fetch_item(start, end, &item)) != NULL) {
+
+               if (item.format != HID_ITEM_FORMAT_SHORT) {
+                       dbg("unexpected long global item");
+                       kfree(device->collection);
+                       hid_free_device(device);
+                       kfree(parser);
+                       return NULL;
+               }
+
+               if (dispatch_type[item.type](parser, &item)) {
+                       dbg("item %u %u %u %u parsing failed\n",
+                               item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+                       kfree(device->collection);
+                       hid_free_device(device);
+                       kfree(parser);
+                       return NULL;
+               }
+
+               if (start == end) {
+                       if (parser->collection_stack_ptr) {
+                               dbg("unbalanced collection at end of report description");
+                               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->collection);
+                               hid_free_device(device);
+                               kfree(parser);
+                               return NULL;
+                       }
+                       kfree(parser);
+                       return device;
+               }
+       }
+
+       dbg("item fetching failed at offset %d\n", (int)(end - start));
+       kfree(device->collection);
+       hid_free_device(device);
+       kfree(parser);
+       return NULL;
+}
+
+/*
+ * Convert a signed n-bit integer to signed 32-bit integer. Common
+ * cases are done through the compiler, the screwed things has to be
+ * done by hand.
+ */
+
+static s32 snto32(__u32 value, unsigned n)
+{
+       switch (n) {
+               case 8:  return ((__s8)value);
+               case 16: return ((__s16)value);
+               case 32: return ((__s32)value);
+       }
+       return value & (1 << (n - 1)) ? value | (-1 << n) : value;
+}
+
+/*
+ * Convert a signed 32-bit integer to a signed n-bit integer.
+ */
+
+static u32 s32ton(__s32 value, unsigned n)
+{
+       s32 a = value >> (n - 1);
+       if (a && a != -1)
+               return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+       return value & ((1 << n) - 1);
+}
+
+/*
+ * Extract/implement a data field from/to a little endian report (bit array).
+ *
+ * Code sort-of follows HID spec:
+ *     http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ *
+ * While the USB HID spec allows unlimited length bit fields in "report
+ * descriptors", most devices never use more than 16 bits.
+ * One model of UPS is claimed to report "LINEV" as a 32-bit field.
+ * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
+ */
+
+static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+{
+       u64 x;
+
+       WARN_ON(n > 32);
+
+       report += offset >> 3;  /* adjust byte index */
+       offset &= 7;            /* now only need bit offset into one byte */
+       x = get_unaligned((u64 *) report);
+       x = le64_to_cpu(x);
+       x = (x >> offset) & ((1ULL << n) - 1);  /* extract bit field */
+       return (u32) x;
+}
+
+/*
+ * "implement" : set bits in a little endian bit stream.
+ * Same concepts as "extract" (see comments above).
+ * The data mangled in the bit stream remains in little endian
+ * order the whole time. It make more sense to talk about
+ * endianness of register values by considering a register
+ * a "cached" copy of the little endiad bit stream.
+ */
+static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+{
+       u64 x;
+       u64 m = (1ULL << n) - 1;
+
+       WARN_ON(n > 32);
+
+       WARN_ON(value > m);
+       value &= m;
+
+       report += offset >> 3;
+       offset &= 7;
+
+       x = get_unaligned((u64 *)report);
+       x &= cpu_to_le64(~(m << offset));
+       x |= cpu_to_le64(((u64) value) << offset);
+       put_unaligned(x, (u64 *) report);
+}
+
+/*
+ * Search an array for a value.
+ */
+
+static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+{
+       while (n--) {
+               if (*array++ == value)
+                       return 0;
+       }
+       return -1;
+}
+
+static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
+{
+       hid_dump_input(usage, value);
+       if (hid->claimed & HID_CLAIMED_INPUT)
+               hidinput_hid_event(hid, field, usage, value);
+       if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
+               hiddev_hid_event(hid, field, usage, value);
+}
+
+/*
+ * Analyse a received field, and fetch the data from it. The field
+ * content is stored for next report processing (we do differential
+ * reporting to the layer).
+ */
+
+static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
+{
+       unsigned n;
+       unsigned count = field->report_count;
+       unsigned offset = field->report_offset;
+       unsigned size = field->report_size;
+       __s32 min = field->logical_minimum;
+       __s32 max = field->logical_maximum;
+       __s32 *value;
+
+       if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
+               return;
+
+       for (n = 0; n < count; n++) {
+
+                       value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
+                                                   extract(data, offset + n * size, size);
+
+                       if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
+                           && value[n] >= min && value[n] <= max
+                           && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+                               goto exit;
+       }
+
+       for (n = 0; n < count; n++) {
+
+               if (HID_MAIN_ITEM_VARIABLE & field->flags) {
+                       hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
+                       continue;
+               }
+
+               if (field->value[n] >= min && field->value[n] <= max
+                       && field->usage[field->value[n] - min].hid
+                       && search(value, field->value[n], count))
+                               hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
+
+               if (value[n] >= min && value[n] <= max
+                       && field->usage[value[n] - min].hid
+                       && search(field->value, value[n], count))
+                               hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
+       }
+
+       memcpy(field->value, value, count * sizeof(__s32));
+exit:
+       kfree(value);
+}
+
+
+/*
+ * Output the field into the report.
+ */
+
+static void hid_output_field(struct hid_field *field, __u8 *data)
+{
+       unsigned count = field->report_count;
+       unsigned offset = field->report_offset;
+       unsigned size = field->report_size;
+       unsigned n;
+
+       for (n = 0; n < count; n++) {
+               if (field->logical_minimum < 0) /* signed values */
+                       implement(data, offset + n * size, size, s32ton(field->value[n], size));
+               else                            /* unsigned values */
+                       implement(data, offset + n * size, size, field->value[n]);
+       }
+}
+
+/*
+ * Create a report.
+ */
+
+static void hid_output_report(struct hid_report *report, __u8 *data)
+{
+       unsigned n;
+
+       if (report->id > 0)
+               *data++ = report->id;
+
+       for (n = 0; n < report->maxfield; n++)
+               hid_output_field(report->field[n], data);
+}
+
+/*
+ * Set a field value. The report this field belongs to has to be
+ * created and transferred to the device, to set this value in the
+ * device.
+ */
+
+int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+{
+       unsigned size = field->report_size;
+
+       hid_dump_input(field->usage + offset, value);
+
+       if (offset >= field->report_count) {
+               dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
+               hid_dump_field(field, 8);
+               return -1;
+       }
+       if (field->logical_minimum < 0) {
+               if (value != snto32(s32ton(value, size), size)) {
+                       dbg("value %d is out of range", value);
+                       return -1;
+               }
+       }
+       field->value[offset] = value;
+       return 0;
+}
+
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
new file mode 100644 (file)
index 0000000..d459005
--- /dev/null
@@ -0,0 +1,840 @@
+/*
+ * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2006 Jiri Kosina
+ *
+ *  HID to Linux Input mapping
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/usb/input.h>
+
+#undef DEBUG
+
+#include <linux/hid.h>
+
+#define unk    KEY_UNKNOWN
+
+static const unsigned char hid_keyboard[256] = {
+         0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+        50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+         4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+        27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+        65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+       105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+        72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
+       191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
+       115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
+       122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+        29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+       150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
+};
+
+static const struct {
+       __s32 x;
+       __s32 y;
+}  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+#define map_abs(c)     do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
+#define map_rel(c)     do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
+#define map_key(c)     do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
+#define map_led(c)     do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
+
+#define map_abs_clear(c)       do { map_abs(c); clear_bit(c, bit); } while (0)
+#define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
+
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+
+struct hidinput_key_translation {
+       u16 from;
+       u16 to;
+       u8 flags;
+};
+
+#define POWERBOOK_FLAG_FKEY 0x01
+
+static struct hidinput_key_translation powerbook_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN,     POWERBOOK_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,       POWERBOOK_FLAG_FKEY },
+       { KEY_F3,       KEY_MUTE,               POWERBOOK_FLAG_FKEY },
+       { KEY_F4,       KEY_VOLUMEDOWN,         POWERBOOK_FLAG_FKEY },
+       { KEY_F5,       KEY_VOLUMEUP,           POWERBOOK_FLAG_FKEY },
+       { KEY_F6,       KEY_NUMLOCK,            POWERBOOK_FLAG_FKEY },
+       { KEY_F7,       KEY_SWITCHVIDEOMODE,    POWERBOOK_FLAG_FKEY },
+       { KEY_F8,       KEY_KBDILLUMTOGGLE,     POWERBOOK_FLAG_FKEY },
+       { KEY_F9,       KEY_KBDILLUMDOWN,       POWERBOOK_FLAG_FKEY },
+       { KEY_F10,      KEY_KBDILLUMUP,         POWERBOOK_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+static struct hidinput_key_translation powerbook_numlock_keys[] = {
+       { KEY_J,        KEY_KP1 },
+       { KEY_K,        KEY_KP2 },
+       { KEY_L,        KEY_KP3 },
+       { KEY_U,        KEY_KP4 },
+       { KEY_I,        KEY_KP5 },
+       { KEY_O,        KEY_KP6 },
+       { KEY_7,        KEY_KP7 },
+       { KEY_8,        KEY_KP8 },
+       { KEY_9,        KEY_KP9 },
+       { KEY_M,        KEY_KP0 },
+       { KEY_DOT,      KEY_KPDOT },
+       { KEY_SLASH,    KEY_KPPLUS },
+       { KEY_SEMICOLON, KEY_KPMINUS },
+       { KEY_P,        KEY_KPASTERISK },
+       { KEY_MINUS,    KEY_KPEQUAL },
+       { KEY_0,        KEY_KPSLASH },
+       { KEY_F6,       KEY_NUMLOCK },
+       { KEY_KPENTER,  KEY_KPENTER },
+       { KEY_BACKSPACE, KEY_BACKSPACE },
+       { }
+};
+
+static struct hidinput_key_translation powerbook_iso_keyboard[] = {
+       { KEY_GRAVE,    KEY_102ND },
+       { KEY_102ND,    KEY_GRAVE },
+       { }
+};
+
+
+static int usbhid_pb_fnmode = 1;
+module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
+MODULE_PARM_DESC(pb_fnmode,
+               "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
+
+static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
+{
+       struct hidinput_key_translation *trans;
+
+       /* Look for the translation */
+       for (trans = table; trans->from; trans++)
+               if (trans->from == from)
+                       return trans;
+
+       return NULL;
+}
+
+static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+               struct hid_usage *usage, __s32 value)
+{
+       struct hidinput_key_translation *trans;
+
+       if (usage->code == KEY_FN) {
+               if (value) hid->quirks |=  HID_QUIRK_POWERBOOK_FN_ON;
+               else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
+
+               input_event(input, usage->type, usage->code, value);
+
+               return 1;
+       }
+
+       if (usbhid_pb_fnmode) {
+               int do_translate;
+
+               trans = find_translation(powerbook_fn_keys, usage->code);
+               if (trans) {
+                       if (test_bit(usage->code, hid->pb_pressed_fn))
+                               do_translate = 1;
+                       else if (trans->flags & POWERBOOK_FLAG_FKEY)
+                               do_translate =
+                                       (usbhid_pb_fnmode == 2 &&  (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+                                       (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+                       else
+                               do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
+
+                       if (do_translate) {
+                               if (value)
+                                       set_bit(usage->code, hid->pb_pressed_fn);
+                               else
+                                       clear_bit(usage->code, hid->pb_pressed_fn);
+
+                               input_event(input, usage->type, trans->to, value);
+
+                               return 1;
+                       }
+               }
+
+               if (test_bit(usage->code, hid->pb_pressed_numlock) ||
+                               test_bit(LED_NUML, input->led)) {
+                       trans = find_translation(powerbook_numlock_keys, usage->code);
+
+                       if (trans) {
+                               if (value)
+                                       set_bit(usage->code, hid->pb_pressed_numlock);
+                               else
+                                       clear_bit(usage->code, hid->pb_pressed_numlock);
+
+                               input_event(input, usage->type, trans->to, value);
+                       }
+
+                       return 1;
+               }
+       }
+
+       if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
+               trans = find_translation(powerbook_iso_keyboard, usage->code);
+               if (trans) {
+                       input_event(input, usage->type, trans->to, value);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void hidinput_pb_setup(struct input_dev *input)
+{
+       struct hidinput_key_translation *trans;
+
+       set_bit(KEY_NUMLOCK, input->keybit);
+
+       /* Enable all needed keys */
+       for (trans = powerbook_fn_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+       for (trans = powerbook_numlock_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+       for (trans = powerbook_iso_keyboard; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+}
+#else
+static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+               struct hid_usage *usage, __s32 value)
+{
+       return 0;
+}
+
+static inline void hidinput_pb_setup(struct input_dev *input)
+{
+}
+#endif
+
+static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
+                                    struct hid_usage *usage)
+{
+       struct input_dev *input = hidinput->input;
+       struct hid_device *device = input->private;
+       int max = 0, code;
+       unsigned long *bit = NULL;
+
+       field->hidinput = hidinput;
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "Mapping: ");
+       resolv_usage(usage->hid);
+       printk(" ---> ");
+#endif
+
+       if (field->flags & HID_MAIN_ITEM_CONSTANT)
+               goto ignore;
+
+       switch (usage->hid & HID_USAGE_PAGE) {
+
+               case HID_UP_UNDEFINED:
+                       goto ignore;
+
+               case HID_UP_KEYBOARD:
+
+                       set_bit(EV_REP, input->evbit);
+
+                       if ((usage->hid & HID_USAGE) < 256) {
+                               if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
+                               map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
+                       } else
+                               map_key(KEY_UNKNOWN);
+
+                       break;
+
+               case HID_UP_BUTTON:
+
+                       code = ((usage->hid - 1) & 0xf);
+
+                       switch (field->application) {
+                               case HID_GD_MOUSE:
+                               case HID_GD_POINTER:  code += 0x110; break;
+                               case HID_GD_JOYSTICK: code += 0x120; break;
+                               case HID_GD_GAMEPAD:  code += 0x130; break;
+                               default:
+                                       switch (field->physical) {
+                                               case HID_GD_MOUSE:
+                                               case HID_GD_POINTER:  code += 0x110; break;
+                                               case HID_GD_JOYSTICK: code += 0x120; break;
+                                               case HID_GD_GAMEPAD:  code += 0x130; break;
+                                               default:              code += 0x100;
+                                       }
+                       }
+
+                       map_key(code);
+                       break;
+
+
+               case HID_UP_SIMULATION:
+
+                       switch (usage->hid & 0xffff) {
+                               case 0xba: map_abs(ABS_RUDDER);   break;
+                               case 0xbb: map_abs(ABS_THROTTLE); break;
+                               case 0xc4: map_abs(ABS_GAS);      break;
+                               case 0xc5: map_abs(ABS_BRAKE);    break;
+                               case 0xc8: map_abs(ABS_WHEEL);    break;
+                               default:   goto ignore;
+                       }
+                       break;
+
+               case HID_UP_GENDESK:
+
+                       if ((usage->hid & 0xf0) == 0x80) {      /* SystemControl */
+                               switch (usage->hid & 0xf) {
+                                       case 0x1: map_key_clear(KEY_POWER);  break;
+                                       case 0x2: map_key_clear(KEY_SLEEP);  break;
+                                       case 0x3: map_key_clear(KEY_WAKEUP); break;
+                                       default: goto unknown;
+                               }
+                               break;
+                       }
+
+                       if ((usage->hid & 0xf0) == 0x90) {      /* D-pad */
+                               switch (usage->hid) {
+                                       case HID_GD_UP:    usage->hat_dir = 1; break;
+                                       case HID_GD_DOWN:  usage->hat_dir = 5; break;
+                                       case HID_GD_RIGHT: usage->hat_dir = 3; break;
+                                       case HID_GD_LEFT:  usage->hat_dir = 7; break;
+                                       default: goto unknown;
+                               }
+                               if (field->dpad) {
+                                       map_abs(field->dpad);
+                                       goto ignore;
+                               }
+                               map_abs(ABS_HAT0X);
+                               break;
+                       }
+
+                       switch (usage->hid) {
+
+                               /* These usage IDs map directly to the usage codes. */
+                               case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
+                               case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+                               case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
+                                       if (field->flags & HID_MAIN_ITEM_RELATIVE)
+                                               map_rel(usage->hid & 0xf);
+                                       else
+                                               map_abs(usage->hid & 0xf);
+                                       break;
+
+                               case HID_GD_HATSWITCH:
+                                       usage->hat_min = field->logical_minimum;
+                                       usage->hat_max = field->logical_maximum;
+                                       map_abs(ABS_HAT0X);
+                                       break;
+
+                               case HID_GD_START:      map_key_clear(BTN_START);       break;
+                               case HID_GD_SELECT:     map_key_clear(BTN_SELECT);      break;
+
+                               default: goto unknown;
+                       }
+
+                       break;
+
+               case HID_UP_LED:
+                       if (((usage->hid - 1) & 0xffff) >= LED_MAX)
+                               goto ignore;
+                       map_led((usage->hid - 1) & 0xffff);
+                       break;
+
+               case HID_UP_DIGITIZER:
+
+                       switch (usage->hid & 0xff) {
+
+                               case 0x30: /* TipPressure */
+                                       if (!test_bit(BTN_TOUCH, input->keybit)) {
+                                               device->quirks |= HID_QUIRK_NOTOUCH;
+                                               set_bit(EV_KEY, input->evbit);
+                                               set_bit(BTN_TOUCH, input->keybit);
+                                       }
+
+                                       map_abs_clear(ABS_PRESSURE);
+                                       break;
+
+                               case 0x32: /* InRange */
+                                       switch (field->physical & 0xff) {
+                                               case 0x21: map_key(BTN_TOOL_MOUSE); break;
+                                               case 0x22: map_key(BTN_TOOL_FINGER); break;
+                                               default: map_key(BTN_TOOL_PEN); break;
+                                       }
+                                       break;
+
+                               case 0x3c: /* Invert */
+                                       map_key_clear(BTN_TOOL_RUBBER);
+                                       break;
+
+                               case 0x33: /* Touch */
+                               case 0x42: /* TipSwitch */
+                               case 0x43: /* TipSwitch2 */
+                                       device->quirks &= ~HID_QUIRK_NOTOUCH;
+                                       map_key_clear(BTN_TOUCH);
+                                       break;
+
+                               case 0x44: /* BarrelSwitch */
+                                       map_key_clear(BTN_STYLUS);
+                                       break;
+
+                               default:  goto unknown;
+                       }
+                       break;
+
+               case HID_UP_CONSUMER:   /* USB HUT v1.1, pages 56-62 */
+
+                       switch (usage->hid & HID_USAGE) {
+                               case 0x000: goto ignore;
+                               case 0x034: map_key_clear(KEY_SLEEP);           break;
+                               case 0x036: map_key_clear(BTN_MISC);            break;
+                               case 0x045: map_key_clear(KEY_RADIO);           break;
+                               case 0x08a: map_key_clear(KEY_WWW);             break;
+                               case 0x08d: map_key_clear(KEY_PROGRAM);         break;
+                               case 0x095: map_key_clear(KEY_HELP);            break;
+                               case 0x09c: map_key_clear(KEY_CHANNELUP);       break;
+                               case 0x09d: map_key_clear(KEY_CHANNELDOWN);     break;
+                               case 0x0b0: map_key_clear(KEY_PLAY);            break;
+                               case 0x0b1: map_key_clear(KEY_PAUSE);           break;
+                               case 0x0b2: map_key_clear(KEY_RECORD);          break;
+                               case 0x0b3: map_key_clear(KEY_FASTFORWARD);     break;
+                               case 0x0b4: map_key_clear(KEY_REWIND);          break;
+                               case 0x0b5: map_key_clear(KEY_NEXTSONG);        break;
+                               case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);    break;
+                               case 0x0b7: map_key_clear(KEY_STOPCD);          break;
+                               case 0x0b8: map_key_clear(KEY_EJECTCD);         break;
+                               case 0x0cd: map_key_clear(KEY_PLAYPAUSE);       break;
+                               case 0x0e0: map_abs_clear(ABS_VOLUME);          break;
+                               case 0x0e2: map_key_clear(KEY_MUTE);            break;
+                               case 0x0e5: map_key_clear(KEY_BASSBOOST);       break;
+                               case 0x0e9: map_key_clear(KEY_VOLUMEUP);        break;
+                               case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);      break;
+                               case 0x183: map_key_clear(KEY_CONFIG);          break;
+                               case 0x18a: map_key_clear(KEY_MAIL);            break;
+                               case 0x192: map_key_clear(KEY_CALC);            break;
+                               case 0x194: map_key_clear(KEY_FILE);            break;
+                               case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
+                               case 0x201: map_key_clear(KEY_NEW);             break;
+                               case 0x207: map_key_clear(KEY_SAVE);            break;
+                               case 0x208: map_key_clear(KEY_PRINT);           break;
+                               case 0x209: map_key_clear(KEY_PROPS);           break;
+                               case 0x21a: map_key_clear(KEY_UNDO);            break;
+                               case 0x21b: map_key_clear(KEY_COPY);            break;
+                               case 0x21c: map_key_clear(KEY_CUT);             break;
+                               case 0x21d: map_key_clear(KEY_PASTE);           break;
+                               case 0x221: map_key_clear(KEY_FIND);            break;
+                               case 0x223: map_key_clear(KEY_HOMEPAGE);        break;
+                               case 0x224: map_key_clear(KEY_BACK);            break;
+                               case 0x225: map_key_clear(KEY_FORWARD);         break;
+                               case 0x226: map_key_clear(KEY_STOP);            break;
+                               case 0x227: map_key_clear(KEY_REFRESH);         break;
+                               case 0x22a: map_key_clear(KEY_BOOKMARKS);       break;
+                               case 0x233: map_key_clear(KEY_SCROLLUP);        break;
+                               case 0x234: map_key_clear(KEY_SCROLLDOWN);      break;
+                               case 0x238: map_rel(REL_HWHEEL);                break;
+                               case 0x279: map_key_clear(KEY_REDO);            break;
+                               case 0x289: map_key_clear(KEY_REPLY);           break;
+                               case 0x28b: map_key_clear(KEY_FORWARDMAIL);     break;
+                               case 0x28c: map_key_clear(KEY_SEND);            break;
+
+                               /* Reported on a Cherry Cymotion keyboard */
+                               case 0x301: map_key_clear(KEY_PROG1);           break;
+                               case 0x302: map_key_clear(KEY_PROG2);           break;
+                               case 0x303: map_key_clear(KEY_PROG3);           break;
+
+                               default:    goto ignore;
+                       }
+                       break;
+
+               case HID_UP_HPVENDOR:   /* Reported on a Dutch layout HP5308 */
+
+                       set_bit(EV_REP, input->evbit);
+                       switch (usage->hid & HID_USAGE) {
+                               case 0x021: map_key_clear(KEY_PRINT);           break;
+                               case 0x070: map_key_clear(KEY_HP);              break;
+                               case 0x071: map_key_clear(KEY_CAMERA);          break;
+                               case 0x072: map_key_clear(KEY_SOUND);           break;
+                               case 0x073: map_key_clear(KEY_QUESTION);        break;
+                               case 0x080: map_key_clear(KEY_EMAIL);           break;
+                               case 0x081: map_key_clear(KEY_CHAT);            break;
+                               case 0x082: map_key_clear(KEY_SEARCH);          break;
+                               case 0x083: map_key_clear(KEY_CONNECT);         break;
+                               case 0x084: map_key_clear(KEY_FINANCE);         break;
+                               case 0x085: map_key_clear(KEY_SPORT);           break;
+                               case 0x086: map_key_clear(KEY_SHOP);            break;
+                               default:    goto ignore;
+                       }
+                       break;
+
+               case HID_UP_MSVENDOR:
+                       goto ignore;
+
+               case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
+
+                       set_bit(EV_REP, input->evbit);
+                       switch(usage->hid & HID_USAGE) {
+                               case 0x003:
+                                       /* The fn key on Apple PowerBooks */
+                                       map_key_clear(KEY_FN);
+                                       hidinput_pb_setup(input);
+                                       break;
+
+                               default:    goto ignore;
+                       }
+                       break;
+
+               case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
+
+                       set_bit(EV_REP, input->evbit);
+                       switch(usage->hid & HID_USAGE) {
+                               case 0x004: map_key_clear(KEY_AGAIN);           break;
+                               case 0x00d: map_key_clear(KEY_HOME);            break;
+                               case 0x024: map_key_clear(KEY_SHUFFLE);         break;
+                               case 0x025: map_key_clear(KEY_TV);              break;
+                               case 0x026: map_key_clear(KEY_MENU);            break;
+                               case 0x031: map_key_clear(KEY_AUDIO);           break;
+                               case 0x032: map_key_clear(KEY_TEXT);            break;
+                               case 0x033: map_key_clear(KEY_LAST);            break;
+                               case 0x047: map_key_clear(KEY_MP3);             break;
+                               case 0x048: map_key_clear(KEY_DVD);             break;
+                               case 0x049: map_key_clear(KEY_MEDIA);           break;
+                               case 0x04a: map_key_clear(KEY_VIDEO);           break;
+                               case 0x04b: map_key_clear(KEY_ANGLE);           break;
+                               case 0x04c: map_key_clear(KEY_LANGUAGE);        break;
+                               case 0x04d: map_key_clear(KEY_SUBTITLE);        break;
+                               case 0x051: map_key_clear(KEY_RED);             break;
+                               case 0x052: map_key_clear(KEY_CLOSE);           break;
+                               default:    goto ignore;
+                       }
+                       break;
+
+               case HID_UP_PID:
+
+                       switch(usage->hid & HID_USAGE) {
+                               case 0xa4: map_key_clear(BTN_DEAD);     break;
+                               default: goto ignore;
+                       }
+                       break;
+
+               default:
+               unknown:
+                       if (field->report_size == 1) {
+                               if (field->report->type == HID_OUTPUT_REPORT) {
+                                       map_led(LED_MISC);
+                                       break;
+                               }
+                               map_key(BTN_MISC);
+                               break;
+                       }
+                       if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+                               map_rel(REL_MISC);
+                               break;
+                       }
+                       map_abs(ABS_MISC);
+                       break;
+       }
+
+       if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
+               if (usage->hid == HID_GD_Z)
+                       map_rel(REL_HWHEEL);
+               else if (usage->code == BTN_1)
+                       map_key(BTN_2);
+               else if (usage->code == BTN_2)
+                       map_key(BTN_1);
+       }
+
+       if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
+                (usage->type == EV_REL) && (usage->code == REL_WHEEL))
+                       set_bit(REL_HWHEEL, bit);
+
+       if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
+               || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
+               goto ignore;
+
+       if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
+               usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
+               field->flags &= ~HID_MAIN_ITEM_RELATIVE;
+
+       set_bit(usage->type, input->evbit);
+
+       while (usage->code <= max && test_and_set_bit(usage->code, bit))
+               usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+
+       if (usage->code > max)
+               goto ignore;
+
+
+       if (usage->type == EV_ABS) {
+
+               int a = field->logical_minimum;
+               int b = field->logical_maximum;
+
+               if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
+                       a = field->logical_minimum = 0;
+                       b = field->logical_maximum = 255;
+               }
+
+               if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
+                       input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
+               else    input_set_abs_params(input, usage->code, a, b, 0, 0);
+
+       }
+
+       if (usage->type == EV_ABS &&
+           (usage->hat_min < usage->hat_max || usage->hat_dir)) {
+               int i;
+               for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
+                       input_set_abs_params(input, i, -1, 1, 0, 0);
+                       set_bit(i, input->absbit);
+               }
+               if (usage->hat_dir && !field->dpad)
+                       field->dpad = usage->code;
+       }
+
+#ifdef DEBUG
+       resolv_event(usage->type, usage->code);
+       printk("\n");
+#endif
+       return;
+
+ignore:
+#ifdef DEBUG
+       printk("IGNORED\n");
+#endif
+       return;
+}
+
+void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+       struct input_dev *input;
+       int *quirks = &hid->quirks;
+
+       if (!field->hidinput)
+               return;
+
+       input = field->hidinput->input;
+
+       if (!usage->type)
+               return;
+
+       if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
+               || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
+               if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+               else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+               return;
+       }
+
+       if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
+               input_event(input, usage->type, usage->code, -value);
+               return;
+       }
+
+       if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
+               input_event(input, usage->type, REL_HWHEEL, value);
+               return;
+       }
+
+       if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
+               return;
+
+       if (usage->hat_min < usage->hat_max || usage->hat_dir) {
+               int hat_dir = usage->hat_dir;
+               if (!hat_dir)
+                       hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
+               if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
+               input_event(input, usage->type, usage->code    , hid_hat_to_axis[hat_dir].x);
+                input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
+                return;
+        }
+
+       if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
+               *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
+               return;
+       }
+
+       if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
+               if (value) {
+                       input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
+                       return;
+               }
+               input_event(input, usage->type, usage->code, 0);
+               input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
+               return;
+       }
+
+       if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
+               int a = field->logical_minimum;
+               int b = field->logical_maximum;
+               input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
+       }
+
+       if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
+               dbg("Maximum Effects - %d",value);
+               return;
+       }
+
+       if (usage->hid == (HID_UP_PID | 0x7fUL)) {
+               dbg("PID Pool Report\n");
+               return;
+       }
+
+       if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
+               return;
+
+       input_event(input, usage->type, usage->code, value);
+
+       if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
+               input_event(input, usage->type, usage->code, 0);
+}
+
+void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
+{
+       struct hid_input *hidinput;
+
+       list_for_each_entry(hidinput, &hid->inputs, list)
+               input_sync(hidinput->input);
+}
+
+static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+{
+       struct hid_report *report;
+       int i, j;
+
+       list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
+               for (i = 0; i < report->maxfield; i++) {
+                       *field = report->field[i];
+                       for (j = 0; j < (*field)->maxusage; j++)
+                               if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
+                                       return j;
+               }
+       }
+       return -1;
+}
+
+/*
+ * Register the input device; print a message.
+ * Configure the input layer interface
+ * Read all reports and initialize the absolute field values.
+ */
+
+int hidinput_connect(struct hid_device *hid)
+{
+       struct usb_device *dev = hid->dev;
+       struct hid_report *report;
+       struct hid_input *hidinput = NULL;
+       struct input_dev *input_dev;
+       int i, j, k;
+
+       INIT_LIST_HEAD(&hid->inputs);
+
+       for (i = 0; i < hid->maxcollection; i++)
+               if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
+                   hid->collection[i].type == HID_COLLECTION_PHYSICAL)
+                       if (IS_INPUT_APPLICATION(hid->collection[i].usage))
+                               break;
+
+       if (i == hid->maxcollection)
+               return -1;
+
+       for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+               list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
+
+                       if (!report->maxfield)
+                               continue;
+
+                       if (!hidinput) {
+                               hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
+                               input_dev = input_allocate_device();
+                               if (!hidinput || !input_dev) {
+                                       kfree(hidinput);
+                                       input_free_device(input_dev);
+                                       err("Out of memory during hid input probe");
+                                       return -1;
+                               }
+
+                               input_dev->private = hid;
+                               input_dev->event = hidinput_input_event;
+                               input_dev->open = hidinput_open;
+                               input_dev->close = hidinput_close;
+
+                               input_dev->name = hid->name;
+                               input_dev->phys = hid->phys;
+                               input_dev->uniq = hid->uniq;
+                               usb_to_input_id(dev, &input_dev->id);
+                               input_dev->cdev.dev = &hid->intf->dev;
+
+                               hidinput->input = input_dev;
+                               list_add_tail(&hidinput->list, &hid->inputs);
+                       }
+
+                       for (i = 0; i < report->maxfield; i++)
+                               for (j = 0; j < report->field[i]->maxusage; j++)
+                                       hidinput_configure_usage(hidinput, report->field[i],
+                                                                report->field[i]->usage + j);
+
+                       if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
+                               /* This will leave hidinput NULL, so that it
+                                * allocates another one if we have more inputs on
+                                * the same interface. Some devices (e.g. Happ's
+                                * UGCI) cram a lot of unrelated inputs into the
+                                * same interface. */
+                               hidinput->report = report;
+                               input_register_device(hidinput->input);
+                               hidinput = NULL;
+                       }
+               }
+
+       /* This only gets called when we are a single-input (most of the
+        * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
+        * only useful in this case, and not for multi-input quirks. */
+       if (hidinput) {
+               hid_ff_init(hid);
+               input_register_device(hidinput->input);
+       }
+
+       return 0;
+}
+
+void hidinput_disconnect(struct hid_device *hid)
+{
+       struct hid_input *hidinput, *next;
+
+       list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
+               list_del(&hidinput->list);
+               input_unregister_device(hidinput->input);
+               kfree(hidinput);
+       }
+}
index 0811c39bd14f785900defc5787119f8f47e5bef5..06e169b6a17eb3975e6fefaf56068a7403b2c85f 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006 Jiri Kosina
  */
 
 /*
@@ -32,7 +33,7 @@
 
 #include <linux/usb.h>
 
-#include "hid.h"
+#include <linux/hid.h>
 #include <linux/hiddev.h>
 
 /*
@@ -54,887 +55,6 @@ static unsigned int hid_mousepoll_interval;
 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
 MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
-/*
- * Register a new report for a device.
- */
-
-static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
-{
-       struct hid_report_enum *report_enum = device->report_enum + type;
-       struct hid_report *report;
-
-       if (report_enum->report_id_hash[id])
-               return report_enum->report_id_hash[id];
-
-       if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
-               return NULL;
-
-       if (id != 0)
-               report_enum->numbered = 1;
-
-       report->id = id;
-       report->type = type;
-       report->size = 0;
-       report->device = device;
-       report_enum->report_id_hash[id] = report;
-
-       list_add_tail(&report->list, &report_enum->report_list);
-
-       return report;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
-{
-       struct hid_field *field;
-
-       if (report->maxfield == HID_MAX_FIELDS) {
-               dbg("too many fields in report");
-               return NULL;
-       }
-
-       if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-               + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
-
-       field->index = report->maxfield++;
-       report->field[field->index] = field;
-       field->usage = (struct hid_usage *)(field + 1);
-       field->value = (unsigned *)(field->usage + usages);
-       field->report = report;
-
-       return field;
-}
-
-/*
- * Open a collection. The type/usage is pushed on the stack.
- */
-
-static int open_collection(struct hid_parser *parser, unsigned type)
-{
-       struct hid_collection *collection;
-       unsigned usage;
-
-       usage = parser->local.usage[0];
-
-       if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
-               dbg("collection stack overflow");
-               return -1;
-       }
-
-       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;
-}
-
-/*
- * Close a collection.
- */
-
-static int close_collection(struct hid_parser *parser)
-{
-       if (!parser->collection_stack_ptr) {
-               dbg("collection stack underflow");
-               return -1;
-       }
-       parser->collection_stack_ptr--;
-       return 0;
-}
-
-/*
- * Climb up the stack, search for the specified collection type
- * and return the usage.
- */
-
-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->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 */
-}
-
-/*
- * Add a usage to the temporary parser table.
- */
-
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
-{
-       if (parser->local.usage_index >= HID_MAX_USAGES) {
-               dbg("usage index exceeded");
-               return -1;
-       }
-       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;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
-{
-       struct hid_report *report;
-       struct hid_field *field;
-       int usages;
-       unsigned offset;
-       int i;
-
-       if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
-               dbg("hid_register_report failed");
-               return -1;
-       }
-
-       if (parser->global.logical_maximum < parser->global.logical_minimum) {
-               dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
-               return -1;
-       }
-
-       offset = report->size;
-       report->size += parser->global.report_size * parser->global.report_count;
-
-       if (!parser->local.usage_index) /* Ignore padding fields */
-               return 0;
-
-       usages = max_t(int, parser->local.usage_index, parser->global.report_count);
-
-       if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
-               return 0;
-
-       field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
-       field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
-       field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
-
-       for (i = 0; i < usages; i++) {
-               int j = i;
-               /* Duplicate the last usage we parsed if we have excess values */
-               if (i >= parser->local.usage_index)
-                       j = parser->local.usage_index - 1;
-               field->usage[i].hid = parser->local.usage[j];
-               field->usage[i].collection_index =
-                       parser->local.collection_index[j];
-       }
-
-       field->maxusage = usages;
-       field->flags = flags;
-       field->report_offset = offset;
-       field->report_type = report_type;
-       field->report_size = parser->global.report_size;
-       field->report_count = parser->global.report_count;
-       field->logical_minimum = parser->global.logical_minimum;
-       field->logical_maximum = parser->global.logical_maximum;
-       field->physical_minimum = parser->global.physical_minimum;
-       field->physical_maximum = parser->global.physical_maximum;
-       field->unit_exponent = parser->global.unit_exponent;
-       field->unit = parser->global.unit;
-
-       return 0;
-}
-
-/*
- * Read data value from item.
- */
-
-static u32 item_udata(struct hid_item *item)
-{
-       switch (item->size) {
-               case 1: return item->data.u8;
-               case 2: return item->data.u16;
-               case 4: return item->data.u32;
-       }
-       return 0;
-}
-
-static s32 item_sdata(struct hid_item *item)
-{
-       switch (item->size) {
-               case 1: return item->data.s8;
-               case 2: return item->data.s16;
-               case 4: return item->data.s32;
-       }
-       return 0;
-}
-
-/*
- * Process a global item.
- */
-
-static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
-{
-       switch (item->tag) {
-
-               case HID_GLOBAL_ITEM_TAG_PUSH:
-
-                       if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
-                               dbg("global enviroment stack overflow");
-                               return -1;
-                       }
-
-                       memcpy(parser->global_stack + parser->global_stack_ptr++,
-                               &parser->global, sizeof(struct hid_global));
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_POP:
-
-                       if (!parser->global_stack_ptr) {
-                               dbg("global enviroment stack underflow");
-                               return -1;
-                       }
-
-                       memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
-                               sizeof(struct hid_global));
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-                       parser->global.usage_page = item_udata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-                       parser->global.logical_minimum = item_sdata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-                       if (parser->global.logical_minimum < 0)
-                               parser->global.logical_maximum = item_sdata(item);
-                       else
-                               parser->global.logical_maximum = item_udata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-                       parser->global.physical_minimum = item_sdata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-                       if (parser->global.physical_minimum < 0)
-                               parser->global.physical_maximum = item_sdata(item);
-                       else
-                               parser->global.physical_maximum = item_udata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-                       parser->global.unit_exponent = item_sdata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_UNIT:
-                       parser->global.unit = item_udata(item);
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
-                       if ((parser->global.report_size = item_udata(item)) > 32) {
-                               dbg("invalid report_size %d", parser->global.report_size);
-                               return -1;
-                       }
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-                       if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-                               dbg("invalid report_count %d", parser->global.report_count);
-                               return -1;
-                       }
-                       return 0;
-
-               case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-                       if ((parser->global.report_id = item_udata(item)) == 0) {
-                               dbg("report_id 0 is invalid");
-                               return -1;
-                       }
-                       return 0;
-
-               default:
-                       dbg("unknown global tag 0x%x", item->tag);
-                       return -1;
-       }
-}
-
-/*
- * Process a local item.
- */
-
-static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
-{
-       __u32 data;
-       unsigned n;
-
-       if (item->size == 0) {
-               dbg("item data expected for local item");
-               return -1;
-       }
-
-       data = item_udata(item);
-
-       switch (item->tag) {
-
-               case HID_LOCAL_ITEM_TAG_DELIMITER:
-
-                       if (data) {
-                               /*
-                                * We treat items before the first delimiter
-                                * as global to all usage sets (branch 0).
-                                * In the moment we process only these global
-                                * items and the first delimiter set.
-                                */
-                               if (parser->local.delimiter_depth != 0) {
-                                       dbg("nested delimiters");
-                                       return -1;
-                               }
-                               parser->local.delimiter_depth++;
-                               parser->local.delimiter_branch++;
-                       } else {
-                               if (parser->local.delimiter_depth < 1) {
-                                       dbg("bogus close delimiter");
-                                       return -1;
-                               }
-                               parser->local.delimiter_depth--;
-                       }
-                       return 1;
-
-               case HID_LOCAL_ITEM_TAG_USAGE:
-
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
-                               return 0;
-                       }
-
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
-
-                       return hid_add_usage(parser, data);
-
-               case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
-                               return 0;
-                       }
-
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
-
-                       parser->local.usage_minimum = data;
-                       return 0;
-
-               case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
-                               return 0;
-                       }
-
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
-
-                       for (n = parser->local.usage_minimum; n <= data; n++)
-                               if (hid_add_usage(parser, n)) {
-                                       dbg("hid_add_usage failed\n");
-                                       return -1;
-                               }
-                       return 0;
-
-               default:
-
-                       dbg("unknown local item tag 0x%x", item->tag);
-                       return 0;
-       }
-       return 0;
-}
-
-/*
- * Process a main item.
- */
-
-static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
-{
-       __u32 data;
-       int ret;
-
-       data = item_udata(item);
-
-       switch (item->tag) {
-               case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-                       ret = open_collection(parser, data & 0xff);
-                       break;
-               case HID_MAIN_ITEM_TAG_END_COLLECTION:
-                       ret = close_collection(parser);
-                       break;
-               case HID_MAIN_ITEM_TAG_INPUT:
-                       ret = hid_add_field(parser, HID_INPUT_REPORT, data);
-                       break;
-               case HID_MAIN_ITEM_TAG_OUTPUT:
-                       ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
-                       break;
-               case HID_MAIN_ITEM_TAG_FEATURE:
-                       ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
-                       break;
-               default:
-                       dbg("unknown main item tag 0x%x", item->tag);
-                       ret = 0;
-       }
-
-       memset(&parser->local, 0, sizeof(parser->local));       /* Reset the local parser environment */
-
-       return ret;
-}
-
-/*
- * Process a reserved item.
- */
-
-static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
-{
-       dbg("reserved item type, tag 0x%x", item->tag);
-       return 0;
-}
-
-/*
- * Free a report and all registered fields. The field->usage and
- * field->value table's are allocated behind the field, so we need
- * only to free(field) itself.
- */
-
-static void hid_free_report(struct hid_report *report)
-{
-       unsigned n;
-
-       for (n = 0; n < report->maxfield; n++)
-               kfree(report->field[n]);
-       kfree(report);
-}
-
-/*
- * Free a device structure, all reports, and all fields.
- */
-
-static void hid_free_device(struct hid_device *device)
-{
-       unsigned i,j;
-
-       for (i = 0; i < HID_REPORT_TYPES; i++) {
-               struct hid_report_enum *report_enum = device->report_enum + i;
-
-               for (j = 0; j < 256; j++) {
-                       struct hid_report *report = report_enum->report_id_hash[j];
-                       if (report)
-                               hid_free_report(report);
-               }
-       }
-
-       kfree(device->rdesc);
-       kfree(device);
-}
-
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
-
-static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
-{
-       u8 b;
-
-       if ((end - start) <= 0)
-               return NULL;
-
-       b = *start++;
-
-       item->type = (b >> 2) & 3;
-       item->tag  = (b >> 4) & 15;
-
-       if (item->tag == HID_ITEM_TAG_LONG) {
-
-               item->format = HID_ITEM_FORMAT_LONG;
-
-               if ((end - start) < 2)
-                       return NULL;
-
-               item->size = *start++;
-               item->tag  = *start++;
-
-               if ((end - start) < item->size)
-                       return NULL;
-
-               item->data.longdata = start;
-               start += item->size;
-               return start;
-       }
-
-       item->format = HID_ITEM_FORMAT_SHORT;
-       item->size = b & 3;
-
-       switch (item->size) {
-
-               case 0:
-                       return start;
-
-               case 1:
-                       if ((end - start) < 1)
-                               return NULL;
-                       item->data.u8 = *start++;
-                       return start;
-
-               case 2:
-                       if ((end - start) < 2)
-                               return NULL;
-                       item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
-                       start = (__u8 *)((__le16 *)start + 1);
-                       return start;
-
-               case 3:
-                       item->size++;
-                       if ((end - start) < 4)
-                               return NULL;
-                       item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
-                       start = (__u8 *)((__le32 *)start + 1);
-                       return start;
-       }
-
-       return NULL;
-}
-
-/*
- * Parse a report description into a hid_device structure. Reports are
- * enumerated, fields are attached to these reports.
- */
-
-static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
-{
-       struct hid_device *device;
-       struct hid_parser *parser;
-       struct hid_item item;
-       __u8 *end;
-       unsigned i;
-       static int (*dispatch_type[])(struct hid_parser *parser,
-                                     struct hid_item *item) = {
-               hid_parser_main,
-               hid_parser_global,
-               hid_parser_local,
-               hid_parser_reserved
-       };
-
-       if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
-               return NULL;
-
-       if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
-                                  HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
-               kfree(device);
-               return NULL;
-       }
-       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 = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
-               kfree(device->rdesc);
-               kfree(device->collection);
-               kfree(device);
-               return NULL;
-       }
-       parser->device = device;
-
-       end = start + size;
-       while ((start = fetch_item(start, end, &item)) != NULL) {
-
-               if (item.format != HID_ITEM_FORMAT_SHORT) {
-                       dbg("unexpected long global item");
-                       kfree(device->collection);
-                       hid_free_device(device);
-                       kfree(parser);
-                       return NULL;
-               }
-
-               if (dispatch_type[item.type](parser, &item)) {
-                       dbg("item %u %u %u %u parsing failed\n",
-                               item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
-                       kfree(device->collection);
-                       hid_free_device(device);
-                       kfree(parser);
-                       return NULL;
-               }
-
-               if (start == end) {
-                       if (parser->collection_stack_ptr) {
-                               dbg("unbalanced collection at end of report description");
-                               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->collection);
-                               hid_free_device(device);
-                               kfree(parser);
-                               return NULL;
-                       }
-                       kfree(parser);
-                       return device;
-               }
-       }
-
-       dbg("item fetching failed at offset %d\n", (int)(end - start));
-       kfree(device->collection);
-       hid_free_device(device);
-       kfree(parser);
-       return NULL;
-}
-
-/*
- * Convert a signed n-bit integer to signed 32-bit integer. Common
- * cases are done through the compiler, the screwed things has to be
- * done by hand.
- */
-
-static s32 snto32(__u32 value, unsigned n)
-{
-       switch (n) {
-               case 8:  return ((__s8)value);
-               case 16: return ((__s16)value);
-               case 32: return ((__s32)value);
-       }
-       return value & (1 << (n - 1)) ? value | (-1 << n) : value;
-}
-
-/*
- * Convert a signed 32-bit integer to a signed n-bit integer.
- */
-
-static u32 s32ton(__s32 value, unsigned n)
-{
-       s32 a = value >> (n - 1);
-       if (a && a != -1)
-               return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
-       return value & ((1 << n) - 1);
-}
-
-/*
- * Extract/implement a data field from/to a little endian report (bit array).
- *
- * Code sort-of follows HID spec:
- *     http://www.usb.org/developers/devclass_docs/HID1_11.pdf
- *
- * While the USB HID spec allows unlimited length bit fields in "report
- * descriptors", most devices never use more than 16 bits.
- * One model of UPS is claimed to report "LINEV" as a 32-bit field.
- * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
- */
-
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
-{
-       u64 x;
-
-       WARN_ON(n > 32);
-
-       report += offset >> 3;  /* adjust byte index */
-       offset &= 7;            /* now only need bit offset into one byte */
-       x = get_unaligned((u64 *) report);
-       x = le64_to_cpu(x);
-       x = (x >> offset) & ((1ULL << n) - 1);  /* extract bit field */
-       return (u32) x;
-}
-
-/*
- * "implement" : set bits in a little endian bit stream.
- * Same concepts as "extract" (see comments above).
- * The data mangled in the bit stream remains in little endian
- * order the whole time. It make more sense to talk about
- * endianness of register values by considering a register
- * a "cached" copy of the little endiad bit stream.
- */
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
-{
-       u64 x;
-       u64 m = (1ULL << n) - 1;
-
-       WARN_ON(n > 32);
-
-       WARN_ON(value > m);
-       value &= m;
-
-       report += offset >> 3;
-       offset &= 7;
-
-       x = get_unaligned((u64 *)report);
-       x &= cpu_to_le64(~(m << offset));
-       x |= cpu_to_le64(((u64) value) << offset);
-       put_unaligned(x, (u64 *) report);
-}
-
-/*
- * Search an array for a value.
- */
-
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
-{
-       while (n--) {
-               if (*array++ == value)
-                       return 0;
-       }
-       return -1;
-}
-
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
-{
-       hid_dump_input(usage, value);
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               hidinput_hid_event(hid, field, usage, value);
-       if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
-               hiddev_hid_event(hid, field, usage, value);
-}
-
-/*
- * Analyse a received field, and fetch the data from it. The field
- * content is stored for next report processing (we do differential
- * reporting to the layer).
- */
-
-static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
-{
-       unsigned n;
-       unsigned count = field->report_count;
-       unsigned offset = field->report_offset;
-       unsigned size = field->report_size;
-       __s32 min = field->logical_minimum;
-       __s32 max = field->logical_maximum;
-       __s32 *value;
-
-       if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
-               return;
-
-       for (n = 0; n < count; n++) {
-
-                       value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
-                                                   extract(data, offset + n * size, size);
-
-                       if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
-                           && value[n] >= min && value[n] <= max
-                           && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
-                               goto exit;
-       }
-
-       for (n = 0; n < count; n++) {
-
-               if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-                       hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
-                       continue;
-               }
-
-               if (field->value[n] >= min && field->value[n] <= max
-                       && field->usage[field->value[n] - min].hid
-                       && search(value, field->value[n], count))
-                               hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
-
-               if (value[n] >= min && value[n] <= max
-                       && field->usage[value[n] - min].hid
-                       && search(field->value, value[n], count))
-                               hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
-       }
-
-       memcpy(field->value, value, count * sizeof(__s32));
-exit:
-       kfree(value);
-}
-
-static int hid_input_report(int type, struct urb *urb, int interrupt)
-{
-       struct hid_device *hid = urb->context;
-       struct hid_report_enum *report_enum = hid->report_enum + type;
-       u8 *data = urb->transfer_buffer;
-       int len = urb->actual_length;
-       struct hid_report *report;
-       int n, size;
-
-       if (!len) {
-               dbg("empty report");
-               return -1;
-       }
-
-#ifdef DEBUG_DATA
-       printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
-#endif
-
-       n = 0;                          /* Normally report number is 0 */
-       if (report_enum->numbered) {    /* Device uses numbered reports, data[0] is report number */
-               n = *data++;
-               len--;
-       }
-
-#ifdef DEBUG_DATA
-       {
-               int i;
-               printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
-               for (i = 0; i < len; i++)
-                       printk(" %02x", data[i]);
-               printk("\n");
-       }
-#endif
-
-       if (!(report = report_enum->report_id_hash[n])) {
-               dbg("undefined report_id %d received", n);
-               return -1;
-       }
-
-       size = ((report->size - 1) >> 3) + 1;
-
-       if (len < size) {
-               dbg("report %d is too short, (%d < %d)", report->id, len, size);
-               memset(data + len, 0, size - len);
-       }
-
-       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, interrupt);
-
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               hidinput_report_event(hid, report);
-
-       return 0;
-}
-
 /*
  * Input submission and I/O error handler.
  */
@@ -1044,6 +164,65 @@ done:
        spin_unlock_irqrestore(&hid->inlock, flags);
 }
 
+
+static int hid_input_report(int type, struct urb *urb, int interrupt)
+{
+       struct hid_device *hid = urb->context;
+       struct hid_report_enum *report_enum = hid->report_enum + type;
+       u8 *data = urb->transfer_buffer;
+       int len = urb->actual_length;
+       struct hid_report *report;
+       int n, size;
+
+       if (!len) {
+               dbg("empty report");
+               return -1;
+       }
+
+#ifdef DEBUG_DATA
+       printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
+#endif
+
+       n = 0;                          /* Normally report number is 0 */
+       if (report_enum->numbered) {    /* Device uses numbered reports, data[0] is report number */
+               n = *data++;
+               len--;
+       }
+
+#ifdef DEBUG_DATA
+       {
+               int i;
+               printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
+               for (i = 0; i < len; i++)
+                       printk(" %02x", data[i]);
+               printk("\n");
+       }
+#endif
+
+       if (!(report = report_enum->report_id_hash[n])) {
+               dbg("undefined report_id %d received", n);
+               return -1;
+       }
+
+       size = ((report->size - 1) >> 3) + 1;
+
+       if (len < size) {
+               dbg("report %d is too short, (%d < %d)", report->id, len, size);
+               memset(data + len, 0, size - len);
+       }
+
+       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, interrupt);
+
+       if (hid->claimed & HID_CLAIMED_INPUT)
+               hidinput_report_event(hid, report);
+
+       return 0;
+}
+
 /*
  * Input interrupt completion handler.
  */
@@ -1092,67 +271,6 @@ static void hid_irq_in(struct urb *urb)
        }
 }
 
-/*
- * Output the field into the report.
- */
-
-static void hid_output_field(struct hid_field *field, __u8 *data)
-{
-       unsigned count = field->report_count;
-       unsigned offset = field->report_offset;
-       unsigned size = field->report_size;
-       unsigned n;
-
-       for (n = 0; n < count; n++) {
-               if (field->logical_minimum < 0) /* signed values */
-                       implement(data, offset + n * size, size, s32ton(field->value[n], size));
-               else                            /* unsigned values */
-                       implement(data, offset + n * size, size, field->value[n]);
-       }
-}
-
-/*
- * Create a report.
- */
-
-static void hid_output_report(struct hid_report *report, __u8 *data)
-{
-       unsigned n;
-
-       if (report->id > 0)
-               *data++ = report->id;
-
-       for (n = 0; n < report->maxfield; n++)
-               hid_output_field(report->field[n], data);
-}
-
-/*
- * Set a field value. The report this field belongs to has to be
- * created and transferred to the device, to set this value in the
- * device.
- */
-
-int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
-{
-       unsigned size = field->report_size;
-
-       hid_dump_input(field->usage + offset, value);
-
-       if (offset >= field->report_count) {
-               dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
-               hid_dump_field(field, 8);
-               return -1;
-       }
-       if (field->logical_minimum < 0) {
-               if (value != snto32(s32ton(value, size), size)) {
-                       dbg("value %d is out of range", value);
-                       return -1;
-               }
-       }
-       field->value[offset] = value;
-       return 0;
-}
-
 /*
  * Find a report field with a specified HID usage.
  */
@@ -1379,6 +497,29 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign
        spin_unlock_irqrestore(&hid->ctrllock, flags);
 }
 
+static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct hid_device *hid = dev->private;
+       struct hid_field *field;
+       int offset;
+
+       if (type == EV_FF)
+               return input_ff_event(dev, type, code, value);
+
+       if (type != EV_LED)
+               return -1;
+
+       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+               warn("event field not found");
+               return -1;
+       }
+
+       hid_set_field(field, offset, value);
+       hid_submit_report(hid, field->report, USB_DIR_OUT);
+
+       return 0;
+}
+
 int hid_wait_io(struct hid_device *hid)
 {
        if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
@@ -1428,6 +569,18 @@ void hid_close(struct hid_device *hid)
                usb_kill_urb(hid->urbin);
 }
 
+static int hidinput_open(struct input_dev *dev)
+{
+       struct hid_device *hid = dev->private;
+       return hid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+       struct hid_device *hid = dev->private;
+       hid_close(hid);
+}
+
 #define USB_VENDOR_ID_PANJIT           0x134c
 
 #define USB_VENDOR_ID_TURBOX           0x062a
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
deleted file mode 100644 (file)
index f04d6d7..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
- *
- *  (c) 1999 Andreas Gal               <gal@cs.uni-magdeburg.de>
- *  (c) 2000-2001 Vojtech Pavlik       <vojtech@ucw.cz>
- *
- *  Some debug stuff for the HID parser.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/input.h>
-
-struct hid_usage_entry {
-       unsigned  page;
-       unsigned  usage;
-       char     *description;
-};
-
-static const struct hid_usage_entry hid_usage_table[] = {
-  {  0,      0, "Undefined" },
-  {  1,      0, "GenericDesktop" },
-    {0, 0x01, "Pointer"},
-    {0, 0x02, "Mouse"},
-    {0, 0x04, "Joystick"},
-    {0, 0x05, "GamePad"},
-    {0, 0x06, "Keyboard"},
-    {0, 0x07, "Keypad"},
-    {0, 0x08, "MultiAxis"},
-      {0, 0x30, "X"},
-      {0, 0x31, "Y"},
-      {0, 0x32, "Z"},
-      {0, 0x33, "Rx"},
-      {0, 0x34, "Ry"},
-      {0, 0x35, "Rz"},
-      {0, 0x36, "Slider"},
-      {0, 0x37, "Dial"},
-      {0, 0x38, "Wheel"},
-      {0, 0x39, "HatSwitch"},
-    {0, 0x3a, "CountedBuffer"},
-      {0, 0x3b, "ByteCount"},
-      {0, 0x3c, "MotionWakeup"},
-      {0, 0x3d, "Start"},
-      {0, 0x3e, "Select"},
-      {0, 0x40, "Vx"},
-      {0, 0x41, "Vy"},
-      {0, 0x42, "Vz"},
-      {0, 0x43, "Vbrx"},
-      {0, 0x44, "Vbry"},
-      {0, 0x45, "Vbrz"},
-      {0, 0x46, "Vno"},
-    {0, 0x80, "SystemControl"},
-      {0, 0x81, "SystemPowerDown"},
-      {0, 0x82, "SystemSleep"},
-      {0, 0x83, "SystemWakeUp"},
-      {0, 0x84, "SystemContextMenu"},
-      {0, 0x85, "SystemMainMenu"},
-      {0, 0x86, "SystemAppMenu"},
-      {0, 0x87, "SystemMenuHelp"},
-      {0, 0x88, "SystemMenuExit"},
-      {0, 0x89, "SystemMenuSelect"},
-      {0, 0x8a, "SystemMenuRight"},
-      {0, 0x8b, "SystemMenuLeft"},
-      {0, 0x8c, "SystemMenuUp"},
-      {0, 0x8d, "SystemMenuDown"},
-      {0, 0x90, "D-PadUp"},
-      {0, 0x91, "D-PadDown"},
-      {0, 0x92, "D-PadRight"},
-      {0, 0x93, "D-PadLeft"},
-  {  2, 0, "Simulation" },
-      {0, 0xb0, "Aileron"},
-      {0, 0xb1, "AileronTrim"},
-      {0, 0xb2, "Anti-Torque"},
-      {0, 0xb3, "Autopilot"},
-      {0, 0xb4, "Chaff"},
-      {0, 0xb5, "Collective"},
-      {0, 0xb6, "DiveBrake"},
-      {0, 0xb7, "ElectronicCountermeasures"},
-      {0, 0xb8, "Elevator"},
-      {0, 0xb9, "ElevatorTrim"},
-      {0, 0xba, "Rudder"},
-      {0, 0xbb, "Throttle"},
-      {0, 0xbc, "FlightCommunications"},
-      {0, 0xbd, "FlareRelease"},
-      {0, 0xbe, "LandingGear"},
-      {0, 0xbf, "ToeBrake"},
-  {  7, 0, "Keyboard" },
-  {  8, 0, "LED" },
-      {0, 0x01, "NumLock"},
-      {0, 0x02, "CapsLock"},
-      {0, 0x03, "ScrollLock"},
-      {0, 0x04, "Compose"},
-      {0, 0x05, "Kana"},
-      {0, 0x4b, "GenericIndicator"},
-  {  9, 0, "Button" },
-  { 10, 0, "Ordinal" },
-  { 12, 0, "Consumer" },
-      {0, 0x238, "HorizontalWheel"},
-  { 13, 0, "Digitizers" },
-    {0, 0x01, "Digitizer"},
-    {0, 0x02, "Pen"},
-    {0, 0x03, "LightPen"},
-    {0, 0x04, "TouchScreen"},
-    {0, 0x05, "TouchPad"},
-    {0, 0x20, "Stylus"},
-    {0, 0x21, "Puck"},
-    {0, 0x22, "Finger"},
-    {0, 0x30, "TipPressure"},
-    {0, 0x31, "BarrelPressure"},
-    {0, 0x32, "InRange"},
-    {0, 0x33, "Touch"},
-    {0, 0x34, "UnTouch"},
-    {0, 0x35, "Tap"},
-    {0, 0x39, "TabletFunctionKey"},
-    {0, 0x3a, "ProgramChangeKey"},
-    {0, 0x3c, "Invert"},
-    {0, 0x42, "TipSwitch"},
-    {0, 0x43, "SecondaryTipSwitch"},
-    {0, 0x44, "BarrelSwitch"},
-    {0, 0x45, "Eraser"},
-    {0, 0x46, "TabletPick"},
-  { 15, 0, "PhysicalInterfaceDevice" },
-    {0, 0x00, "Undefined"},
-    {0, 0x01, "Physical_Interface_Device"},
-      {0, 0x20, "Normal"},
-    {0, 0x21, "Set_Effect_Report"},
-      {0, 0x22, "Effect_Block_Index"},
-      {0, 0x23, "Parameter_Block_Offset"},
-      {0, 0x24, "ROM_Flag"},
-      {0, 0x25, "Effect_Type"},
-        {0, 0x26, "ET_Constant_Force"},
-        {0, 0x27, "ET_Ramp"},
-        {0, 0x28, "ET_Custom_Force_Data"},
-        {0, 0x30, "ET_Square"},
-        {0, 0x31, "ET_Sine"},
-        {0, 0x32, "ET_Triangle"},
-        {0, 0x33, "ET_Sawtooth_Up"},
-        {0, 0x34, "ET_Sawtooth_Down"},
-        {0, 0x40, "ET_Spring"},
-        {0, 0x41, "ET_Damper"},
-        {0, 0x42, "ET_Inertia"},
-        {0, 0x43, "ET_Friction"},
-      {0, 0x50, "Duration"},
-      {0, 0x51, "Sample_Period"},
-      {0, 0x52, "Gain"},
-      {0, 0x53, "Trigger_Button"},
-      {0, 0x54, "Trigger_Repeat_Interval"},
-      {0, 0x55, "Axes_Enable"},
-        {0, 0x56, "Direction_Enable"},
-      {0, 0x57, "Direction"},
-      {0, 0x58, "Type_Specific_Block_Offset"},
-        {0, 0x59, "Block_Type"},
-        {0, 0x5A, "Set_Envelope_Report"},
-          {0, 0x5B, "Attack_Level"},
-          {0, 0x5C, "Attack_Time"},
-          {0, 0x5D, "Fade_Level"},
-          {0, 0x5E, "Fade_Time"},
-        {0, 0x5F, "Set_Condition_Report"},
-        {0, 0x60, "CP_Offset"},
-        {0, 0x61, "Positive_Coefficient"},
-        {0, 0x62, "Negative_Coefficient"},
-        {0, 0x63, "Positive_Saturation"},
-        {0, 0x64, "Negative_Saturation"},
-        {0, 0x65, "Dead_Band"},
-      {0, 0x66, "Download_Force_Sample"},
-      {0, 0x67, "Isoch_Custom_Force_Enable"},
-      {0, 0x68, "Custom_Force_Data_Report"},
-        {0, 0x69, "Custom_Force_Data"},
-        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
-      {0, 0x6B, "Set_Custom_Force_Report"},
-        {0, 0x6C, "Custom_Force_Data_Offset"},
-        {0, 0x6D, "Sample_Count"},
-      {0, 0x6E, "Set_Periodic_Report"},
-        {0, 0x6F, "Offset"},
-        {0, 0x70, "Magnitude"},
-        {0, 0x71, "Phase"},
-        {0, 0x72, "Period"},
-      {0, 0x73, "Set_Constant_Force_Report"},
-        {0, 0x74, "Set_Ramp_Force_Report"},
-        {0, 0x75, "Ramp_Start"},
-        {0, 0x76, "Ramp_End"},
-      {0, 0x77, "Effect_Operation_Report"},
-        {0, 0x78, "Effect_Operation"},
-          {0, 0x79, "Op_Effect_Start"},
-          {0, 0x7A, "Op_Effect_Start_Solo"},
-          {0, 0x7B, "Op_Effect_Stop"},
-          {0, 0x7C, "Loop_Count"},
-      {0, 0x7D, "Device_Gain_Report"},
-        {0, 0x7E, "Device_Gain"},
-    {0, 0x7F, "PID_Pool_Report"},
-      {0, 0x80, "RAM_Pool_Size"},
-      {0, 0x81, "ROM_Pool_Size"},
-      {0, 0x82, "ROM_Effect_Block_Count"},
-      {0, 0x83, "Simultaneous_Effects_Max"},
-      {0, 0x84, "Pool_Alignment"},
-    {0, 0x85, "PID_Pool_Move_Report"},
-      {0, 0x86, "Move_Source"},
-      {0, 0x87, "Move_Destination"},
-      {0, 0x88, "Move_Length"},
-    {0, 0x89, "PID_Block_Load_Report"},
-      {0, 0x8B, "Block_Load_Status"},
-      {0, 0x8C, "Block_Load_Success"},
-      {0, 0x8D, "Block_Load_Full"},
-      {0, 0x8E, "Block_Load_Error"},
-      {0, 0x8F, "Block_Handle"},
-      {0, 0x90, "PID_Block_Free_Report"},
-      {0, 0x91, "Type_Specific_Block_Handle"},
-    {0, 0x92, "PID_State_Report"},
-      {0, 0x94, "Effect_Playing"},
-      {0, 0x95, "PID_Device_Control_Report"},
-        {0, 0x96, "PID_Device_Control"},
-        {0, 0x97, "DC_Enable_Actuators"},
-        {0, 0x98, "DC_Disable_Actuators"},
-        {0, 0x99, "DC_Stop_All_Effects"},
-        {0, 0x9A, "DC_Device_Reset"},
-        {0, 0x9B, "DC_Device_Pause"},
-        {0, 0x9C, "DC_Device_Continue"},
-      {0, 0x9F, "Device_Paused"},
-      {0, 0xA0, "Actuators_Enabled"},
-      {0, 0xA4, "Safety_Switch"},
-      {0, 0xA5, "Actuator_Override_Switch"},
-      {0, 0xA6, "Actuator_Power"},
-    {0, 0xA7, "Start_Delay"},
-    {0, 0xA8, "Parameter_Block_Size"},
-    {0, 0xA9, "Device_Managed_Pool"},
-    {0, 0xAA, "Shared_Parameter_Blocks"},
-    {0, 0xAB, "Create_New_Effect_Report"},
-    {0, 0xAC, "RAM_Pool_Available"},
-  { 0x84, 0, "Power Device" },
-    { 0x84, 0x02, "PresentStatus" },
-    { 0x84, 0x03, "ChangeStatus" },
-    { 0x84, 0x04, "UPS" },
-    { 0x84, 0x05, "PowerSupply" },
-    { 0x84, 0x10, "BatterySystem" },
-    { 0x84, 0x11, "BatterySystemID" },
-    { 0x84, 0x12, "Battery" },
-    { 0x84, 0x13, "BatteryID" },
-    { 0x84, 0x14, "Charger" },
-    { 0x84, 0x15, "ChargerID" },
-    { 0x84, 0x16, "PowerConverter" },
-    { 0x84, 0x17, "PowerConverterID" },
-    { 0x84, 0x18, "OutletSystem" },
-    { 0x84, 0x19, "OutletSystemID" },
-    { 0x84, 0x1a, "Input" },
-    { 0x84, 0x1b, "InputID" },
-    { 0x84, 0x1c, "Output" },
-    { 0x84, 0x1d, "OutputID" },
-    { 0x84, 0x1e, "Flow" },
-    { 0x84, 0x1f, "FlowID" },
-    { 0x84, 0x20, "Outlet" },
-    { 0x84, 0x21, "OutletID" },
-    { 0x84, 0x22, "Gang" },
-    { 0x84, 0x24, "PowerSummary" },
-    { 0x84, 0x25, "PowerSummaryID" },
-    { 0x84, 0x30, "Voltage" },
-    { 0x84, 0x31, "Current" },
-    { 0x84, 0x32, "Frequency" },
-    { 0x84, 0x33, "ApparentPower" },
-    { 0x84, 0x35, "PercentLoad" },
-    { 0x84, 0x40, "ConfigVoltage" },
-    { 0x84, 0x41, "ConfigCurrent" },
-    { 0x84, 0x43, "ConfigApparentPower" },
-    { 0x84, 0x53, "LowVoltageTransfer" },
-    { 0x84, 0x54, "HighVoltageTransfer" },
-    { 0x84, 0x56, "DelayBeforeStartup" },
-    { 0x84, 0x57, "DelayBeforeShutdown" },
-    { 0x84, 0x58, "Test" },
-    { 0x84, 0x5a, "AudibleAlarmControl" },
-    { 0x84, 0x60, "Present" },
-    { 0x84, 0x61, "Good" },
-    { 0x84, 0x62, "InternalFailure" },
-    { 0x84, 0x65, "Overload" },
-    { 0x84, 0x66, "OverCharged" },
-    { 0x84, 0x67, "OverTemperature" },
-    { 0x84, 0x68, "ShutdownRequested" },
-    { 0x84, 0x69, "ShutdownImminent" },
-    { 0x84, 0x6b, "SwitchOn/Off" },
-    { 0x84, 0x6c, "Switchable" },
-    { 0x84, 0x6d, "Used" },
-    { 0x84, 0x6e, "Boost" },
-    { 0x84, 0x73, "CommunicationLost" },
-    { 0x84, 0xfd, "iManufacturer" },
-    { 0x84, 0xfe, "iProduct" },
-    { 0x84, 0xff, "iSerialNumber" },
-  { 0x85, 0, "Battery System" },
-    { 0x85, 0x01, "SMBBatteryMode" },
-    { 0x85, 0x02, "SMBBatteryStatus" },
-    { 0x85, 0x03, "SMBAlarmWarning" },
-    { 0x85, 0x04, "SMBChargerMode" },
-    { 0x85, 0x05, "SMBChargerStatus" },
-    { 0x85, 0x06, "SMBChargerSpecInfo" },
-    { 0x85, 0x07, "SMBSelectorState" },
-    { 0x85, 0x08, "SMBSelectorPresets" },
-    { 0x85, 0x09, "SMBSelectorInfo" },
-    { 0x85, 0x29, "RemainingCapacityLimit" },
-    { 0x85, 0x2c, "CapacityMode" },
-    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
-    { 0x85, 0x44, "Charging" },
-    { 0x85, 0x45, "Discharging" },
-    { 0x85, 0x4b, "NeedReplacement" },
-    { 0x85, 0x66, "RemainingCapacity" },
-    { 0x85, 0x68, "RunTimeToEmpty" },
-    { 0x85, 0x6a, "AverageTimeToFull" },
-    { 0x85, 0x83, "DesignCapacity" },
-    { 0x85, 0x85, "ManufacturerDate" },
-    { 0x85, 0x89, "iDeviceChemistry" },
-    { 0x85, 0x8b, "Rechargable" },
-    { 0x85, 0x8f, "iOEMInformation" },
-    { 0x85, 0x8d, "CapacityGranularity1" },
-    { 0x85, 0xd0, "ACPresent" },
-  /* pages 0xff00 to 0xffff are vendor-specific */
-  { 0xffff, 0, "Vendor-specific-FF" },
-  { 0, 0, NULL }
-};
-
-static void resolv_usage_page(unsigned page) {
-       const struct hid_usage_entry *p;
-
-       for (p = hid_usage_table; p->description; p++)
-               if (p->page == page) {
-                       printk("%s", p->description);
-                       return;
-               }
-       printk("%04x", page);
-}
-
-static void resolv_usage(unsigned usage) {
-       const struct hid_usage_entry *p;
-
-       resolv_usage_page(usage >> 16);
-       printk(".");
-       for (p = hid_usage_table; p->description; p++)
-               if (p->page == (usage >> 16)) {
-                       for(++p; p->description && p->usage != 0; p++)
-                               if (p->usage == (usage & 0xffff)) {
-                                       printk("%s", p->description);
-                                       return;
-                               }
-                       break;
-               }
-       printk("%04x", usage & 0xffff);
-}
-
-__inline__ static void tab(int n) {
-       while (n--) printk(" ");
-}
-
-static void hid_dump_field(struct hid_field *field, int n) {
-       int j;
-
-       if (field->physical) {
-               tab(n);
-               printk("Physical(");
-               resolv_usage(field->physical); printk(")\n");
-       }
-       if (field->logical) {
-               tab(n);
-               printk("Logical(");
-               resolv_usage(field->logical); printk(")\n");
-       }
-       tab(n); printk("Usage(%d)\n", field->maxusage);
-       for (j = 0; j < field->maxusage; j++) {
-               tab(n+2);resolv_usage(field->usage[j].hid); printk("\n");
-       }
-       if (field->logical_minimum != field->logical_maximum) {
-               tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
-               tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
-       }
-       if (field->physical_minimum != field->physical_maximum) {
-               tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
-               tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
-       }
-       if (field->unit_exponent) {
-               tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
-       }
-       if (field->unit) {
-               char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
-               char *units[5][8] = {
-                       { "None", "None", "None", "None", "None", "None", "None", "None" },
-                       { "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
-                       { "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
-                       { "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
-                       { "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
-               };
-
-               int i;
-               int sys;
-                __u32 data = field->unit;
-
-               /* First nibble tells us which system we're in. */
-               sys = data & 0xf;
-               data >>= 4;
-
-               if(sys > 4) {
-                       tab(n); printk("Unit(Invalid)\n");
-               }
-               else {
-                       int earlier_unit = 0;
-
-                       tab(n); printk("Unit(%s : ", systems[sys]);
-
-                       for (i=1 ; i<sizeof(__u32)*2 ; i++) {
-                               char nibble = data & 0xf;
-                               data >>= 4;
-                               if (nibble != 0) {
-                                       if(earlier_unit++ > 0)
-                                               printk("*");
-                                       printk("%s", units[sys][i]);
-                                       if(nibble != 1) {
-                                               /* This is a _signed_ nibble(!) */
-
-                                               int val = nibble & 0x7;
-                                               if(nibble & 0x08)
-                                                       val = -((0x7 & ~val) +1);
-                                               printk("^%d", val);
-                                       }
-                               }
-                       }
-                       printk(")\n");
-               }
-       }
-       tab(n); printk("Report Size(%u)\n", field->report_size);
-       tab(n); printk("Report Count(%u)\n", field->report_count);
-       tab(n); printk("Report Offset(%u)\n", field->report_offset);
-
-       tab(n); printk("Flags( ");
-       j = field->flags;
-       printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
-       printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
-       printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
-       printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
-       printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
-       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
-       printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
-       printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
-       printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
-       printk(")\n");
-}
-
-static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
-       struct hid_report_enum *report_enum;
-       struct hid_report *report;
-       struct list_head *list;
-       unsigned i,k;
-       static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
-
-       for (i = 0; i < HID_REPORT_TYPES; i++) {
-               report_enum = device->report_enum + i;
-               list = report_enum->report_list.next;
-               while (list != &report_enum->report_list) {
-                       report = (struct hid_report *) list;
-                       tab(2);
-                       printk("%s", table[i]);
-                       if (report->id)
-                               printk("(%d)", report->id);
-                       printk("[%s]", table[report->type]);
-                       printk("\n");
-                       for (k = 0; k < report->maxfield; k++) {
-                               tab(4);
-                               printk("Field(%d)\n", k);
-                               hid_dump_field(report->field[k], 6);
-                       }
-                       list = list->next;
-               }
-       }
-}
-
-static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) {
-       printk("hid-debug: input ");
-       resolv_usage(usage->hid);
-       printk(" = %d\n", value);
-}
-
-
-static char *events[EV_MAX + 1] = {
-       [EV_SYN] = "Sync",                      [EV_KEY] = "Key",
-       [EV_REL] = "Relative",                  [EV_ABS] = "Absolute",
-       [EV_MSC] = "Misc",                      [EV_LED] = "LED",
-       [EV_SND] = "Sound",                     [EV_REP] = "Repeat",
-       [EV_FF] = "ForceFeedback",              [EV_PWR] = "Power",
-       [EV_FF_STATUS] = "ForceFeedbackStatus",
-};
-
-static char *syncs[2] = {
-       [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
-};
-static char *keys[KEY_MAX + 1] = {
-       [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
-       [KEY_1] = "1",                          [KEY_2] = "2",
-       [KEY_3] = "3",                          [KEY_4] = "4",
-       [KEY_5] = "5",                          [KEY_6] = "6",
-       [KEY_7] = "7",                          [KEY_8] = "8",
-       [KEY_9] = "9",                          [KEY_0] = "0",
-       [KEY_MINUS] = "Minus",                  [KEY_EQUAL] = "Equal",
-       [KEY_BACKSPACE] = "Backspace",          [KEY_TAB] = "Tab",
-       [KEY_Q] = "Q",                          [KEY_W] = "W",
-       [KEY_E] = "E",                          [KEY_R] = "R",
-       [KEY_T] = "T",                          [KEY_Y] = "Y",
-       [KEY_U] = "U",                          [KEY_I] = "I",
-       [KEY_O] = "O",                          [KEY_P] = "P",
-       [KEY_LEFTBRACE] = "LeftBrace",          [KEY_RIGHTBRACE] = "RightBrace",
-       [KEY_ENTER] = "Enter",                  [KEY_LEFTCTRL] = "LeftControl",
-       [KEY_A] = "A",                          [KEY_S] = "S",
-       [KEY_D] = "D",                          [KEY_F] = "F",
-       [KEY_G] = "G",                          [KEY_H] = "H",
-       [KEY_J] = "J",                          [KEY_K] = "K",
-       [KEY_L] = "L",                          [KEY_SEMICOLON] = "Semicolon",
-       [KEY_APOSTROPHE] = "Apostrophe",        [KEY_GRAVE] = "Grave",
-       [KEY_LEFTSHIFT] = "LeftShift",          [KEY_BACKSLASH] = "BackSlash",
-       [KEY_Z] = "Z",                          [KEY_X] = "X",
-       [KEY_C] = "C",                          [KEY_V] = "V",
-       [KEY_B] = "B",                          [KEY_N] = "N",
-       [KEY_M] = "M",                          [KEY_COMMA] = "Comma",
-       [KEY_DOT] = "Dot",                      [KEY_SLASH] = "Slash",
-       [KEY_RIGHTSHIFT] = "RightShift",        [KEY_KPASTERISK] = "KPAsterisk",
-       [KEY_LEFTALT] = "LeftAlt",              [KEY_SPACE] = "Space",
-       [KEY_CAPSLOCK] = "CapsLock",            [KEY_F1] = "F1",
-       [KEY_F2] = "F2",                        [KEY_F3] = "F3",
-       [KEY_F4] = "F4",                        [KEY_F5] = "F5",
-       [KEY_F6] = "F6",                        [KEY_F7] = "F7",
-       [KEY_F8] = "F8",                        [KEY_F9] = "F9",
-       [KEY_F10] = "F10",                      [KEY_NUMLOCK] = "NumLock",
-       [KEY_SCROLLLOCK] = "ScrollLock",        [KEY_KP7] = "KP7",
-       [KEY_KP8] = "KP8",                      [KEY_KP9] = "KP9",
-       [KEY_KPMINUS] = "KPMinus",              [KEY_KP4] = "KP4",
-       [KEY_KP5] = "KP5",                      [KEY_KP6] = "KP6",
-       [KEY_KPPLUS] = "KPPlus",                [KEY_KP1] = "KP1",
-       [KEY_KP2] = "KP2",                      [KEY_KP3] = "KP3",
-       [KEY_KP0] = "KP0",                      [KEY_KPDOT] = "KPDot",
-       [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
-       [KEY_F11] = "F11",                      [KEY_F12] = "F12",
-       [KEY_RO] = "RO",                        [KEY_KATAKANA] = "Katakana",
-       [KEY_HIRAGANA] = "HIRAGANA",            [KEY_HENKAN] = "Henkan",
-       [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
-       [KEY_KPJPCOMMA] = "KPJpComma",          [KEY_KPENTER] = "KPEnter",
-       [KEY_RIGHTCTRL] = "RightCtrl",          [KEY_KPSLASH] = "KPSlash",
-       [KEY_SYSRQ] = "SysRq",                  [KEY_RIGHTALT] = "RightAlt",
-       [KEY_LINEFEED] = "LineFeed",            [KEY_HOME] = "Home",
-       [KEY_UP] = "Up",                        [KEY_PAGEUP] = "PageUp",
-       [KEY_LEFT] = "Left",                    [KEY_RIGHT] = "Right",
-       [KEY_END] = "End",                      [KEY_DOWN] = "Down",
-       [KEY_PAGEDOWN] = "PageDown",            [KEY_INSERT] = "Insert",
-       [KEY_DELETE] = "Delete",                [KEY_MACRO] = "Macro",
-       [KEY_MUTE] = "Mute",                    [KEY_VOLUMEDOWN] = "VolumeDown",
-       [KEY_VOLUMEUP] = "VolumeUp",            [KEY_POWER] = "Power",
-       [KEY_KPEQUAL] = "KPEqual",              [KEY_KPPLUSMINUS] = "KPPlusMinus",
-       [KEY_PAUSE] = "Pause",                  [KEY_KPCOMMA] = "KPComma",
-       [KEY_HANGUEL] = "Hangeul",              [KEY_HANJA] = "Hanja",
-       [KEY_YEN] = "Yen",                      [KEY_LEFTMETA] = "LeftMeta",
-       [KEY_RIGHTMETA] = "RightMeta",          [KEY_COMPOSE] = "Compose",
-       [KEY_STOP] = "Stop",                    [KEY_AGAIN] = "Again",
-       [KEY_PROPS] = "Props",                  [KEY_UNDO] = "Undo",
-       [KEY_FRONT] = "Front",                  [KEY_COPY] = "Copy",
-       [KEY_OPEN] = "Open",                    [KEY_PASTE] = "Paste",
-       [KEY_FIND] = "Find",                    [KEY_CUT] = "Cut",
-       [KEY_HELP] = "Help",                    [KEY_MENU] = "Menu",
-       [KEY_CALC] = "Calc",                    [KEY_SETUP] = "Setup",
-       [KEY_SLEEP] = "Sleep",                  [KEY_WAKEUP] = "WakeUp",
-       [KEY_FILE] = "File",                    [KEY_SENDFILE] = "SendFile",
-       [KEY_DELETEFILE] = "DeleteFile",        [KEY_XFER] = "X-fer",
-       [KEY_PROG1] = "Prog1",                  [KEY_PROG2] = "Prog2",
-       [KEY_WWW] = "WWW",                      [KEY_MSDOS] = "MSDOS",
-       [KEY_COFFEE] = "Coffee",                [KEY_DIRECTION] = "Direction",
-       [KEY_CYCLEWINDOWS] = "CycleWindows",    [KEY_MAIL] = "Mail",
-       [KEY_BOOKMARKS] = "Bookmarks",          [KEY_COMPUTER] = "Computer",
-       [KEY_BACK] = "Back",                    [KEY_FORWARD] = "Forward",
-       [KEY_CLOSECD] = "CloseCD",              [KEY_EJECTCD] = "EjectCD",
-       [KEY_EJECTCLOSECD] = "EjectCloseCD",    [KEY_NEXTSONG] = "NextSong",
-       [KEY_PLAYPAUSE] = "PlayPause",          [KEY_PREVIOUSSONG] = "PreviousSong",
-       [KEY_STOPCD] = "StopCD",                [KEY_RECORD] = "Record",
-       [KEY_REWIND] = "Rewind",                [KEY_PHONE] = "Phone",
-       [KEY_ISO] = "ISOKey",                   [KEY_CONFIG] = "Config",
-       [KEY_HOMEPAGE] = "HomePage",            [KEY_REFRESH] = "Refresh",
-       [KEY_EXIT] = "Exit",                    [KEY_MOVE] = "Move",
-       [KEY_EDIT] = "Edit",                    [KEY_SCROLLUP] = "ScrollUp",
-       [KEY_SCROLLDOWN] = "ScrollDown",        [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
-       [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
-       [KEY_REDO] = "Redo",                    [KEY_F13] = "F13",
-       [KEY_F14] = "F14",                      [KEY_F15] = "F15",
-       [KEY_F16] = "F16",                      [KEY_F17] = "F17",
-       [KEY_F18] = "F18",                      [KEY_F19] = "F19",
-       [KEY_F20] = "F20",                      [KEY_F21] = "F21",
-       [KEY_F22] = "F22",                      [KEY_F23] = "F23",
-       [KEY_F24] = "F24",                      [KEY_PLAYCD] = "PlayCD",
-       [KEY_PAUSECD] = "PauseCD",              [KEY_PROG3] = "Prog3",
-       [KEY_PROG4] = "Prog4",                  [KEY_SUSPEND] = "Suspend",
-       [KEY_CLOSE] = "Close",                  [KEY_PLAY] = "Play",
-       [KEY_FASTFORWARD] = "FastForward",      [KEY_BASSBOOST] = "BassBoost",
-       [KEY_PRINT] = "Print",                  [KEY_HP] = "HP",
-       [KEY_CAMERA] = "Camera",                [KEY_SOUND] = "Sound",
-       [KEY_QUESTION] = "Question",            [KEY_EMAIL] = "Email",
-       [KEY_CHAT] = "Chat",                    [KEY_SEARCH] = "Search",
-       [KEY_CONNECT] = "Connect",              [KEY_FINANCE] = "Finance",
-       [KEY_SPORT] = "Sport",                  [KEY_SHOP] = "Shop",
-       [KEY_ALTERASE] = "AlternateErase",      [KEY_CANCEL] = "Cancel",
-       [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
-       [KEY_MEDIA] = "Media",                  [KEY_UNKNOWN] = "Unknown",
-       [BTN_0] = "Btn0",                       [BTN_1] = "Btn1",
-       [BTN_2] = "Btn2",                       [BTN_3] = "Btn3",
-       [BTN_4] = "Btn4",                       [BTN_5] = "Btn5",
-       [BTN_6] = "Btn6",                       [BTN_7] = "Btn7",
-       [BTN_8] = "Btn8",                       [BTN_9] = "Btn9",
-       [BTN_LEFT] = "LeftBtn",                 [BTN_RIGHT] = "RightBtn",
-       [BTN_MIDDLE] = "MiddleBtn",             [BTN_SIDE] = "SideBtn",
-       [BTN_EXTRA] = "ExtraBtn",               [BTN_FORWARD] = "ForwardBtn",
-       [BTN_BACK] = "BackBtn",                 [BTN_TASK] = "TaskBtn",
-       [BTN_TRIGGER] = "Trigger",              [BTN_THUMB] = "ThumbBtn",
-       [BTN_THUMB2] = "ThumbBtn2",             [BTN_TOP] = "TopBtn",
-       [BTN_TOP2] = "TopBtn2",                 [BTN_PINKIE] = "PinkieBtn",
-       [BTN_BASE] = "BaseBtn",                 [BTN_BASE2] = "BaseBtn2",
-       [BTN_BASE3] = "BaseBtn3",               [BTN_BASE4] = "BaseBtn4",
-       [BTN_BASE5] = "BaseBtn5",               [BTN_BASE6] = "BaseBtn6",
-       [BTN_DEAD] = "BtnDead",                 [BTN_A] = "BtnA",
-       [BTN_B] = "BtnB",                       [BTN_C] = "BtnC",
-       [BTN_X] = "BtnX",                       [BTN_Y] = "BtnY",
-       [BTN_Z] = "BtnZ",                       [BTN_TL] = "BtnTL",
-       [BTN_TR] = "BtnTR",                     [BTN_TL2] = "BtnTL2",
-       [BTN_TR2] = "BtnTR2",                   [BTN_SELECT] = "BtnSelect",
-       [BTN_START] = "BtnStart",               [BTN_MODE] = "BtnMode",
-       [BTN_THUMBL] = "BtnThumbL",             [BTN_THUMBR] = "BtnThumbR",
-       [BTN_TOOL_PEN] = "ToolPen",             [BTN_TOOL_RUBBER] = "ToolRubber",
-       [BTN_TOOL_BRUSH] = "ToolBrush",         [BTN_TOOL_PENCIL] = "ToolPencil",
-       [BTN_TOOL_AIRBRUSH] = "ToolAirbrush",   [BTN_TOOL_FINGER] = "ToolFinger",
-       [BTN_TOOL_MOUSE] = "ToolMouse",         [BTN_TOOL_LENS] = "ToolLens",
-       [BTN_TOUCH] = "Touch",                  [BTN_STYLUS] = "Stylus",
-       [BTN_STYLUS2] = "Stylus2",              [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
-       [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
-       [BTN_GEAR_UP] = "Gear up",              [KEY_OK] = "Ok",
-       [KEY_SELECT] = "Select",                [KEY_GOTO] = "Goto",
-       [KEY_CLEAR] = "Clear",                  [KEY_POWER2] = "Power2",
-       [KEY_OPTION] = "Option",                [KEY_INFO] = "Info",
-       [KEY_TIME] = "Time",                    [KEY_VENDOR] = "Vendor",
-       [KEY_ARCHIVE] = "Archive",              [KEY_PROGRAM] = "Program",
-       [KEY_CHANNEL] = "Channel",              [KEY_FAVORITES] = "Favorites",
-       [KEY_EPG] = "EPG",                      [KEY_PVR] = "PVR",
-       [KEY_MHP] = "MHP",                      [KEY_LANGUAGE] = "Language",
-       [KEY_TITLE] = "Title",                  [KEY_SUBTITLE] = "Subtitle",
-       [KEY_ANGLE] = "Angle",                  [KEY_ZOOM] = "Zoom",
-       [KEY_MODE] = "Mode",                    [KEY_KEYBOARD] = "Keyboard",
-       [KEY_SCREEN] = "Screen",                [KEY_PC] = "PC",
-       [KEY_TV] = "TV",                        [KEY_TV2] = "TV2",
-       [KEY_VCR] = "VCR",                      [KEY_VCR2] = "VCR2",
-       [KEY_SAT] = "Sat",                      [KEY_SAT2] = "Sat2",
-       [KEY_CD] = "CD",                        [KEY_TAPE] = "Tape",
-       [KEY_RADIO] = "Radio",                  [KEY_TUNER] = "Tuner",
-       [KEY_PLAYER] = "Player",                [KEY_TEXT] = "Text",
-       [KEY_DVD] = "DVD",                      [KEY_AUX] = "Aux",
-       [KEY_MP3] = "MP3",                      [KEY_AUDIO] = "Audio",
-       [KEY_VIDEO] = "Video",                  [KEY_DIRECTORY] = "Directory",
-       [KEY_LIST] = "List",                    [KEY_MEMO] = "Memo",
-       [KEY_CALENDAR] = "Calendar",            [KEY_RED] = "Red",
-       [KEY_GREEN] = "Green",                  [KEY_YELLOW] = "Yellow",
-       [KEY_BLUE] = "Blue",                    [KEY_CHANNELUP] = "ChannelUp",
-       [KEY_CHANNELDOWN] = "ChannelDown",      [KEY_FIRST] = "First",
-       [KEY_LAST] = "Last",                    [KEY_AB] = "AB",
-       [KEY_NEXT] = "Next",                    [KEY_RESTART] = "Restart",
-       [KEY_SLOW] = "Slow",                    [KEY_SHUFFLE] = "Shuffle",
-       [KEY_BREAK] = "Break",                  [KEY_PREVIOUS] = "Previous",
-       [KEY_DIGITS] = "Digits",                [KEY_TEEN] = "TEEN",
-       [KEY_TWEN] = "TWEN",                    [KEY_DEL_EOL] = "DeleteEOL",
-       [KEY_DEL_EOS] = "DeleteEOS",            [KEY_INS_LINE] = "InsertLine",
-       [KEY_DEL_LINE] = "DeleteLine",
-       [KEY_SEND] = "Send",                    [KEY_REPLY] = "Reply",
-       [KEY_FORWARDMAIL] = "ForwardMail",      [KEY_SAVE] = "Save",
-       [KEY_DOCUMENTS] = "Documents",
-       [KEY_FN] = "Fn",                        [KEY_FN_ESC] = "Fn+ESC",
-       [KEY_FN_1] = "Fn+1",                    [KEY_FN_2] = "Fn+2",
-       [KEY_FN_B] = "Fn+B",                    [KEY_FN_D] = "Fn+D",
-       [KEY_FN_E] = "Fn+E",                    [KEY_FN_F] = "Fn+F",
-       [KEY_FN_S] = "Fn+S",
-       [KEY_FN_F1] = "Fn+F1",                  [KEY_FN_F2] = "Fn+F2",
-       [KEY_FN_F3] = "Fn+F3",                  [KEY_FN_F4] = "Fn+F4",
-       [KEY_FN_F5] = "Fn+F5",                  [KEY_FN_F6] = "Fn+F6",
-       [KEY_FN_F7] = "Fn+F7",                  [KEY_FN_F8] = "Fn+F8",
-       [KEY_FN_F9] = "Fn+F9",                  [KEY_FN_F10] = "Fn+F10",
-       [KEY_FN_F11] = "Fn+F11",                [KEY_FN_F12] = "Fn+F12",
-       [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
-       [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
-       [KEY_KBDILLUMUP] = "KbdIlluminationUp",
-       [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
-};
-
-static char *relatives[REL_MAX + 1] = {
-       [REL_X] = "X",                  [REL_Y] = "Y",
-       [REL_Z] = "Z",                  [REL_HWHEEL] = "HWheel",
-       [REL_DIAL] = "Dial",            [REL_WHEEL] = "Wheel",
-       [REL_MISC] = "Misc",
-};
-
-static char *absolutes[ABS_MAX + 1] = {
-       [ABS_X] = "X",                  [ABS_Y] = "Y",
-       [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
-       [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
-       [ABS_THROTTLE] = "Throttle",    [ABS_RUDDER] = "Rudder",
-       [ABS_WHEEL] = "Wheel",          [ABS_GAS] = "Gas",
-       [ABS_BRAKE] = "Brake",          [ABS_HAT0X] = "Hat0X",
-       [ABS_HAT0Y] = "Hat0Y",          [ABS_HAT1X] = "Hat1X",
-       [ABS_HAT1Y] = "Hat1Y",          [ABS_HAT2X] = "Hat2X",
-       [ABS_HAT2Y] = "Hat2Y",          [ABS_HAT3X] = "Hat3X",
-       [ABS_HAT3Y] = "Hat 3Y",         [ABS_PRESSURE] = "Pressure",
-       [ABS_DISTANCE] = "Distance",    [ABS_TILT_X] = "XTilt",
-       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "Tool Width",
-       [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
-};
-
-static char *misc[MSC_MAX + 1] = {
-       [MSC_SERIAL] = "Serial",        [MSC_PULSELED] = "Pulseled",
-       [MSC_GESTURE] = "Gesture",      [MSC_RAW] = "RawData"
-};
-
-static char *leds[LED_MAX + 1] = {
-       [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
-       [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
-       [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
-       [LED_SUSPEND] = "Suspend",      [LED_MUTE] = "Mute",
-       [LED_MISC] = "Misc",
-};
-
-static char *repeats[REP_MAX + 1] = {
-       [REP_DELAY] = "Delay",          [REP_PERIOD] = "Period"
-};
-
-static char *sounds[SND_MAX + 1] = {
-       [SND_CLICK] = "Click",          [SND_BELL] = "Bell",
-       [SND_TONE] = "Tone"
-};
-
-static char **names[EV_MAX + 1] = {
-       [EV_SYN] = syncs,                       [EV_KEY] = keys,
-       [EV_REL] = relatives,                   [EV_ABS] = absolutes,
-       [EV_MSC] = misc,                        [EV_LED] = leds,
-       [EV_SND] = sounds,                      [EV_REP] = repeats,
-};
-
-static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
-
-       printk("%s.%s", events[type] ? events[type] : "?",
-               names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
-}
index a8fc46c721c50cf0a1a8485d50da96c800b3f5fe..4187f4ee9a9c761cc66fb8066d279c2841458edc 100644 (file)
@@ -32,7 +32,7 @@
 #undef DEBUG
 #include <linux/usb.h>
 
-#include "hid.h"
+#include <linux/hid.h>
 
 /*
  * This table contains pointers to initializers. To add support for new
index 3a7e5fbff025f20a6cbad8a1594476bebb24d7c4..8756eb3263de6c1e3bf6d811782fd94f2a5b6bdf 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  USB HID to Linux Input mapping
+ *
  */
 
 /*
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/usb/input.h>
-
-#undef DEBUG
-
-#include "hid.h"
-
-#define unk    KEY_UNKNOWN
-
-static const unsigned char hid_keyboard[256] = {
-         0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
-        50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
-         4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
-        27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
-        65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
-       105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
-        72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
-       191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
-       115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
-       122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-        29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
-       150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
-};
-
-static const struct {
-       __s32 x;
-       __s32 y;
-}  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-#define map_abs(c)     do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
-#define map_rel(c)     do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
-#define map_key(c)     do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
-#define map_led(c)     do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
-
-#define map_abs_clear(c)       do { map_abs(c); clear_bit(c, bit); } while (0)
-#define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
-
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-
-struct hidinput_key_translation {
-       u16 from;
-       u16 to;
-       u8 flags;
-};
-
-#define POWERBOOK_FLAG_FKEY 0x01
-
-static struct hidinput_key_translation powerbook_fn_keys[] = {
-       { KEY_BACKSPACE, KEY_DELETE },
-       { KEY_F1,       KEY_BRIGHTNESSDOWN,     POWERBOOK_FLAG_FKEY },
-       { KEY_F2,       KEY_BRIGHTNESSUP,       POWERBOOK_FLAG_FKEY },
-       { KEY_F3,       KEY_MUTE,               POWERBOOK_FLAG_FKEY },
-       { KEY_F4,       KEY_VOLUMEDOWN,         POWERBOOK_FLAG_FKEY },
-       { KEY_F5,       KEY_VOLUMEUP,           POWERBOOK_FLAG_FKEY },
-       { KEY_F6,       KEY_NUMLOCK,            POWERBOOK_FLAG_FKEY },
-       { KEY_F7,       KEY_SWITCHVIDEOMODE,    POWERBOOK_FLAG_FKEY },
-       { KEY_F8,       KEY_KBDILLUMTOGGLE,     POWERBOOK_FLAG_FKEY },
-       { KEY_F9,       KEY_KBDILLUMDOWN,       POWERBOOK_FLAG_FKEY },
-       { KEY_F10,      KEY_KBDILLUMUP,         POWERBOOK_FLAG_FKEY },
-       { KEY_UP,       KEY_PAGEUP },
-       { KEY_DOWN,     KEY_PAGEDOWN },
-       { KEY_LEFT,     KEY_HOME },
-       { KEY_RIGHT,    KEY_END },
-       { }
-};
-
-static struct hidinput_key_translation powerbook_numlock_keys[] = {
-       { KEY_J,        KEY_KP1 },
-       { KEY_K,        KEY_KP2 },
-       { KEY_L,        KEY_KP3 },
-       { KEY_U,        KEY_KP4 },
-       { KEY_I,        KEY_KP5 },
-       { KEY_O,        KEY_KP6 },
-       { KEY_7,        KEY_KP7 },
-       { KEY_8,        KEY_KP8 },
-       { KEY_9,        KEY_KP9 },
-       { KEY_M,        KEY_KP0 },
-       { KEY_DOT,      KEY_KPDOT },
-       { KEY_SLASH,    KEY_KPPLUS },
-       { KEY_SEMICOLON, KEY_KPMINUS },
-       { KEY_P,        KEY_KPASTERISK },
-       { KEY_MINUS,    KEY_KPEQUAL },
-       { KEY_0,        KEY_KPSLASH },
-       { KEY_F6,       KEY_NUMLOCK },
-       { KEY_KPENTER,  KEY_KPENTER },
-       { KEY_BACKSPACE, KEY_BACKSPACE },
-       { }
-};
-
-static struct hidinput_key_translation powerbook_iso_keyboard[] = {
-       { KEY_GRAVE,    KEY_102ND },
-       { KEY_102ND,    KEY_GRAVE },
-       { }
-};
-
-static int usbhid_pb_fnmode = 1;
-module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
-       "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
-
-static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
-{
-       struct hidinput_key_translation *trans;
-
-       /* Look for the translation */
-       for (trans = table; trans->from; trans++)
-               if (trans->from == from)
-                       return trans;
-
-       return NULL;
-}
-
-static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
-                            struct hid_usage *usage, __s32 value)
-{
-       struct hidinput_key_translation *trans;
-
-       if (usage->code == KEY_FN) {
-               if (value) hid->quirks |=  HID_QUIRK_POWERBOOK_FN_ON;
-               else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
-
-               input_event(input, usage->type, usage->code, value);
-
-               return 1;
-       }
-
-       if (usbhid_pb_fnmode) {
-               int do_translate;
-
-               trans = find_translation(powerbook_fn_keys, usage->code);
-               if (trans) {
-                       if (test_bit(usage->code, hid->pb_pressed_fn))
-                               do_translate = 1;
-                       else if (trans->flags & POWERBOOK_FLAG_FKEY)
-                               do_translate =
-                                       (usbhid_pb_fnmode == 2 &&  (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
-                                       (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
-                       else
-                               do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
-
-                       if (do_translate) {
-                               if (value)
-                                       set_bit(usage->code, hid->pb_pressed_fn);
-                               else
-                                       clear_bit(usage->code, hid->pb_pressed_fn);
-
-                               input_event(input, usage->type, trans->to, value);
-
-                               return 1;
-                       }
-               }
-
-               if (test_bit(usage->code, hid->pb_pressed_numlock) ||
-                   test_bit(LED_NUML, input->led)) {
-                       trans = find_translation(powerbook_numlock_keys, usage->code);
-
-                       if (trans) {
-                               if (value)
-                                       set_bit(usage->code, hid->pb_pressed_numlock);
-                               else
-                                       clear_bit(usage->code, hid->pb_pressed_numlock);
-
-                               input_event(input, usage->type, trans->to, value);
-                       }
-
-                       return 1;
-               }
-       }
-
-       if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
-               trans = find_translation(powerbook_iso_keyboard, usage->code);
-               if (trans) {
-                       input_event(input, usage->type, trans->to, value);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static void hidinput_pb_setup(struct input_dev *input)
-{
-       struct hidinput_key_translation *trans;
-
-       set_bit(KEY_NUMLOCK, input->keybit);
-
-       /* Enable all needed keys */
-       for (trans = powerbook_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_numlock_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_iso_keyboard; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-}
-#else
-static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
-                                   struct hid_usage *usage, __s32 value)
-{
-       return 0;
-}
-
-static inline void hidinput_pb_setup(struct input_dev *input)
-{
-}
-#endif
-
-static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
-                                    struct hid_usage *usage)
-{
-       struct input_dev *input = hidinput->input;
-       struct hid_device *device = input->private;
-       int max = 0, code;
-       unsigned long *bit = NULL;
-
-       field->hidinput = hidinput;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "Mapping: ");
-       resolv_usage(usage->hid);
-       printk(" ---> ");
-#endif
-
-       if (field->flags & HID_MAIN_ITEM_CONSTANT)
-               goto ignore;
-
-       switch (usage->hid & HID_USAGE_PAGE) {
-
-               case HID_UP_UNDEFINED:
-                       goto ignore;
-
-               case HID_UP_KEYBOARD:
-
-                       set_bit(EV_REP, input->evbit);
-
-                       if ((usage->hid & HID_USAGE) < 256) {
-                               if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
-                               map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
-                       } else
-                               map_key(KEY_UNKNOWN);
-
-                       break;
-
-               case HID_UP_BUTTON:
-
-                       code = ((usage->hid - 1) & 0xf);
-
-                       switch (field->application) {
-                               case HID_GD_MOUSE:
-                               case HID_GD_POINTER:  code += 0x110; break;
-                               case HID_GD_JOYSTICK: code += 0x120; break;
-                               case HID_GD_GAMEPAD:  code += 0x130; break;
-                               default:
-                                       switch (field->physical) {
-                                               case HID_GD_MOUSE:
-                                               case HID_GD_POINTER:  code += 0x110; break;
-                                               case HID_GD_JOYSTICK: code += 0x120; break;
-                                               case HID_GD_GAMEPAD:  code += 0x130; break;
-                                               default:              code += 0x100;
-                                       }
-                       }
-
-                       map_key(code);
-                       break;
-
-
-               case HID_UP_SIMULATION:
-
-                       switch (usage->hid & 0xffff) {
-                               case 0xba: map_abs(ABS_RUDDER);   break;
-                               case 0xbb: map_abs(ABS_THROTTLE); break;
-                               case 0xc4: map_abs(ABS_GAS);      break;
-                               case 0xc5: map_abs(ABS_BRAKE);    break;
-                               case 0xc8: map_abs(ABS_WHEEL);    break;
-                               default:   goto ignore;
-                       }
-                       break;
-
-               case HID_UP_GENDESK:
-
-                       if ((usage->hid & 0xf0) == 0x80) {      /* SystemControl */
-                               switch (usage->hid & 0xf) {
-                                       case 0x1: map_key_clear(KEY_POWER);  break;
-                                       case 0x2: map_key_clear(KEY_SLEEP);  break;
-                                       case 0x3: map_key_clear(KEY_WAKEUP); break;
-                                       default: goto unknown;
-                               }
-                               break;
-                       }
-
-                       if ((usage->hid & 0xf0) == 0x90) {      /* D-pad */
-                               switch (usage->hid) {
-                                       case HID_GD_UP:    usage->hat_dir = 1; break;
-                                       case HID_GD_DOWN:  usage->hat_dir = 5; break;
-                                       case HID_GD_RIGHT: usage->hat_dir = 3; break;
-                                       case HID_GD_LEFT:  usage->hat_dir = 7; break;
-                                       default: goto unknown;
-                               }
-                               if (field->dpad) {
-                                       map_abs(field->dpad);
-                                       goto ignore;
-                               }
-                               map_abs(ABS_HAT0X);
-                               break;
-                       }
-
-                       switch (usage->hid) {
-
-                               /* These usage IDs map directly to the usage codes. */
-                               case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
-                               case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
-                               case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
-                                       if (field->flags & HID_MAIN_ITEM_RELATIVE)
-                                               map_rel(usage->hid & 0xf);
-                                       else
-                                               map_abs(usage->hid & 0xf);
-                                       break;
-
-                               case HID_GD_HATSWITCH:
-                                       usage->hat_min = field->logical_minimum;
-                                       usage->hat_max = field->logical_maximum;
-                                       map_abs(ABS_HAT0X);
-                                       break;
-
-                               case HID_GD_START:      map_key_clear(BTN_START);       break;
-                               case HID_GD_SELECT:     map_key_clear(BTN_SELECT);      break;
-
-                               default: goto unknown;
-                       }
-
-                       break;
-
-               case HID_UP_LED:
-                       if (((usage->hid - 1) & 0xffff) >= LED_MAX)
-                               goto ignore;
-                       map_led((usage->hid - 1) & 0xffff);
-                       break;
-
-               case HID_UP_DIGITIZER:
-
-                       switch (usage->hid & 0xff) {
-
-                               case 0x30: /* TipPressure */
-                                       if (!test_bit(BTN_TOUCH, input->keybit)) {
-                                               device->quirks |= HID_QUIRK_NOTOUCH;
-                                               set_bit(EV_KEY, input->evbit);
-                                               set_bit(BTN_TOUCH, input->keybit);
-                                       }
-
-                                       map_abs_clear(ABS_PRESSURE);
-                                       break;
-
-                               case 0x32: /* InRange */
-                                       switch (field->physical & 0xff) {
-                                               case 0x21: map_key(BTN_TOOL_MOUSE); break;
-                                               case 0x22: map_key(BTN_TOOL_FINGER); break;
-                                               default: map_key(BTN_TOOL_PEN); break;
-                                       }
-                                       break;
-
-                               case 0x3c: /* Invert */
-                                       map_key_clear(BTN_TOOL_RUBBER);
-                                       break;
-
-                               case 0x33: /* Touch */
-                               case 0x42: /* TipSwitch */
-                               case 0x43: /* TipSwitch2 */
-                                       device->quirks &= ~HID_QUIRK_NOTOUCH;
-                                       map_key_clear(BTN_TOUCH);
-                                       break;
-
-                               case 0x44: /* BarrelSwitch */
-                                       map_key_clear(BTN_STYLUS);
-                                       break;
-
-                               default:  goto unknown;
-                       }
-                       break;
-
-               case HID_UP_CONSUMER:   /* USB HUT v1.1, pages 56-62 */
-
-                       switch (usage->hid & HID_USAGE) {
-                               case 0x000: goto ignore;
-                               case 0x034: map_key_clear(KEY_SLEEP);           break;
-                               case 0x036: map_key_clear(BTN_MISC);            break;
-                               case 0x045: map_key_clear(KEY_RADIO);           break;
-                               case 0x08a: map_key_clear(KEY_WWW);             break;
-                               case 0x08d: map_key_clear(KEY_PROGRAM);         break;
-                               case 0x095: map_key_clear(KEY_HELP);            break;
-                               case 0x09c: map_key_clear(KEY_CHANNELUP);       break;
-                               case 0x09d: map_key_clear(KEY_CHANNELDOWN);     break;
-                               case 0x0b0: map_key_clear(KEY_PLAY);            break;
-                               case 0x0b1: map_key_clear(KEY_PAUSE);           break;
-                               case 0x0b2: map_key_clear(KEY_RECORD);          break;
-                               case 0x0b3: map_key_clear(KEY_FASTFORWARD);     break;
-                               case 0x0b4: map_key_clear(KEY_REWIND);          break;
-                               case 0x0b5: map_key_clear(KEY_NEXTSONG);        break;
-                               case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);    break;
-                               case 0x0b7: map_key_clear(KEY_STOPCD);          break;
-                               case 0x0b8: map_key_clear(KEY_EJECTCD);         break;
-                               case 0x0cd: map_key_clear(KEY_PLAYPAUSE);       break;
-                               case 0x0e0: map_abs_clear(ABS_VOLUME);          break;
-                               case 0x0e2: map_key_clear(KEY_MUTE);            break;
-                               case 0x0e5: map_key_clear(KEY_BASSBOOST);       break;
-                               case 0x0e9: map_key_clear(KEY_VOLUMEUP);        break;
-                               case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);      break;
-                               case 0x183: map_key_clear(KEY_CONFIG);          break;
-                               case 0x18a: map_key_clear(KEY_MAIL);            break;
-                               case 0x192: map_key_clear(KEY_CALC);            break;
-                               case 0x194: map_key_clear(KEY_FILE);            break;
-                               case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
-                               case 0x201: map_key_clear(KEY_NEW);             break;
-                               case 0x207: map_key_clear(KEY_SAVE);            break;
-                               case 0x208: map_key_clear(KEY_PRINT);           break;
-                               case 0x209: map_key_clear(KEY_PROPS);           break;
-                               case 0x21a: map_key_clear(KEY_UNDO);            break;
-                               case 0x21b: map_key_clear(KEY_COPY);            break;
-                               case 0x21c: map_key_clear(KEY_CUT);             break;
-                               case 0x21d: map_key_clear(KEY_PASTE);           break;
-                               case 0x221: map_key_clear(KEY_FIND);            break;
-                               case 0x223: map_key_clear(KEY_HOMEPAGE);        break;
-                               case 0x224: map_key_clear(KEY_BACK);            break;
-                               case 0x225: map_key_clear(KEY_FORWARD);         break;
-                               case 0x226: map_key_clear(KEY_STOP);            break;
-                               case 0x227: map_key_clear(KEY_REFRESH);         break;
-                               case 0x22a: map_key_clear(KEY_BOOKMARKS);       break;
-                               case 0x233: map_key_clear(KEY_SCROLLUP);        break;
-                               case 0x234: map_key_clear(KEY_SCROLLDOWN);      break;
-                               case 0x238: map_rel(REL_HWHEEL);                break;
-                               case 0x279: map_key_clear(KEY_REDO);            break;
-                               case 0x289: map_key_clear(KEY_REPLY);           break;
-                               case 0x28b: map_key_clear(KEY_FORWARDMAIL);     break;
-                               case 0x28c: map_key_clear(KEY_SEND);            break;
-
-                               /* Reported on a Cherry Cymotion keyboard */
-                               case 0x301: map_key_clear(KEY_PROG1);           break;
-                               case 0x302: map_key_clear(KEY_PROG2);           break;
-                               case 0x303: map_key_clear(KEY_PROG3);           break;
-
-                               default:    goto ignore;
-                       }
-                       break;
-
-               case HID_UP_HPVENDOR:   /* Reported on a Dutch layout HP5308 */
-
-                       set_bit(EV_REP, input->evbit);
-                       switch (usage->hid & HID_USAGE) {
-                               case 0x021: map_key_clear(KEY_PRINT);           break;
-                               case 0x070: map_key_clear(KEY_HP);              break;
-                               case 0x071: map_key_clear(KEY_CAMERA);          break;
-                               case 0x072: map_key_clear(KEY_SOUND);           break;
-                               case 0x073: map_key_clear(KEY_QUESTION);        break;
-                               case 0x080: map_key_clear(KEY_EMAIL);           break;
-                               case 0x081: map_key_clear(KEY_CHAT);            break;
-                               case 0x082: map_key_clear(KEY_SEARCH);          break;
-                               case 0x083: map_key_clear(KEY_CONNECT);         break;
-                               case 0x084: map_key_clear(KEY_FINANCE);         break;
-                               case 0x085: map_key_clear(KEY_SPORT);           break;
-                               case 0x086: map_key_clear(KEY_SHOP);            break;
-                               default:    goto ignore;
-                       }
-                       break;
-
-               case HID_UP_MSVENDOR:
-                       goto ignore;
-
-               case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
-
-                       set_bit(EV_REP, input->evbit);
-                       switch(usage->hid & HID_USAGE) {
-                               case 0x003:
-                                       /* The fn key on Apple PowerBooks */
-                                       map_key_clear(KEY_FN);
-                                       hidinput_pb_setup(input);
-                                       break;
-
-                               default:    goto ignore;
-                       }
-                       break;
-
-               case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
-
-                       set_bit(EV_REP, input->evbit);
-                       switch(usage->hid & HID_USAGE) {
-                               case 0x004: map_key_clear(KEY_AGAIN);           break;
-                               case 0x00d: map_key_clear(KEY_HOME);            break;
-                               case 0x024: map_key_clear(KEY_SHUFFLE);         break;
-                               case 0x025: map_key_clear(KEY_TV);              break;
-                               case 0x026: map_key_clear(KEY_MENU);            break;
-                               case 0x031: map_key_clear(KEY_AUDIO);           break;
-                               case 0x032: map_key_clear(KEY_TEXT);            break;
-                               case 0x033: map_key_clear(KEY_LAST);            break;
-                               case 0x047: map_key_clear(KEY_MP3);             break;
-                               case 0x048: map_key_clear(KEY_DVD);             break;
-                               case 0x049: map_key_clear(KEY_MEDIA);           break;
-                               case 0x04a: map_key_clear(KEY_VIDEO);           break;
-                               case 0x04b: map_key_clear(KEY_ANGLE);           break;
-                               case 0x04c: map_key_clear(KEY_LANGUAGE);        break;
-                               case 0x04d: map_key_clear(KEY_SUBTITLE);        break;
-                               case 0x051: map_key_clear(KEY_RED);             break;
-                               case 0x052: map_key_clear(KEY_CLOSE);           break;
-                               default:    goto ignore;
-                       }
-                       break;
-
-               case HID_UP_PID:
-
-                       switch(usage->hid & HID_USAGE) {
-                               case 0xa4: map_key_clear(BTN_DEAD);     break;
-                               default: goto ignore;
-                       }
-                       break;
-
-               default:
-               unknown:
-                       if (field->report_size == 1) {
-                               if (field->report->type == HID_OUTPUT_REPORT) {
-                                       map_led(LED_MISC);
-                                       break;
-                               }
-                               map_key(BTN_MISC);
-                               break;
-                       }
-                       if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-                               map_rel(REL_MISC);
-                               break;
-                       }
-                       map_abs(ABS_MISC);
-                       break;
-       }
-
-       if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
-               if (usage->hid == HID_GD_Z)
-                       map_rel(REL_HWHEEL);
-               else if (usage->code == BTN_1)
-                       map_key(BTN_2);
-               else if (usage->code == BTN_2)
-                       map_key(BTN_1);
-       }
-
-       if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
-                (usage->type == EV_REL) && (usage->code == REL_WHEEL))
-                       set_bit(REL_HWHEEL, bit);
-
-       if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-               || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
-               goto ignore;
-
-       if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
-           usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
-               field->flags &= ~HID_MAIN_ITEM_RELATIVE;
-
-       set_bit(usage->type, input->evbit);
-
-       while (usage->code <= max && test_and_set_bit(usage->code, bit))
-               usage->code = find_next_zero_bit(bit, max + 1, usage->code);
-
-       if (usage->code > max)
-               goto ignore;
-
-
-       if (usage->type == EV_ABS) {
-
-               int a = field->logical_minimum;
-               int b = field->logical_maximum;
-
-               if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
-                       a = field->logical_minimum = 0;
-                       b = field->logical_maximum = 255;
-               }
-
-               if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
-                       input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
-               else    input_set_abs_params(input, usage->code, a, b, 0, 0);
-
-       }
-
-       if (usage->type == EV_ABS &&
-           (usage->hat_min < usage->hat_max || usage->hat_dir)) {
-               int i;
-               for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
-                       input_set_abs_params(input, i, -1, 1, 0, 0);
-                       set_bit(i, input->absbit);
-               }
-               if (usage->hat_dir && !field->dpad)
-                       field->dpad = usage->code;
-       }
-
-#ifdef DEBUG
-       resolv_event(usage->type, usage->code);
-       printk("\n");
-#endif
-       return;
-
-ignore:
-#ifdef DEBUG
-       printk("IGNORED\n");
-#endif
-       return;
-}
-
-void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
-{
-       struct input_dev *input;
-       int *quirks = &hid->quirks;
-
-       if (!field->hidinput)
-               return;
-
-       input = field->hidinput->input;
-
-       if (!usage->type)
-               return;
-
-       if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-               || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
-               if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-               else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-               return;
-       }
-
-       if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
-               input_event(input, usage->type, usage->code, -value);
-               return;
-       }
-
-       if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
-               input_event(input, usage->type, REL_HWHEEL, value);
-               return;
-       }
-
-       if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
-               return;
-
-       if (usage->hat_min < usage->hat_max || usage->hat_dir) {
-               int hat_dir = usage->hat_dir;
-               if (!hat_dir)
-                       hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
-               if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
-               input_event(input, usage->type, usage->code    , hid_hat_to_axis[hat_dir].x);
-                input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
-                return;
-        }
-
-       if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
-               *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
-               return;
-       }
-
-       if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
-               if (value) {
-                       input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
-                       return;
-               }
-               input_event(input, usage->type, usage->code, 0);
-               input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
-               return;
-       }
-
-       if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
-               int a = field->logical_minimum;
-               int b = field->logical_maximum;
-               input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
-       }
-
-       if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
-               dbg("Maximum Effects - %d",value);
-               return;
-       }
-
-       if (usage->hid == (HID_UP_PID | 0x7fUL)) {
-               dbg("PID Pool Report\n");
-               return;
-       }
-
-       if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
-               return;
-
-       input_event(input, usage->type, usage->code, value);
-
-       if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
-               input_event(input, usage->type, usage->code, 0);
-}
-
-void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
-{
-       struct hid_input *hidinput;
-
-       list_for_each_entry(hidinput, &hid->inputs, list)
-               input_sync(hidinput->input);
-}
-
-static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
-{
-       struct hid_report *report;
-       int i, j;
-
-       list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
-               for (i = 0; i < report->maxfield; i++) {
-                       *field = report->field[i];
-                       for (j = 0; j < (*field)->maxusage; j++)
-                               if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
-                                       return j;
-               }
-       }
-       return -1;
-}
-
-static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-       struct hid_device *hid = dev->private;
-       struct hid_field *field;
-       int offset;
-
-       if (type == EV_FF)
-               return input_ff_event(dev, type, code, value);
-
-       if (type != EV_LED)
-               return -1;
-
-       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-               warn("event field not found");
-               return -1;
-       }
-
-       hid_set_field(field, offset, value);
-       hid_submit_report(hid, field->report, USB_DIR_OUT);
-
-       return 0;
-}
-
-static int hidinput_open(struct input_dev *dev)
-{
-       struct hid_device *hid = dev->private;
-       return hid_open(hid);
-}
-
-static void hidinput_close(struct input_dev *dev)
-{
-       struct hid_device *hid = dev->private;
-       hid_close(hid);
-}
-
-/*
- * Register the input device; print a message.
- * Configure the input layer interface
- * Read all reports and initialize the absolute field values.
- */
-
-int hidinput_connect(struct hid_device *hid)
-{
-       struct usb_device *dev = hid->dev;
-       struct hid_report *report;
-       struct hid_input *hidinput = NULL;
-       struct input_dev *input_dev;
-       int i, j, k;
-
-       INIT_LIST_HEAD(&hid->inputs);
-
-       for (i = 0; i < hid->maxcollection; i++)
-               if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
-                   hid->collection[i].type == HID_COLLECTION_PHYSICAL)
-                       if (IS_INPUT_APPLICATION(hid->collection[i].usage))
-                               break;
-
-       if (i == hid->maxcollection)
-               return -1;
-
-       for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
-               list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
-
-                       if (!report->maxfield)
-                               continue;
-
-                       if (!hidinput) {
-                               hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
-                               input_dev = input_allocate_device();
-                               if (!hidinput || !input_dev) {
-                                       kfree(hidinput);
-                                       input_free_device(input_dev);
-                                       err("Out of memory during hid input probe");
-                                       return -1;
-                               }
-
-                               input_dev->private = hid;
-                               input_dev->event = hidinput_input_event;
-                               input_dev->open = hidinput_open;
-                               input_dev->close = hidinput_close;
-
-                               input_dev->name = hid->name;
-                               input_dev->phys = hid->phys;
-                               input_dev->uniq = hid->uniq;
-                               usb_to_input_id(dev, &input_dev->id);
-                               input_dev->cdev.dev = &hid->intf->dev;
-
-                               hidinput->input = input_dev;
-                               list_add_tail(&hidinput->list, &hid->inputs);
-                       }
-
-                       for (i = 0; i < report->maxfield; i++)
-                               for (j = 0; j < report->field[i]->maxusage; j++)
-                                       hidinput_configure_usage(hidinput, report->field[i],
-                                                                report->field[i]->usage + j);
-
-                       if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
-                               /* This will leave hidinput NULL, so that it
-                                * allocates another one if we have more inputs on
-                                * the same interface. Some devices (e.g. Happ's
-                                * UGCI) cram a lot of unrelated inputs into the
-                                * same interface. */
-                               hidinput->report = report;
-                               input_register_device(hidinput->input);
-                               hidinput = NULL;
-                       }
-               }
-
-       /* This only gets called when we are a single-input (most of the
-        * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
-        * only useful in this case, and not for multi-input quirks. */
-       if (hidinput) {
-               hid_ff_init(hid);
-               input_register_device(hidinput->input);
-       }
-
-       return 0;
-}
-
-void hidinput_disconnect(struct hid_device *hid)
-{
-       struct hid_input *hidinput, *next;
 
-       list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
-               list_del(&hidinput->list);
-               input_unregister_device(hidinput->input);
-               kfree(hidinput);
-       }
-}
index 93da222b6da8ffce8ab4d11762ab562e2d4fc2d1..e977ba3d17e068e8823bb278e889784eee98bd5b 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <linux/input.h>
 #include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
 
 struct device_type {
        u16 idVendor;
index 5420c13eb8eb27c1ff9eeb5adeab88b543fc9828..b4caea3864e3d4c5f84181ec27c4cc6a6fedabef 100644 (file)
@@ -28,7 +28,9 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 
-#include "hid.h"
+#include <linux/hid.h>
+
+#include "usbhid.h"
 
 #define        PID_EFFECTS_MAX         64
 
index 2d5be4c318ac2a566e99e89865391a2140a7b2eb..1cd1418ad6acba583f1630fd942ffdf3d58571df 100644 (file)
@@ -32,7 +32,7 @@
 #undef DEBUG
 #include <linux/usb.h>
 
-#include "hid.h"
+#include <linux/hid.h>
 
 /* Usages for thrustmaster devices I know about */
 #define THRUSTMASTER_USAGE_RUMBLE_LR   (HID_UP_GENDESK | 0xbb)
index d2ce3214572c59e9184d987939791640c11ab99a..af1bfae39dce4dca68470c08eaf1d2d6921e2a53 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <linux/input.h>
 #include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
 
 struct zpff_device {
        struct hid_report *report;
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
deleted file mode 100644 (file)
index 76ad68d..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-#ifndef __HID_H
-#define __HID_H
-
-/*
- * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $
- *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-
-/*
- * USB HID (Human Interface Device) interface class code
- */
-
-#define USB_INTERFACE_CLASS_HID                3
-
-/*
- * USB HID interface subclass and protocol codes
- */
-
-#define USB_INTERFACE_SUBCLASS_BOOT    1
-#define USB_INTERFACE_PROTOCOL_KEYBOARD        1
-#define USB_INTERFACE_PROTOCOL_MOUSE   2
-
-/*
- * HID class requests
- */
-
-#define HID_REQ_GET_REPORT             0x01
-#define HID_REQ_GET_IDLE               0x02
-#define HID_REQ_GET_PROTOCOL           0x03
-#define HID_REQ_SET_REPORT             0x09
-#define HID_REQ_SET_IDLE               0x0A
-#define HID_REQ_SET_PROTOCOL           0x0B
-
-/*
- * HID class descriptor types
- */
-
-#define HID_DT_HID                     (USB_TYPE_CLASS | 0x01)
-#define HID_DT_REPORT                  (USB_TYPE_CLASS | 0x02)
-#define HID_DT_PHYSICAL                        (USB_TYPE_CLASS | 0x03)
-
-/*
- * We parse each description item into this structure. Short items data
- * values are expanded to 32-bit signed int, long items contain a pointer
- * into the data area.
- */
-
-struct hid_item {
-       unsigned  format;
-       __u8      size;
-       __u8      type;
-       __u8      tag;
-       union {
-           __u8   u8;
-           __s8   s8;
-           __u16  u16;
-           __s16  s16;
-           __u32  u32;
-           __s32  s32;
-           __u8  *longdata;
-       } data;
-};
-
-/*
- * HID report item format
- */
-
-#define HID_ITEM_FORMAT_SHORT  0
-#define HID_ITEM_FORMAT_LONG   1
-
-/*
- * Special tag indicating long items
- */
-
-#define HID_ITEM_TAG_LONG      15
-
-/*
- * HID report descriptor item type (prefix bit 2,3)
- */
-
-#define HID_ITEM_TYPE_MAIN             0
-#define HID_ITEM_TYPE_GLOBAL           1
-#define HID_ITEM_TYPE_LOCAL            2
-#define HID_ITEM_TYPE_RESERVED         3
-
-/*
- * HID report descriptor main item tags
- */
-
-#define HID_MAIN_ITEM_TAG_INPUT                        8
-#define HID_MAIN_ITEM_TAG_OUTPUT               9
-#define HID_MAIN_ITEM_TAG_FEATURE              11
-#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION     10
-#define HID_MAIN_ITEM_TAG_END_COLLECTION       12
-
-/*
- * HID report descriptor main item contents
- */
-
-#define HID_MAIN_ITEM_CONSTANT         0x001
-#define HID_MAIN_ITEM_VARIABLE         0x002
-#define HID_MAIN_ITEM_RELATIVE         0x004
-#define HID_MAIN_ITEM_WRAP             0x008
-#define HID_MAIN_ITEM_NONLINEAR                0x010
-#define HID_MAIN_ITEM_NO_PREFERRED     0x020
-#define HID_MAIN_ITEM_NULL_STATE       0x040
-#define HID_MAIN_ITEM_VOLATILE         0x080
-#define HID_MAIN_ITEM_BUFFERED_BYTE    0x100
-
-/*
- * HID report descriptor collection item types
- */
-
-#define HID_COLLECTION_PHYSICAL                0
-#define HID_COLLECTION_APPLICATION     1
-#define HID_COLLECTION_LOGICAL         2
-
-/*
- * HID report descriptor global item tags
- */
-
-#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE         0
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM    1
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM    2
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM   3
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM   4
-#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT      5
-#define HID_GLOBAL_ITEM_TAG_UNIT               6
-#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE                7
-#define HID_GLOBAL_ITEM_TAG_REPORT_ID          8
-#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT       9
-#define HID_GLOBAL_ITEM_TAG_PUSH               10
-#define HID_GLOBAL_ITEM_TAG_POP                        11
-
-/*
- * HID report descriptor local item tags
- */
-
-#define HID_LOCAL_ITEM_TAG_USAGE               0
-#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM       1
-#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM       2
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX    3
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM  4
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM  5
-#define HID_LOCAL_ITEM_TAG_STRING_INDEX                7
-#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM      8
-#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM      9
-#define HID_LOCAL_ITEM_TAG_DELIMITER           10
-
-/*
- * HID usage tables
- */
-
-#define HID_USAGE_PAGE         0xffff0000
-
-#define HID_UP_UNDEFINED       0x00000000
-#define HID_UP_GENDESK         0x00010000
-#define HID_UP_SIMULATION      0x00020000
-#define HID_UP_KEYBOARD                0x00070000
-#define HID_UP_LED             0x00080000
-#define HID_UP_BUTTON          0x00090000
-#define HID_UP_ORDINAL         0x000a0000
-#define HID_UP_CONSUMER                0x000c0000
-#define HID_UP_DIGITIZER       0x000d0000
-#define HID_UP_PID             0x000f0000
-#define HID_UP_HPVENDOR         0xff7f0000
-#define HID_UP_MSVENDOR                0xff000000
-#define HID_UP_CUSTOM          0x00ff0000
-#define HID_UP_LOGIVENDOR      0xffbc0000
-
-#define HID_USAGE              0x0000ffff
-
-#define HID_GD_POINTER         0x00010001
-#define HID_GD_MOUSE           0x00010002
-#define HID_GD_JOYSTICK                0x00010004
-#define HID_GD_GAMEPAD         0x00010005
-#define HID_GD_KEYBOARD                0x00010006
-#define HID_GD_KEYPAD          0x00010007
-#define HID_GD_MULTIAXIS       0x00010008
-#define HID_GD_X               0x00010030
-#define HID_GD_Y               0x00010031
-#define HID_GD_Z               0x00010032
-#define HID_GD_RX              0x00010033
-#define HID_GD_RY              0x00010034
-#define HID_GD_RZ              0x00010035
-#define HID_GD_SLIDER          0x00010036
-#define HID_GD_DIAL            0x00010037
-#define HID_GD_WHEEL           0x00010038
-#define HID_GD_HATSWITCH       0x00010039
-#define HID_GD_BUFFER          0x0001003a
-#define HID_GD_BYTECOUNT       0x0001003b
-#define HID_GD_MOTION          0x0001003c
-#define HID_GD_START           0x0001003d
-#define HID_GD_SELECT          0x0001003e
-#define HID_GD_VX              0x00010040
-#define HID_GD_VY              0x00010041
-#define HID_GD_VZ              0x00010042
-#define HID_GD_VBRX            0x00010043
-#define HID_GD_VBRY            0x00010044
-#define HID_GD_VBRZ            0x00010045
-#define HID_GD_VNO             0x00010046
-#define HID_GD_FEATURE         0x00010047
-#define HID_GD_UP              0x00010090
-#define HID_GD_DOWN            0x00010091
-#define HID_GD_RIGHT           0x00010092
-#define HID_GD_LEFT            0x00010093
-
-/*
- * HID report types --- Ouch! HID spec says 1 2 3!
- */
-
-#define HID_INPUT_REPORT       0
-#define HID_OUTPUT_REPORT      1
-#define HID_FEATURE_REPORT     2
-
-/*
- * HID device quirks.
- */
-
-#define HID_QUIRK_INVERT                       0x00000001
-#define HID_QUIRK_NOTOUCH                      0x00000002
-#define HID_QUIRK_IGNORE                       0x00000004
-#define HID_QUIRK_NOGET                                0x00000008
-#define HID_QUIRK_HIDDEV                       0x00000010
-#define HID_QUIRK_BADPAD                       0x00000020
-#define HID_QUIRK_MULTI_INPUT                  0x00000040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7          0x00000080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x00000100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x00000200
-#define HID_QUIRK_MIGHTYMOUSE                  0x00000400
-#define HID_QUIRK_CYMOTION                     0x00000800
-#define HID_QUIRK_POWERBOOK_HAS_FN             0x00001000
-#define HID_QUIRK_POWERBOOK_FN_ON              0x00002000
-#define HID_QUIRK_INVERT_HWHEEL                        0x00004000
-#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD       0x00008000
-#define HID_QUIRK_BAD_RELATIVE_KEYS            0x00010000
-
-/*
- * This is the global environment of the parser. This information is
- * persistent for main-items. The global environment can be saved and
- * restored with PUSH/POP statements.
- */
-
-struct hid_global {
-       unsigned usage_page;
-       __s32    logical_minimum;
-       __s32    logical_maximum;
-       __s32    physical_minimum;
-       __s32    physical_maximum;
-       __s32    unit_exponent;
-       unsigned unit;
-       unsigned report_id;
-       unsigned report_size;
-       unsigned report_count;
-};
-
-/*
- * This is the local environment. It is persistent up the next main-item.
- */
-
-#define HID_MAX_DESCRIPTOR_SIZE                4096
-#define HID_MAX_USAGES                 1024
-#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;
-       unsigned delimiter_branch;
-};
-
-/*
- * This is the collection stack. We climb up the stack to determine
- * application and function of each field.
- */
-
-struct hid_collection {
-       unsigned type;
-       unsigned usage;
-       unsigned level;
-};
-
-struct hid_usage {
-       unsigned  hid;                  /* hid usage code */
-       unsigned  collection_index;     /* index into collection array */
-       /* hidinput data */
-       __u16     code;                 /* input driver code */
-       __u8      type;                 /* input driver type */
-       __s8      hat_min;              /* hat switch fun */
-       __s8      hat_max;              /* ditto */
-       __s8      hat_dir;              /* ditto */
-};
-
-struct hid_input;
-
-struct hid_field {
-       unsigned  physical;             /* physical usage for this field */
-       unsigned  logical;              /* logical usage for this field */
-       unsigned  application;          /* application usage for this field */
-       struct hid_usage *usage;        /* usage table for this function */
-       unsigned  maxusage;             /* maximum usage index */
-       unsigned  flags;                /* main-item flags (i.e. volatile,array,constant) */
-       unsigned  report_offset;        /* bit offset in the report */
-       unsigned  report_size;          /* size of this field in the report */
-       unsigned  report_count;         /* number of this field in the report */
-       unsigned  report_type;          /* (input,output,feature) */
-       __s32    *value;                /* last known value(s) */
-       __s32     logical_minimum;
-       __s32     logical_maximum;
-       __s32     physical_minimum;
-       __s32     physical_maximum;
-       __s32     unit_exponent;
-       unsigned  unit;
-       struct hid_report *report;      /* associated report */
-       unsigned index;                 /* index into report->field[] */
-       /* hidinput data */
-       struct hid_input *hidinput;     /* associated input structure */
-       __u16 dpad;                     /* dpad input code */
-};
-
-#define HID_MAX_FIELDS 64
-
-struct hid_report {
-       struct list_head list;
-       unsigned id;                                    /* id of this report */
-       unsigned type;                                  /* report type */
-       struct hid_field *field[HID_MAX_FIELDS];        /* fields of the report */
-       unsigned maxfield;                              /* maximum valid field index */
-       unsigned size;                                  /* size of the report (bits) */
-       struct hid_device *device;                      /* associated device */
-};
-
-struct hid_report_enum {
-       unsigned numbered;
-       struct list_head report_list;
-       struct hid_report *report_id_hash[256];
-};
-
-#define HID_REPORT_TYPES 3
-
-#define HID_MIN_BUFFER_SIZE    64              /* make sure there is at least a packet size of space */
-#define HID_MAX_BUFFER_SIZE    4096            /* 4kb */
-#define HID_CONTROL_FIFO_SIZE  256             /* to init devices with >100 reports */
-#define HID_OUTPUT_FIFO_SIZE   64
-
-struct hid_control_fifo {
-       unsigned char dir;
-       struct hid_report *report;
-};
-
-#define HID_CLAIMED_INPUT      1
-#define HID_CLAIMED_HIDDEV     2
-
-#define HID_CTRL_RUNNING       1
-#define HID_OUT_RUNNING                2
-#define HID_IN_RUNNING         3
-#define HID_RESET_PENDING      4
-#define HID_SUSPENDED          5
-#define HID_CLEAR_HALT         6
-
-struct hid_input {
-       struct list_head list;
-       struct hid_report *report;
-       struct input_dev *input;
-};
-
-struct hid_device {                                                    /* device report descriptor */
-        __u8 *rdesc;
-       unsigned rsize;
-       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 */
-       struct hid_report_enum report_enum[HID_REPORT_TYPES];
-
-       struct usb_device *dev;                                         /* USB device */
-       struct usb_interface *intf;                                     /* USB interface */
-       int ifnum;                                                      /* USB interface number */
-
-       unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
-       struct timer_list io_retry;                                     /* Retry timer */
-       unsigned long stop_retry;                                       /* Time to give up, in jiffies */
-       unsigned int retry_delay;                                       /* Delay length in ms */
-       struct work_struct reset_work;                                  /* Task context for resets */
-
-       unsigned int bufsize;                                           /* URB buffer size */
-
-       struct urb *urbin;                                              /* Input URB */
-       char *inbuf;                                                    /* Input buffer */
-       dma_addr_t inbuf_dma;                                           /* Input buffer dma */
-       spinlock_t inlock;                                              /* Input fifo spinlock */
-
-       struct urb *urbctrl;                                            /* Control URB */
-       struct usb_ctrlrequest *cr;                                     /* Control request struct */
-       dma_addr_t cr_dma;                                              /* Control request struct dma */
-       struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];            /* Control fifo */
-       unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
-       char *ctrlbuf;                                                  /* Control buffer */
-       dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
-       spinlock_t ctrllock;                                            /* Control fifo spinlock */
-
-       struct urb *urbout;                                             /* Output URB */
-       struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
-       unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
-       char *outbuf;                                                   /* Output buffer */
-       dma_addr_t outbuf_dma;                                          /* Output buffer dma */
-       spinlock_t outlock;                                             /* Output fifo spinlock */
-
-       unsigned claimed;                                               /* Claimed by hidinput, hiddev? */
-       unsigned quirks;                                                /* Various quirks the device can pull on us */
-
-       struct list_head inputs;                                        /* The list of inputs */
-       void *hiddev;                                                   /* The hiddev structure */
-       int minor;                                                      /* Hiddev minor number */
-
-       wait_queue_head_t wait;                                         /* For sleeping */
-
-       int open;                                                       /* is the device open by anyone? */
-       char name[128];                                                 /* Device name */
-       char phys[64];                                                  /* Device physical location */
-       char uniq[64];                                                  /* Device unique identifier (serial #) */
-
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-       unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
-       unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
-#endif
-};
-
-#define HID_GLOBAL_STACK_SIZE 4
-#define HID_COLLECTION_STACK_SIZE 4
-
-struct hid_parser {
-       struct hid_global     global;
-       struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
-       unsigned              global_stack_ptr;
-       struct hid_local      local;
-       unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
-       unsigned              collection_stack_ptr;
-       struct hid_device    *device;
-};
-
-struct hid_class_descriptor {
-       __u8  bDescriptorType;
-       __u16 wDescriptorLength;
-} __attribute__ ((packed));
-
-struct hid_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u16 bcdHID;
-       __u8  bCountryCode;
-       __u8  bNumDescriptors;
-
-       struct hid_class_descriptor desc[1];
-} __attribute__ ((packed));
-
-#ifdef DEBUG
-#include "hid-debug.h"
-#else
-#define hid_dump_input(a,b)    do { } while (0)
-#define hid_dump_device(c)     do { } while (0)
-#define hid_dump_field(a,b)    do { } while (0)
-#define resolv_usage(a)                do { } while (0)
-#define resolv_event(a,b)      do { } while (0)
-#endif
-
-#endif
-
-#ifdef CONFIG_USB_HIDINPUT
-/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
-/* We ignore a few input applications that are not widely used */
-#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
-extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *);
-extern void hidinput_disconnect(struct hid_device *);
-#else
-#define IS_INPUT_APPLICATION(a) (0)
-static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
-static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { }
-static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
-static inline void hidinput_disconnect(struct hid_device *hid) { }
-#endif
-
-int hid_open(struct hid_device *);
-void hid_close(struct hid_device *);
-int hid_set_field(struct hid_field *, unsigned, __s32);
-void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
-void hid_init_reports(struct hid_device *hid);
-int hid_wait_io(struct hid_device* hid);
-
-
-#ifdef CONFIG_HID_FF
-int hid_ff_init(struct hid_device *hid);
-
-int hid_lgff_init(struct hid_device *hid);
-int hid_tmff_init(struct hid_device *hid);
-int hid_zpff_init(struct hid_device *hid);
-#ifdef CONFIG_HID_PID
-int hid_pidff_init(struct hid_device *hid);
-#else
-static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
-#endif
-
-#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
-#endif
-
index 7dc14d0cacc1bd5c79298fba41a11aa33749cdaf..cbd3b60d93bb4efc4e5d5e6739a0d3174ce964d0 100644 (file)
@@ -32,8 +32,9 @@
 #include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
 #include <linux/hiddev.h>
+#include "usbhid.h"
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 #define HIDDEV_MINOR_BASE      0
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
new file mode 100644 (file)
index 0000000..f04d6d7
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
+ *
+ *  (c) 1999 Andreas Gal               <gal@cs.uni-magdeburg.de>
+ *  (c) 2000-2001 Vojtech Pavlik       <vojtech@ucw.cz>
+ *
+ *  Some debug stuff for the HID parser.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/input.h>
+
+struct hid_usage_entry {
+       unsigned  page;
+       unsigned  usage;
+       char     *description;
+};
+
+static const struct hid_usage_entry hid_usage_table[] = {
+  {  0,      0, "Undefined" },
+  {  1,      0, "GenericDesktop" },
+    {0, 0x01, "Pointer"},
+    {0, 0x02, "Mouse"},
+    {0, 0x04, "Joystick"},
+    {0, 0x05, "GamePad"},
+    {0, 0x06, "Keyboard"},
+    {0, 0x07, "Keypad"},
+    {0, 0x08, "MultiAxis"},
+      {0, 0x30, "X"},
+      {0, 0x31, "Y"},
+      {0, 0x32, "Z"},
+      {0, 0x33, "Rx"},
+      {0, 0x34, "Ry"},
+      {0, 0x35, "Rz"},
+      {0, 0x36, "Slider"},
+      {0, 0x37, "Dial"},
+      {0, 0x38, "Wheel"},
+      {0, 0x39, "HatSwitch"},
+    {0, 0x3a, "CountedBuffer"},
+      {0, 0x3b, "ByteCount"},
+      {0, 0x3c, "MotionWakeup"},
+      {0, 0x3d, "Start"},
+      {0, 0x3e, "Select"},
+      {0, 0x40, "Vx"},
+      {0, 0x41, "Vy"},
+      {0, 0x42, "Vz"},
+      {0, 0x43, "Vbrx"},
+      {0, 0x44, "Vbry"},
+      {0, 0x45, "Vbrz"},
+      {0, 0x46, "Vno"},
+    {0, 0x80, "SystemControl"},
+      {0, 0x81, "SystemPowerDown"},
+      {0, 0x82, "SystemSleep"},
+      {0, 0x83, "SystemWakeUp"},
+      {0, 0x84, "SystemContextMenu"},
+      {0, 0x85, "SystemMainMenu"},
+      {0, 0x86, "SystemAppMenu"},
+      {0, 0x87, "SystemMenuHelp"},
+      {0, 0x88, "SystemMenuExit"},
+      {0, 0x89, "SystemMenuSelect"},
+      {0, 0x8a, "SystemMenuRight"},
+      {0, 0x8b, "SystemMenuLeft"},
+      {0, 0x8c, "SystemMenuUp"},
+      {0, 0x8d, "SystemMenuDown"},
+      {0, 0x90, "D-PadUp"},
+      {0, 0x91, "D-PadDown"},
+      {0, 0x92, "D-PadRight"},
+      {0, 0x93, "D-PadLeft"},
+  {  2, 0, "Simulation" },
+      {0, 0xb0, "Aileron"},
+      {0, 0xb1, "AileronTrim"},
+      {0, 0xb2, "Anti-Torque"},
+      {0, 0xb3, "Autopilot"},
+      {0, 0xb4, "Chaff"},
+      {0, 0xb5, "Collective"},
+      {0, 0xb6, "DiveBrake"},
+      {0, 0xb7, "ElectronicCountermeasures"},
+      {0, 0xb8, "Elevator"},
+      {0, 0xb9, "ElevatorTrim"},
+      {0, 0xba, "Rudder"},
+      {0, 0xbb, "Throttle"},
+      {0, 0xbc, "FlightCommunications"},
+      {0, 0xbd, "FlareRelease"},
+      {0, 0xbe, "LandingGear"},
+      {0, 0xbf, "ToeBrake"},
+  {  7, 0, "Keyboard" },
+  {  8, 0, "LED" },
+      {0, 0x01, "NumLock"},
+      {0, 0x02, "CapsLock"},
+      {0, 0x03, "ScrollLock"},
+      {0, 0x04, "Compose"},
+      {0, 0x05, "Kana"},
+      {0, 0x4b, "GenericIndicator"},
+  {  9, 0, "Button" },
+  { 10, 0, "Ordinal" },
+  { 12, 0, "Consumer" },
+      {0, 0x238, "HorizontalWheel"},
+  { 13, 0, "Digitizers" },
+    {0, 0x01, "Digitizer"},
+    {0, 0x02, "Pen"},
+    {0, 0x03, "LightPen"},
+    {0, 0x04, "TouchScreen"},
+    {0, 0x05, "TouchPad"},
+    {0, 0x20, "Stylus"},
+    {0, 0x21, "Puck"},
+    {0, 0x22, "Finger"},
+    {0, 0x30, "TipPressure"},
+    {0, 0x31, "BarrelPressure"},
+    {0, 0x32, "InRange"},
+    {0, 0x33, "Touch"},
+    {0, 0x34, "UnTouch"},
+    {0, 0x35, "Tap"},
+    {0, 0x39, "TabletFunctionKey"},
+    {0, 0x3a, "ProgramChangeKey"},
+    {0, 0x3c, "Invert"},
+    {0, 0x42, "TipSwitch"},
+    {0, 0x43, "SecondaryTipSwitch"},
+    {0, 0x44, "BarrelSwitch"},
+    {0, 0x45, "Eraser"},
+    {0, 0x46, "TabletPick"},
+  { 15, 0, "PhysicalInterfaceDevice" },
+    {0, 0x00, "Undefined"},
+    {0, 0x01, "Physical_Interface_Device"},
+      {0, 0x20, "Normal"},
+    {0, 0x21, "Set_Effect_Report"},
+      {0, 0x22, "Effect_Block_Index"},
+      {0, 0x23, "Parameter_Block_Offset"},
+      {0, 0x24, "ROM_Flag"},
+      {0, 0x25, "Effect_Type"},
+        {0, 0x26, "ET_Constant_Force"},
+        {0, 0x27, "ET_Ramp"},
+        {0, 0x28, "ET_Custom_Force_Data"},
+        {0, 0x30, "ET_Square"},
+        {0, 0x31, "ET_Sine"},
+        {0, 0x32, "ET_Triangle"},
+        {0, 0x33, "ET_Sawtooth_Up"},
+        {0, 0x34, "ET_Sawtooth_Down"},
+        {0, 0x40, "ET_Spring"},
+        {0, 0x41, "ET_Damper"},
+        {0, 0x42, "ET_Inertia"},
+        {0, 0x43, "ET_Friction"},
+      {0, 0x50, "Duration"},
+      {0, 0x51, "Sample_Period"},
+      {0, 0x52, "Gain"},
+      {0, 0x53, "Trigger_Button"},
+      {0, 0x54, "Trigger_Repeat_Interval"},
+      {0, 0x55, "Axes_Enable"},
+        {0, 0x56, "Direction_Enable"},
+      {0, 0x57, "Direction"},
+      {0, 0x58, "Type_Specific_Block_Offset"},
+        {0, 0x59, "Block_Type"},
+        {0, 0x5A, "Set_Envelope_Report"},
+          {0, 0x5B, "Attack_Level"},
+          {0, 0x5C, "Attack_Time"},
+          {0, 0x5D, "Fade_Level"},
+          {0, 0x5E, "Fade_Time"},
+        {0, 0x5F, "Set_Condition_Report"},
+        {0, 0x60, "CP_Offset"},
+        {0, 0x61, "Positive_Coefficient"},
+        {0, 0x62, "Negative_Coefficient"},
+        {0, 0x63, "Positive_Saturation"},
+        {0, 0x64, "Negative_Saturation"},
+        {0, 0x65, "Dead_Band"},
+      {0, 0x66, "Download_Force_Sample"},
+      {0, 0x67, "Isoch_Custom_Force_Enable"},
+      {0, 0x68, "Custom_Force_Data_Report"},
+        {0, 0x69, "Custom_Force_Data"},
+        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
+      {0, 0x6B, "Set_Custom_Force_Report"},
+        {0, 0x6C, "Custom_Force_Data_Offset"},
+        {0, 0x6D, "Sample_Count"},
+      {0, 0x6E, "Set_Periodic_Report"},
+        {0, 0x6F, "Offset"},
+        {0, 0x70, "Magnitude"},
+        {0, 0x71, "Phase"},
+        {0, 0x72, "Period"},
+      {0, 0x73, "Set_Constant_Force_Report"},
+        {0, 0x74, "Set_Ramp_Force_Report"},
+        {0, 0x75, "Ramp_Start"},
+        {0, 0x76, "Ramp_End"},
+      {0, 0x77, "Effect_Operation_Report"},
+        {0, 0x78, "Effect_Operation"},
+          {0, 0x79, "Op_Effect_Start"},
+          {0, 0x7A, "Op_Effect_Start_Solo"},
+          {0, 0x7B, "Op_Effect_Stop"},
+          {0, 0x7C, "Loop_Count"},
+      {0, 0x7D, "Device_Gain_Report"},
+        {0, 0x7E, "Device_Gain"},
+    {0, 0x7F, "PID_Pool_Report"},
+      {0, 0x80, "RAM_Pool_Size"},
+      {0, 0x81, "ROM_Pool_Size"},
+      {0, 0x82, "ROM_Effect_Block_Count"},
+      {0, 0x83, "Simultaneous_Effects_Max"},
+      {0, 0x84, "Pool_Alignment"},
+    {0, 0x85, "PID_Pool_Move_Report"},
+      {0, 0x86, "Move_Source"},
+      {0, 0x87, "Move_Destination"},
+      {0, 0x88, "Move_Length"},
+    {0, 0x89, "PID_Block_Load_Report"},
+      {0, 0x8B, "Block_Load_Status"},
+      {0, 0x8C, "Block_Load_Success"},
+      {0, 0x8D, "Block_Load_Full"},
+      {0, 0x8E, "Block_Load_Error"},
+      {0, 0x8F, "Block_Handle"},
+      {0, 0x90, "PID_Block_Free_Report"},
+      {0, 0x91, "Type_Specific_Block_Handle"},
+    {0, 0x92, "PID_State_Report"},
+      {0, 0x94, "Effect_Playing"},
+      {0, 0x95, "PID_Device_Control_Report"},
+        {0, 0x96, "PID_Device_Control"},
+        {0, 0x97, "DC_Enable_Actuators"},
+        {0, 0x98, "DC_Disable_Actuators"},
+        {0, 0x99, "DC_Stop_All_Effects"},
+        {0, 0x9A, "DC_Device_Reset"},
+        {0, 0x9B, "DC_Device_Pause"},
+        {0, 0x9C, "DC_Device_Continue"},
+      {0, 0x9F, "Device_Paused"},
+      {0, 0xA0, "Actuators_Enabled"},
+      {0, 0xA4, "Safety_Switch"},
+      {0, 0xA5, "Actuator_Override_Switch"},
+      {0, 0xA6, "Actuator_Power"},
+    {0, 0xA7, "Start_Delay"},
+    {0, 0xA8, "Parameter_Block_Size"},
+    {0, 0xA9, "Device_Managed_Pool"},
+    {0, 0xAA, "Shared_Parameter_Blocks"},
+    {0, 0xAB, "Create_New_Effect_Report"},
+    {0, 0xAC, "RAM_Pool_Available"},
+  { 0x84, 0, "Power Device" },
+    { 0x84, 0x02, "PresentStatus" },
+    { 0x84, 0x03, "ChangeStatus" },
+    { 0x84, 0x04, "UPS" },
+    { 0x84, 0x05, "PowerSupply" },
+    { 0x84, 0x10, "BatterySystem" },
+    { 0x84, 0x11, "BatterySystemID" },
+    { 0x84, 0x12, "Battery" },
+    { 0x84, 0x13, "BatteryID" },
+    { 0x84, 0x14, "Charger" },
+    { 0x84, 0x15, "ChargerID" },
+    { 0x84, 0x16, "PowerConverter" },
+    { 0x84, 0x17, "PowerConverterID" },
+    { 0x84, 0x18, "OutletSystem" },
+    { 0x84, 0x19, "OutletSystemID" },
+    { 0x84, 0x1a, "Input" },
+    { 0x84, 0x1b, "InputID" },
+    { 0x84, 0x1c, "Output" },
+    { 0x84, 0x1d, "OutputID" },
+    { 0x84, 0x1e, "Flow" },
+    { 0x84, 0x1f, "FlowID" },
+    { 0x84, 0x20, "Outlet" },
+    { 0x84, 0x21, "OutletID" },
+    { 0x84, 0x22, "Gang" },
+    { 0x84, 0x24, "PowerSummary" },
+    { 0x84, 0x25, "PowerSummaryID" },
+    { 0x84, 0x30, "Voltage" },
+    { 0x84, 0x31, "Current" },
+    { 0x84, 0x32, "Frequency" },
+    { 0x84, 0x33, "ApparentPower" },
+    { 0x84, 0x35, "PercentLoad" },
+    { 0x84, 0x40, "ConfigVoltage" },
+    { 0x84, 0x41, "ConfigCurrent" },
+    { 0x84, 0x43, "ConfigApparentPower" },
+    { 0x84, 0x53, "LowVoltageTransfer" },
+    { 0x84, 0x54, "HighVoltageTransfer" },
+    { 0x84, 0x56, "DelayBeforeStartup" },
+    { 0x84, 0x57, "DelayBeforeShutdown" },
+    { 0x84, 0x58, "Test" },
+    { 0x84, 0x5a, "AudibleAlarmControl" },
+    { 0x84, 0x60, "Present" },
+    { 0x84, 0x61, "Good" },
+    { 0x84, 0x62, "InternalFailure" },
+    { 0x84, 0x65, "Overload" },
+    { 0x84, 0x66, "OverCharged" },
+    { 0x84, 0x67, "OverTemperature" },
+    { 0x84, 0x68, "ShutdownRequested" },
+    { 0x84, 0x69, "ShutdownImminent" },
+    { 0x84, 0x6b, "SwitchOn/Off" },
+    { 0x84, 0x6c, "Switchable" },
+    { 0x84, 0x6d, "Used" },
+    { 0x84, 0x6e, "Boost" },
+    { 0x84, 0x73, "CommunicationLost" },
+    { 0x84, 0xfd, "iManufacturer" },
+    { 0x84, 0xfe, "iProduct" },
+    { 0x84, 0xff, "iSerialNumber" },
+  { 0x85, 0, "Battery System" },
+    { 0x85, 0x01, "SMBBatteryMode" },
+    { 0x85, 0x02, "SMBBatteryStatus" },
+    { 0x85, 0x03, "SMBAlarmWarning" },
+    { 0x85, 0x04, "SMBChargerMode" },
+    { 0x85, 0x05, "SMBChargerStatus" },
+    { 0x85, 0x06, "SMBChargerSpecInfo" },
+    { 0x85, 0x07, "SMBSelectorState" },
+    { 0x85, 0x08, "SMBSelectorPresets" },
+    { 0x85, 0x09, "SMBSelectorInfo" },
+    { 0x85, 0x29, "RemainingCapacityLimit" },
+    { 0x85, 0x2c, "CapacityMode" },
+    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
+    { 0x85, 0x44, "Charging" },
+    { 0x85, 0x45, "Discharging" },
+    { 0x85, 0x4b, "NeedReplacement" },
+    { 0x85, 0x66, "RemainingCapacity" },
+    { 0x85, 0x68, "RunTimeToEmpty" },
+    { 0x85, 0x6a, "AverageTimeToFull" },
+    { 0x85, 0x83, "DesignCapacity" },
+    { 0x85, 0x85, "ManufacturerDate" },
+    { 0x85, 0x89, "iDeviceChemistry" },
+    { 0x85, 0x8b, "Rechargable" },
+    { 0x85, 0x8f, "iOEMInformation" },
+    { 0x85, 0x8d, "CapacityGranularity1" },
+    { 0x85, 0xd0, "ACPresent" },
+  /* pages 0xff00 to 0xffff are vendor-specific */
+  { 0xffff, 0, "Vendor-specific-FF" },
+  { 0, 0, NULL }
+};
+
+static void resolv_usage_page(unsigned page) {
+       const struct hid_usage_entry *p;
+
+       for (p = hid_usage_table; p->description; p++)
+               if (p->page == page) {
+                       printk("%s", p->description);
+                       return;
+               }
+       printk("%04x", page);
+}
+
+static void resolv_usage(unsigned usage) {
+       const struct hid_usage_entry *p;
+
+       resolv_usage_page(usage >> 16);
+       printk(".");
+       for (p = hid_usage_table; p->description; p++)
+               if (p->page == (usage >> 16)) {
+                       for(++p; p->description && p->usage != 0; p++)
+                               if (p->usage == (usage & 0xffff)) {
+                                       printk("%s", p->description);
+                                       return;
+                               }
+                       break;
+               }
+       printk("%04x", usage & 0xffff);
+}
+
+__inline__ static void tab(int n) {
+       while (n--) printk(" ");
+}
+
+static void hid_dump_field(struct hid_field *field, int n) {
+       int j;
+
+       if (field->physical) {
+               tab(n);
+               printk("Physical(");
+               resolv_usage(field->physical); printk(")\n");
+       }
+       if (field->logical) {
+               tab(n);
+               printk("Logical(");
+               resolv_usage(field->logical); printk(")\n");
+       }
+       tab(n); printk("Usage(%d)\n", field->maxusage);
+       for (j = 0; j < field->maxusage; j++) {
+               tab(n+2);resolv_usage(field->usage[j].hid); printk("\n");
+       }
+       if (field->logical_minimum != field->logical_maximum) {
+               tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
+               tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+       }
+       if (field->physical_minimum != field->physical_maximum) {
+               tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
+               tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+       }
+       if (field->unit_exponent) {
+               tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+       }
+       if (field->unit) {
+               char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+               char *units[5][8] = {
+                       { "None", "None", "None", "None", "None", "None", "None", "None" },
+                       { "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+                       { "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+                       { "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
+                       { "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
+               };
+
+               int i;
+               int sys;
+                __u32 data = field->unit;
+
+               /* First nibble tells us which system we're in. */
+               sys = data & 0xf;
+               data >>= 4;
+
+               if(sys > 4) {
+                       tab(n); printk("Unit(Invalid)\n");
+               }
+               else {
+                       int earlier_unit = 0;
+
+                       tab(n); printk("Unit(%s : ", systems[sys]);
+
+                       for (i=1 ; i<sizeof(__u32)*2 ; i++) {
+                               char nibble = data & 0xf;
+                               data >>= 4;
+                               if (nibble != 0) {
+                                       if(earlier_unit++ > 0)
+                                               printk("*");
+                                       printk("%s", units[sys][i]);
+                                       if(nibble != 1) {
+                                               /* This is a _signed_ nibble(!) */
+
+                                               int val = nibble & 0x7;
+                                               if(nibble & 0x08)
+                                                       val = -((0x7 & ~val) +1);
+                                               printk("^%d", val);
+                                       }
+                               }
+                       }
+                       printk(")\n");
+               }
+       }
+       tab(n); printk("Report Size(%u)\n", field->report_size);
+       tab(n); printk("Report Count(%u)\n", field->report_count);
+       tab(n); printk("Report Offset(%u)\n", field->report_offset);
+
+       tab(n); printk("Flags( ");
+       j = field->flags;
+       printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+       printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+       printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+       printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+       printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+       printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+       printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+       printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+       printk(")\n");
+}
+
+static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
+       struct hid_report_enum *report_enum;
+       struct hid_report *report;
+       struct list_head *list;
+       unsigned i,k;
+       static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+
+       for (i = 0; i < HID_REPORT_TYPES; i++) {
+               report_enum = device->report_enum + i;
+               list = report_enum->report_list.next;
+               while (list != &report_enum->report_list) {
+                       report = (struct hid_report *) list;
+                       tab(2);
+                       printk("%s", table[i]);
+                       if (report->id)
+                               printk("(%d)", report->id);
+                       printk("[%s]", table[report->type]);
+                       printk("\n");
+                       for (k = 0; k < report->maxfield; k++) {
+                               tab(4);
+                               printk("Field(%d)\n", k);
+                               hid_dump_field(report->field[k], 6);
+                       }
+                       list = list->next;
+               }
+       }
+}
+
+static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) {
+       printk("hid-debug: input ");
+       resolv_usage(usage->hid);
+       printk(" = %d\n", value);
+}
+
+
+static char *events[EV_MAX + 1] = {
+       [EV_SYN] = "Sync",                      [EV_KEY] = "Key",
+       [EV_REL] = "Relative",                  [EV_ABS] = "Absolute",
+       [EV_MSC] = "Misc",                      [EV_LED] = "LED",
+       [EV_SND] = "Sound",                     [EV_REP] = "Repeat",
+       [EV_FF] = "ForceFeedback",              [EV_PWR] = "Power",
+       [EV_FF_STATUS] = "ForceFeedbackStatus",
+};
+
+static char *syncs[2] = {
+       [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
+};
+static char *keys[KEY_MAX + 1] = {
+       [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
+       [KEY_1] = "1",                          [KEY_2] = "2",
+       [KEY_3] = "3",                          [KEY_4] = "4",
+       [KEY_5] = "5",                          [KEY_6] = "6",
+       [KEY_7] = "7",                          [KEY_8] = "8",
+       [KEY_9] = "9",                          [KEY_0] = "0",
+       [KEY_MINUS] = "Minus",                  [KEY_EQUAL] = "Equal",
+       [KEY_BACKSPACE] = "Backspace",          [KEY_TAB] = "Tab",
+       [KEY_Q] = "Q",                          [KEY_W] = "W",
+       [KEY_E] = "E",                          [KEY_R] = "R",
+       [KEY_T] = "T",                          [KEY_Y] = "Y",
+       [KEY_U] = "U",                          [KEY_I] = "I",
+       [KEY_O] = "O",                          [KEY_P] = "P",
+       [KEY_LEFTBRACE] = "LeftBrace",          [KEY_RIGHTBRACE] = "RightBrace",
+       [KEY_ENTER] = "Enter",                  [KEY_LEFTCTRL] = "LeftControl",
+       [KEY_A] = "A",                          [KEY_S] = "S",
+       [KEY_D] = "D",                          [KEY_F] = "F",
+       [KEY_G] = "G",                          [KEY_H] = "H",
+       [KEY_J] = "J",                          [KEY_K] = "K",
+       [KEY_L] = "L",                          [KEY_SEMICOLON] = "Semicolon",
+       [KEY_APOSTROPHE] = "Apostrophe",        [KEY_GRAVE] = "Grave",
+       [KEY_LEFTSHIFT] = "LeftShift",          [KEY_BACKSLASH] = "BackSlash",
+       [KEY_Z] = "Z",                          [KEY_X] = "X",
+       [KEY_C] = "C",                          [KEY_V] = "V",
+       [KEY_B] = "B",                          [KEY_N] = "N",
+       [KEY_M] = "M",                          [KEY_COMMA] = "Comma",
+       [KEY_DOT] = "Dot",                      [KEY_SLASH] = "Slash",
+       [KEY_RIGHTSHIFT] = "RightShift",        [KEY_KPASTERISK] = "KPAsterisk",
+       [KEY_LEFTALT] = "LeftAlt",              [KEY_SPACE] = "Space",
+       [KEY_CAPSLOCK] = "CapsLock",            [KEY_F1] = "F1",
+       [KEY_F2] = "F2",                        [KEY_F3] = "F3",
+       [KEY_F4] = "F4",                        [KEY_F5] = "F5",
+       [KEY_F6] = "F6",                        [KEY_F7] = "F7",
+       [KEY_F8] = "F8",                        [KEY_F9] = "F9",
+       [KEY_F10] = "F10",                      [KEY_NUMLOCK] = "NumLock",
+       [KEY_SCROLLLOCK] = "ScrollLock",        [KEY_KP7] = "KP7",
+       [KEY_KP8] = "KP8",                      [KEY_KP9] = "KP9",
+       [KEY_KPMINUS] = "KPMinus",              [KEY_KP4] = "KP4",
+       [KEY_KP5] = "KP5",                      [KEY_KP6] = "KP6",
+       [KEY_KPPLUS] = "KPPlus",                [KEY_KP1] = "KP1",
+       [KEY_KP2] = "KP2",                      [KEY_KP3] = "KP3",
+       [KEY_KP0] = "KP0",                      [KEY_KPDOT] = "KPDot",
+       [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+       [KEY_F11] = "F11",                      [KEY_F12] = "F12",
+       [KEY_RO] = "RO",                        [KEY_KATAKANA] = "Katakana",
+       [KEY_HIRAGANA] = "HIRAGANA",            [KEY_HENKAN] = "Henkan",
+       [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
+       [KEY_KPJPCOMMA] = "KPJpComma",          [KEY_KPENTER] = "KPEnter",
+       [KEY_RIGHTCTRL] = "RightCtrl",          [KEY_KPSLASH] = "KPSlash",
+       [KEY_SYSRQ] = "SysRq",                  [KEY_RIGHTALT] = "RightAlt",
+       [KEY_LINEFEED] = "LineFeed",            [KEY_HOME] = "Home",
+       [KEY_UP] = "Up",                        [KEY_PAGEUP] = "PageUp",
+       [KEY_LEFT] = "Left",                    [KEY_RIGHT] = "Right",
+       [KEY_END] = "End",                      [KEY_DOWN] = "Down",
+       [KEY_PAGEDOWN] = "PageDown",            [KEY_INSERT] = "Insert",
+       [KEY_DELETE] = "Delete",                [KEY_MACRO] = "Macro",
+       [KEY_MUTE] = "Mute",                    [KEY_VOLUMEDOWN] = "VolumeDown",
+       [KEY_VOLUMEUP] = "VolumeUp",            [KEY_POWER] = "Power",
+       [KEY_KPEQUAL] = "KPEqual",              [KEY_KPPLUSMINUS] = "KPPlusMinus",
+       [KEY_PAUSE] = "Pause",                  [KEY_KPCOMMA] = "KPComma",
+       [KEY_HANGUEL] = "Hangeul",              [KEY_HANJA] = "Hanja",
+       [KEY_YEN] = "Yen",                      [KEY_LEFTMETA] = "LeftMeta",
+       [KEY_RIGHTMETA] = "RightMeta",          [KEY_COMPOSE] = "Compose",
+       [KEY_STOP] = "Stop",                    [KEY_AGAIN] = "Again",
+       [KEY_PROPS] = "Props",                  [KEY_UNDO] = "Undo",
+       [KEY_FRONT] = "Front",                  [KEY_COPY] = "Copy",
+       [KEY_OPEN] = "Open",                    [KEY_PASTE] = "Paste",
+       [KEY_FIND] = "Find",                    [KEY_CUT] = "Cut",
+       [KEY_HELP] = "Help",                    [KEY_MENU] = "Menu",
+       [KEY_CALC] = "Calc",                    [KEY_SETUP] = "Setup",
+       [KEY_SLEEP] = "Sleep",                  [KEY_WAKEUP] = "WakeUp",
+       [KEY_FILE] = "File",                    [KEY_SENDFILE] = "SendFile",
+       [KEY_DELETEFILE] = "DeleteFile",        [KEY_XFER] = "X-fer",
+       [KEY_PROG1] = "Prog1",                  [KEY_PROG2] = "Prog2",
+       [KEY_WWW] = "WWW",                      [KEY_MSDOS] = "MSDOS",
+       [KEY_COFFEE] = "Coffee",                [KEY_DIRECTION] = "Direction",
+       [KEY_CYCLEWINDOWS] = "CycleWindows",    [KEY_MAIL] = "Mail",
+       [KEY_BOOKMARKS] = "Bookmarks",          [KEY_COMPUTER] = "Computer",
+       [KEY_BACK] = "Back",                    [KEY_FORWARD] = "Forward",
+       [KEY_CLOSECD] = "CloseCD",              [KEY_EJECTCD] = "EjectCD",
+       [KEY_EJECTCLOSECD] = "EjectCloseCD",    [KEY_NEXTSONG] = "NextSong",
+       [KEY_PLAYPAUSE] = "PlayPause",          [KEY_PREVIOUSSONG] = "PreviousSong",
+       [KEY_STOPCD] = "StopCD",                [KEY_RECORD] = "Record",
+       [KEY_REWIND] = "Rewind",                [KEY_PHONE] = "Phone",
+       [KEY_ISO] = "ISOKey",                   [KEY_CONFIG] = "Config",
+       [KEY_HOMEPAGE] = "HomePage",            [KEY_REFRESH] = "Refresh",
+       [KEY_EXIT] = "Exit",                    [KEY_MOVE] = "Move",
+       [KEY_EDIT] = "Edit",                    [KEY_SCROLLUP] = "ScrollUp",
+       [KEY_SCROLLDOWN] = "ScrollDown",        [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
+       [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
+       [KEY_REDO] = "Redo",                    [KEY_F13] = "F13",
+       [KEY_F14] = "F14",                      [KEY_F15] = "F15",
+       [KEY_F16] = "F16",                      [KEY_F17] = "F17",
+       [KEY_F18] = "F18",                      [KEY_F19] = "F19",
+       [KEY_F20] = "F20",                      [KEY_F21] = "F21",
+       [KEY_F22] = "F22",                      [KEY_F23] = "F23",
+       [KEY_F24] = "F24",                      [KEY_PLAYCD] = "PlayCD",
+       [KEY_PAUSECD] = "PauseCD",              [KEY_PROG3] = "Prog3",
+       [KEY_PROG4] = "Prog4",                  [KEY_SUSPEND] = "Suspend",
+       [KEY_CLOSE] = "Close",                  [KEY_PLAY] = "Play",
+       [KEY_FASTFORWARD] = "FastForward",      [KEY_BASSBOOST] = "BassBoost",
+       [KEY_PRINT] = "Print",                  [KEY_HP] = "HP",
+       [KEY_CAMERA] = "Camera",                [KEY_SOUND] = "Sound",
+       [KEY_QUESTION] = "Question",            [KEY_EMAIL] = "Email",
+       [KEY_CHAT] = "Chat",                    [KEY_SEARCH] = "Search",
+       [KEY_CONNECT] = "Connect",              [KEY_FINANCE] = "Finance",
+       [KEY_SPORT] = "Sport",                  [KEY_SHOP] = "Shop",
+       [KEY_ALTERASE] = "AlternateErase",      [KEY_CANCEL] = "Cancel",
+       [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
+       [KEY_MEDIA] = "Media",                  [KEY_UNKNOWN] = "Unknown",
+       [BTN_0] = "Btn0",                       [BTN_1] = "Btn1",
+       [BTN_2] = "Btn2",                       [BTN_3] = "Btn3",
+       [BTN_4] = "Btn4",                       [BTN_5] = "Btn5",
+       [BTN_6] = "Btn6",                       [BTN_7] = "Btn7",
+       [BTN_8] = "Btn8",                       [BTN_9] = "Btn9",
+       [BTN_LEFT] = "LeftBtn",                 [BTN_RIGHT] = "RightBtn",
+       [BTN_MIDDLE] = "MiddleBtn",             [BTN_SIDE] = "SideBtn",
+       [BTN_EXTRA] = "ExtraBtn",               [BTN_FORWARD] = "ForwardBtn",
+       [BTN_BACK] = "BackBtn",                 [BTN_TASK] = "TaskBtn",
+       [BTN_TRIGGER] = "Trigger",              [BTN_THUMB] = "ThumbBtn",
+       [BTN_THUMB2] = "ThumbBtn2",             [BTN_TOP] = "TopBtn",
+       [BTN_TOP2] = "TopBtn2",                 [BTN_PINKIE] = "PinkieBtn",
+       [BTN_BASE] = "BaseBtn",                 [BTN_BASE2] = "BaseBtn2",
+       [BTN_BASE3] = "BaseBtn3",               [BTN_BASE4] = "BaseBtn4",
+       [BTN_BASE5] = "BaseBtn5",               [BTN_BASE6] = "BaseBtn6",
+       [BTN_DEAD] = "BtnDead",                 [BTN_A] = "BtnA",
+       [BTN_B] = "BtnB",                       [BTN_C] = "BtnC",
+       [BTN_X] = "BtnX",                       [BTN_Y] = "BtnY",
+       [BTN_Z] = "BtnZ",                       [BTN_TL] = "BtnTL",
+       [BTN_TR] = "BtnTR",                     [BTN_TL2] = "BtnTL2",
+       [BTN_TR2] = "BtnTR2",                   [BTN_SELECT] = "BtnSelect",
+       [BTN_START] = "BtnStart",               [BTN_MODE] = "BtnMode",
+       [BTN_THUMBL] = "BtnThumbL",             [BTN_THUMBR] = "BtnThumbR",
+       [BTN_TOOL_PEN] = "ToolPen",             [BTN_TOOL_RUBBER] = "ToolRubber",
+       [BTN_TOOL_BRUSH] = "ToolBrush",         [BTN_TOOL_PENCIL] = "ToolPencil",
+       [BTN_TOOL_AIRBRUSH] = "ToolAirbrush",   [BTN_TOOL_FINGER] = "ToolFinger",
+       [BTN_TOOL_MOUSE] = "ToolMouse",         [BTN_TOOL_LENS] = "ToolLens",
+       [BTN_TOUCH] = "Touch",                  [BTN_STYLUS] = "Stylus",
+       [BTN_STYLUS2] = "Stylus2",              [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
+       [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
+       [BTN_GEAR_UP] = "Gear up",              [KEY_OK] = "Ok",
+       [KEY_SELECT] = "Select",                [KEY_GOTO] = "Goto",
+       [KEY_CLEAR] = "Clear",                  [KEY_POWER2] = "Power2",
+       [KEY_OPTION] = "Option",                [KEY_INFO] = "Info",
+       [KEY_TIME] = "Time",                    [KEY_VENDOR] = "Vendor",
+       [KEY_ARCHIVE] = "Archive",              [KEY_PROGRAM] = "Program",
+       [KEY_CHANNEL] = "Channel",              [KEY_FAVORITES] = "Favorites",
+       [KEY_EPG] = "EPG",                      [KEY_PVR] = "PVR",
+       [KEY_MHP] = "MHP",                      [KEY_LANGUAGE] = "Language",
+       [KEY_TITLE] = "Title",                  [KEY_SUBTITLE] = "Subtitle",
+       [KEY_ANGLE] = "Angle",                  [KEY_ZOOM] = "Zoom",
+       [KEY_MODE] = "Mode",                    [KEY_KEYBOARD] = "Keyboard",
+       [KEY_SCREEN] = "Screen",                [KEY_PC] = "PC",
+       [KEY_TV] = "TV",                        [KEY_TV2] = "TV2",
+       [KEY_VCR] = "VCR",                      [KEY_VCR2] = "VCR2",
+       [KEY_SAT] = "Sat",                      [KEY_SAT2] = "Sat2",
+       [KEY_CD] = "CD",                        [KEY_TAPE] = "Tape",
+       [KEY_RADIO] = "Radio",                  [KEY_TUNER] = "Tuner",
+       [KEY_PLAYER] = "Player",                [KEY_TEXT] = "Text",
+       [KEY_DVD] = "DVD",                      [KEY_AUX] = "Aux",
+       [KEY_MP3] = "MP3",                      [KEY_AUDIO] = "Audio",
+       [KEY_VIDEO] = "Video",                  [KEY_DIRECTORY] = "Directory",
+       [KEY_LIST] = "List",                    [KEY_MEMO] = "Memo",
+       [KEY_CALENDAR] = "Calendar",            [KEY_RED] = "Red",
+       [KEY_GREEN] = "Green",                  [KEY_YELLOW] = "Yellow",
+       [KEY_BLUE] = "Blue",                    [KEY_CHANNELUP] = "ChannelUp",
+       [KEY_CHANNELDOWN] = "ChannelDown",      [KEY_FIRST] = "First",
+       [KEY_LAST] = "Last",                    [KEY_AB] = "AB",
+       [KEY_NEXT] = "Next",                    [KEY_RESTART] = "Restart",
+       [KEY_SLOW] = "Slow",                    [KEY_SHUFFLE] = "Shuffle",
+       [KEY_BREAK] = "Break",                  [KEY_PREVIOUS] = "Previous",
+       [KEY_DIGITS] = "Digits",                [KEY_TEEN] = "TEEN",
+       [KEY_TWEN] = "TWEN",                    [KEY_DEL_EOL] = "DeleteEOL",
+       [KEY_DEL_EOS] = "DeleteEOS",            [KEY_INS_LINE] = "InsertLine",
+       [KEY_DEL_LINE] = "DeleteLine",
+       [KEY_SEND] = "Send",                    [KEY_REPLY] = "Reply",
+       [KEY_FORWARDMAIL] = "ForwardMail",      [KEY_SAVE] = "Save",
+       [KEY_DOCUMENTS] = "Documents",
+       [KEY_FN] = "Fn",                        [KEY_FN_ESC] = "Fn+ESC",
+       [KEY_FN_1] = "Fn+1",                    [KEY_FN_2] = "Fn+2",
+       [KEY_FN_B] = "Fn+B",                    [KEY_FN_D] = "Fn+D",
+       [KEY_FN_E] = "Fn+E",                    [KEY_FN_F] = "Fn+F",
+       [KEY_FN_S] = "Fn+S",
+       [KEY_FN_F1] = "Fn+F1",                  [KEY_FN_F2] = "Fn+F2",
+       [KEY_FN_F3] = "Fn+F3",                  [KEY_FN_F4] = "Fn+F4",
+       [KEY_FN_F5] = "Fn+F5",                  [KEY_FN_F6] = "Fn+F6",
+       [KEY_FN_F7] = "Fn+F7",                  [KEY_FN_F8] = "Fn+F8",
+       [KEY_FN_F9] = "Fn+F9",                  [KEY_FN_F10] = "Fn+F10",
+       [KEY_FN_F11] = "Fn+F11",                [KEY_FN_F12] = "Fn+F12",
+       [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
+       [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
+       [KEY_KBDILLUMUP] = "KbdIlluminationUp",
+       [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+};
+
+static char *relatives[REL_MAX + 1] = {
+       [REL_X] = "X",                  [REL_Y] = "Y",
+       [REL_Z] = "Z",                  [REL_HWHEEL] = "HWheel",
+       [REL_DIAL] = "Dial",            [REL_WHEEL] = "Wheel",
+       [REL_MISC] = "Misc",
+};
+
+static char *absolutes[ABS_MAX + 1] = {
+       [ABS_X] = "X",                  [ABS_Y] = "Y",
+       [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
+       [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
+       [ABS_THROTTLE] = "Throttle",    [ABS_RUDDER] = "Rudder",
+       [ABS_WHEEL] = "Wheel",          [ABS_GAS] = "Gas",
+       [ABS_BRAKE] = "Brake",          [ABS_HAT0X] = "Hat0X",
+       [ABS_HAT0Y] = "Hat0Y",          [ABS_HAT1X] = "Hat1X",
+       [ABS_HAT1Y] = "Hat1Y",          [ABS_HAT2X] = "Hat2X",
+       [ABS_HAT2Y] = "Hat2Y",          [ABS_HAT3X] = "Hat3X",
+       [ABS_HAT3Y] = "Hat 3Y",         [ABS_PRESSURE] = "Pressure",
+       [ABS_DISTANCE] = "Distance",    [ABS_TILT_X] = "XTilt",
+       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "Tool Width",
+       [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
+};
+
+static char *misc[MSC_MAX + 1] = {
+       [MSC_SERIAL] = "Serial",        [MSC_PULSELED] = "Pulseled",
+       [MSC_GESTURE] = "Gesture",      [MSC_RAW] = "RawData"
+};
+
+static char *leds[LED_MAX + 1] = {
+       [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
+       [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
+       [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
+       [LED_SUSPEND] = "Suspend",      [LED_MUTE] = "Mute",
+       [LED_MISC] = "Misc",
+};
+
+static char *repeats[REP_MAX + 1] = {
+       [REP_DELAY] = "Delay",          [REP_PERIOD] = "Period"
+};
+
+static char *sounds[SND_MAX + 1] = {
+       [SND_CLICK] = "Click",          [SND_BELL] = "Bell",
+       [SND_TONE] = "Tone"
+};
+
+static char **names[EV_MAX + 1] = {
+       [EV_SYN] = syncs,                       [EV_KEY] = keys,
+       [EV_REL] = relatives,                   [EV_ABS] = absolutes,
+       [EV_MSC] = misc,                        [EV_LED] = leds,
+       [EV_SND] = sounds,                      [EV_REP] = repeats,
+};
+
+static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
+
+       printk("%s.%s", events[type] ? events[type] : "?",
+               names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
+}
diff --git a/include/linux/hid.h b/include/linux/hid.h
new file mode 100644 (file)
index 0000000..ee567ae
--- /dev/null
@@ -0,0 +1,540 @@
+#ifndef __HID_H
+#define __HID_H
+
+/*
+ * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
+/*
+ * USB HID (Human Interface Device) interface class code
+ */
+
+#define USB_INTERFACE_CLASS_HID                3
+
+/*
+ * USB HID interface subclass and protocol codes
+ */
+
+#define USB_INTERFACE_SUBCLASS_BOOT    1
+#define USB_INTERFACE_PROTOCOL_KEYBOARD        1
+#define USB_INTERFACE_PROTOCOL_MOUSE   2
+
+/*
+ * HID class requests
+ */
+
+#define HID_REQ_GET_REPORT             0x01
+#define HID_REQ_GET_IDLE               0x02
+#define HID_REQ_GET_PROTOCOL           0x03
+#define HID_REQ_SET_REPORT             0x09
+#define HID_REQ_SET_IDLE               0x0A
+#define HID_REQ_SET_PROTOCOL           0x0B
+
+/*
+ * HID class descriptor types
+ */
+
+#define HID_DT_HID                     (USB_TYPE_CLASS | 0x01)
+#define HID_DT_REPORT                  (USB_TYPE_CLASS | 0x02)
+#define HID_DT_PHYSICAL                        (USB_TYPE_CLASS | 0x03)
+
+/*
+ * We parse each description item into this structure. Short items data
+ * values are expanded to 32-bit signed int, long items contain a pointer
+ * into the data area.
+ */
+
+struct hid_item {
+       unsigned  format;
+       __u8      size;
+       __u8      type;
+       __u8      tag;
+       union {
+           __u8   u8;
+           __s8   s8;
+           __u16  u16;
+           __s16  s16;
+           __u32  u32;
+           __s32  s32;
+           __u8  *longdata;
+       } data;
+};
+
+/*
+ * HID report item format
+ */
+
+#define HID_ITEM_FORMAT_SHORT  0
+#define HID_ITEM_FORMAT_LONG   1
+
+/*
+ * Special tag indicating long items
+ */
+
+#define HID_ITEM_TAG_LONG      15
+
+/*
+ * HID report descriptor item type (prefix bit 2,3)
+ */
+
+#define HID_ITEM_TYPE_MAIN             0
+#define HID_ITEM_TYPE_GLOBAL           1
+#define HID_ITEM_TYPE_LOCAL            2
+#define HID_ITEM_TYPE_RESERVED         3
+
+/*
+ * HID report descriptor main item tags
+ */
+
+#define HID_MAIN_ITEM_TAG_INPUT                        8
+#define HID_MAIN_ITEM_TAG_OUTPUT               9
+#define HID_MAIN_ITEM_TAG_FEATURE              11
+#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION     10
+#define HID_MAIN_ITEM_TAG_END_COLLECTION       12
+
+/*
+ * HID report descriptor main item contents
+ */
+
+#define HID_MAIN_ITEM_CONSTANT         0x001
+#define HID_MAIN_ITEM_VARIABLE         0x002
+#define HID_MAIN_ITEM_RELATIVE         0x004
+#define HID_MAIN_ITEM_WRAP             0x008
+#define HID_MAIN_ITEM_NONLINEAR                0x010
+#define HID_MAIN_ITEM_NO_PREFERRED     0x020
+#define HID_MAIN_ITEM_NULL_STATE       0x040
+#define HID_MAIN_ITEM_VOLATILE         0x080
+#define HID_MAIN_ITEM_BUFFERED_BYTE    0x100
+
+/*
+ * HID report descriptor collection item types
+ */
+
+#define HID_COLLECTION_PHYSICAL                0
+#define HID_COLLECTION_APPLICATION     1
+#define HID_COLLECTION_LOGICAL         2
+
+/*
+ * HID report descriptor global item tags
+ */
+
+#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE         0
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM    1
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM    2
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM   3
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM   4
+#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT      5
+#define HID_GLOBAL_ITEM_TAG_UNIT               6
+#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE                7
+#define HID_GLOBAL_ITEM_TAG_REPORT_ID          8
+#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT       9
+#define HID_GLOBAL_ITEM_TAG_PUSH               10
+#define HID_GLOBAL_ITEM_TAG_POP                        11
+
+/*
+ * HID report descriptor local item tags
+ */
+
+#define HID_LOCAL_ITEM_TAG_USAGE               0
+#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM       1
+#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM       2
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX    3
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM  4
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM  5
+#define HID_LOCAL_ITEM_TAG_STRING_INDEX                7
+#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM      8
+#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM      9
+#define HID_LOCAL_ITEM_TAG_DELIMITER           10
+
+/*
+ * HID usage tables
+ */
+
+#define HID_USAGE_PAGE         0xffff0000
+
+#define HID_UP_UNDEFINED       0x00000000
+#define HID_UP_GENDESK         0x00010000
+#define HID_UP_SIMULATION      0x00020000
+#define HID_UP_KEYBOARD                0x00070000
+#define HID_UP_LED             0x00080000
+#define HID_UP_BUTTON          0x00090000
+#define HID_UP_ORDINAL         0x000a0000
+#define HID_UP_CONSUMER                0x000c0000
+#define HID_UP_DIGITIZER       0x000d0000
+#define HID_UP_PID             0x000f0000
+#define HID_UP_HPVENDOR         0xff7f0000
+#define HID_UP_MSVENDOR                0xff000000
+#define HID_UP_CUSTOM          0x00ff0000
+#define HID_UP_LOGIVENDOR      0xffbc0000
+
+#define HID_USAGE              0x0000ffff
+
+#define HID_GD_POINTER         0x00010001
+#define HID_GD_MOUSE           0x00010002
+#define HID_GD_JOYSTICK                0x00010004
+#define HID_GD_GAMEPAD         0x00010005
+#define HID_GD_KEYBOARD                0x00010006
+#define HID_GD_KEYPAD          0x00010007
+#define HID_GD_MULTIAXIS       0x00010008
+#define HID_GD_X               0x00010030
+#define HID_GD_Y               0x00010031
+#define HID_GD_Z               0x00010032
+#define HID_GD_RX              0x00010033
+#define HID_GD_RY              0x00010034
+#define HID_GD_RZ              0x00010035
+#define HID_GD_SLIDER          0x00010036
+#define HID_GD_DIAL            0x00010037
+#define HID_GD_WHEEL           0x00010038
+#define HID_GD_HATSWITCH       0x00010039
+#define HID_GD_BUFFER          0x0001003a
+#define HID_GD_BYTECOUNT       0x0001003b
+#define HID_GD_MOTION          0x0001003c
+#define HID_GD_START           0x0001003d
+#define HID_GD_SELECT          0x0001003e
+#define HID_GD_VX              0x00010040
+#define HID_GD_VY              0x00010041
+#define HID_GD_VZ              0x00010042
+#define HID_GD_VBRX            0x00010043
+#define HID_GD_VBRY            0x00010044
+#define HID_GD_VBRZ            0x00010045
+#define HID_GD_VNO             0x00010046
+#define HID_GD_FEATURE         0x00010047
+#define HID_GD_UP              0x00010090
+#define HID_GD_DOWN            0x00010091
+#define HID_GD_RIGHT           0x00010092
+#define HID_GD_LEFT            0x00010093
+
+/*
+ * HID report types --- Ouch! HID spec says 1 2 3!
+ */
+
+#define HID_INPUT_REPORT       0
+#define HID_OUTPUT_REPORT      1
+#define HID_FEATURE_REPORT     2
+
+/*
+ * HID device quirks.
+ */
+
+#define HID_QUIRK_INVERT                       0x00000001
+#define HID_QUIRK_NOTOUCH                      0x00000002
+#define HID_QUIRK_IGNORE                       0x00000004
+#define HID_QUIRK_NOGET                                0x00000008
+#define HID_QUIRK_HIDDEV                       0x00000010
+#define HID_QUIRK_BADPAD                       0x00000020
+#define HID_QUIRK_MULTI_INPUT                  0x00000040
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_7          0x00000080
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x00000100
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x00000200
+#define HID_QUIRK_MIGHTYMOUSE                  0x00000400
+#define HID_QUIRK_CYMOTION                     0x00000800
+#define HID_QUIRK_POWERBOOK_HAS_FN             0x00001000
+#define HID_QUIRK_POWERBOOK_FN_ON              0x00002000
+#define HID_QUIRK_INVERT_HWHEEL                        0x00004000
+#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD        0x00008000
+#define HID_QUIRK_BAD_RELATIVE_KEYS            0x00010000
+
+/*
+ * This is the global environment of the parser. This information is
+ * persistent for main-items. The global environment can be saved and
+ * restored with PUSH/POP statements.
+ */
+
+struct hid_global {
+       unsigned usage_page;
+       __s32    logical_minimum;
+       __s32    logical_maximum;
+       __s32    physical_minimum;
+       __s32    physical_maximum;
+       __s32    unit_exponent;
+       unsigned unit;
+       unsigned report_id;
+       unsigned report_size;
+       unsigned report_count;
+};
+
+/*
+ * This is the local environment. It is persistent up the next main-item.
+ */
+
+#define HID_MAX_DESCRIPTOR_SIZE                4096
+#define HID_MAX_USAGES                 1024
+#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;
+       unsigned delimiter_branch;
+};
+
+/*
+ * This is the collection stack. We climb up the stack to determine
+ * application and function of each field.
+ */
+
+struct hid_collection {
+       unsigned type;
+       unsigned usage;
+       unsigned level;
+};
+
+struct hid_usage {
+       unsigned  hid;                  /* hid usage code */
+       unsigned  collection_index;     /* index into collection array */
+       /* hidinput data */
+       __u16     code;                 /* input driver code */
+       __u8      type;                 /* input driver type */
+       __s8      hat_min;              /* hat switch fun */
+       __s8      hat_max;              /* ditto */
+       __s8      hat_dir;              /* ditto */
+};
+
+struct hid_input;
+
+struct hid_field {
+       unsigned  physical;             /* physical usage for this field */
+       unsigned  logical;              /* logical usage for this field */
+       unsigned  application;          /* application usage for this field */
+       struct hid_usage *usage;        /* usage table for this function */
+       unsigned  maxusage;             /* maximum usage index */
+       unsigned  flags;                /* main-item flags (i.e. volatile,array,constant) */
+       unsigned  report_offset;        /* bit offset in the report */
+       unsigned  report_size;          /* size of this field in the report */
+       unsigned  report_count;         /* number of this field in the report */
+       unsigned  report_type;          /* (input,output,feature) */
+       __s32    *value;                /* last known value(s) */
+       __s32     logical_minimum;
+       __s32     logical_maximum;
+       __s32     physical_minimum;
+       __s32     physical_maximum;
+       __s32     unit_exponent;
+       unsigned  unit;
+       struct hid_report *report;      /* associated report */
+       unsigned index;                 /* index into report->field[] */
+       /* hidinput data */
+       struct hid_input *hidinput;     /* associated input structure */
+       __u16 dpad;                     /* dpad input code */
+};
+
+#define HID_MAX_FIELDS 64
+
+struct hid_report {
+       struct list_head list;
+       unsigned id;                                    /* id of this report */
+       unsigned type;                                  /* report type */
+       struct hid_field *field[HID_MAX_FIELDS];        /* fields of the report */
+       unsigned maxfield;                              /* maximum valid field index */
+       unsigned size;                                  /* size of the report (bits) */
+       struct hid_device *device;                      /* associated device */
+};
+
+struct hid_report_enum {
+       unsigned numbered;
+       struct list_head report_list;
+       struct hid_report *report_id_hash[256];
+};
+
+#define HID_REPORT_TYPES 3
+
+#define HID_MIN_BUFFER_SIZE    64              /* make sure there is at least a packet size of space */
+#define HID_MAX_BUFFER_SIZE    4096            /* 4kb */
+#define HID_CONTROL_FIFO_SIZE  256             /* to init devices with >100 reports */
+#define HID_OUTPUT_FIFO_SIZE   64
+
+struct hid_control_fifo {
+       unsigned char dir;
+       struct hid_report *report;
+};
+
+#define HID_CLAIMED_INPUT      1
+#define HID_CLAIMED_HIDDEV     2
+
+#define HID_CTRL_RUNNING       1
+#define HID_OUT_RUNNING                2
+#define HID_IN_RUNNING         3
+#define HID_RESET_PENDING      4
+#define HID_SUSPENDED          5
+#define HID_CLEAR_HALT         6
+
+struct hid_input {
+       struct list_head list;
+       struct hid_report *report;
+       struct input_dev *input;
+};
+
+struct hid_device {                                                    /* device report descriptor */
+        __u8 *rdesc;
+       unsigned rsize;
+       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 */
+       struct hid_report_enum report_enum[HID_REPORT_TYPES];
+
+       struct usb_device *dev;                                         /* USB device */
+       struct usb_interface *intf;                                     /* USB interface */
+       int ifnum;                                                      /* USB interface number */
+
+       unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+       struct timer_list io_retry;                                     /* Retry timer */
+       unsigned long stop_retry;                                       /* Time to give up, in jiffies */
+       unsigned int retry_delay;                                       /* Delay length in ms */
+       struct work_struct reset_work;                                  /* Task context for resets */
+
+       unsigned int bufsize;                                           /* URB buffer size */
+
+       struct urb *urbin;                                              /* Input URB */
+       char *inbuf;                                                    /* Input buffer */
+       dma_addr_t inbuf_dma;                                           /* Input buffer dma */
+       spinlock_t inlock;                                              /* Input fifo spinlock */
+
+       struct urb *urbctrl;                                            /* Control URB */
+       struct usb_ctrlrequest *cr;                                     /* Control request struct */
+       dma_addr_t cr_dma;                                              /* Control request struct dma */
+       struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];            /* Control fifo */
+       unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
+       char *ctrlbuf;                                                  /* Control buffer */
+       dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
+       spinlock_t ctrllock;                                            /* Control fifo spinlock */
+
+       struct urb *urbout;                                             /* Output URB */
+       struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
+       unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
+       char *outbuf;                                                   /* Output buffer */
+       dma_addr_t outbuf_dma;                                          /* Output buffer dma */
+       spinlock_t outlock;                                             /* Output fifo spinlock */
+
+       unsigned claimed;                                               /* Claimed by hidinput, hiddev? */
+       unsigned quirks;                                                /* Various quirks the device can pull on us */
+
+       struct list_head inputs;                                        /* The list of inputs */
+       void *hiddev;                                                   /* The hiddev structure */
+       int minor;                                                      /* Hiddev minor number */
+
+       wait_queue_head_t wait;                                         /* For sleeping */
+
+       int open;                                                       /* is the device open by anyone? */
+       char name[128];                                                 /* Device name */
+       char phys[64];                                                  /* Device physical location */
+       char uniq[64];                                                  /* Device unique identifier (serial #) */
+
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+       unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
+       unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
+#endif
+};
+
+#define HID_GLOBAL_STACK_SIZE 4
+#define HID_COLLECTION_STACK_SIZE 4
+
+struct hid_parser {
+       struct hid_global     global;
+       struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
+       unsigned              global_stack_ptr;
+       struct hid_local      local;
+       unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
+       unsigned              collection_stack_ptr;
+       struct hid_device    *device;
+};
+
+struct hid_class_descriptor {
+       __u8  bDescriptorType;
+       __u16 wDescriptorLength;
+} __attribute__ ((packed));
+
+struct hid_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u16 bcdHID;
+       __u8  bCountryCode;
+       __u8  bNumDescriptors;
+
+       struct hid_class_descriptor desc[1];
+} __attribute__ ((packed));
+
+#ifdef DEBUG
+#include "hid-debug.h"
+#else
+#define hid_dump_input(a,b)    do { } while (0)
+#define hid_dump_device(c)     do { } while (0)
+#define hid_dump_field(a,b)    do { } while (0)
+#define resolv_usage(a)                do { } while (0)
+#define resolv_event(a,b)      do { } while (0)
+#endif
+
+#ifdef CONFIG_HID
+/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
+/* We ignore a few input applications that are not widely used */
+#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
+extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
+extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
+extern int hidinput_connect(struct hid_device *);
+extern void hidinput_disconnect(struct hid_device *);
+#else
+#define IS_INPUT_APPLICATION(a) (0)
+static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
+static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { }
+static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
+static inline void hidinput_disconnect(struct hid_device *hid) { }
+#endif
+
+int hid_set_field(struct hid_field *, unsigned, __s32);
+int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
+void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
+void hid_output_report(struct hid_report *report, __u8 *data);
+void hid_free_device(struct hid_device *device);
+struct hid_device *hid_parse_report(__u8 *start, unsigned size);
+
+#ifdef CONFIG_HID_FF
+int hid_ff_init(struct hid_device *hid);
+
+int hid_lgff_init(struct hid_device *hid);
+int hid_tmff_init(struct hid_device *hid);
+int hid_zpff_init(struct hid_device *hid);
+#ifdef CONFIG_HID_PID
+int hid_pidff_init(struct hid_device *hid);
+#else
+static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
+#endif
+
+#else
+static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#endif
+#endif
+