igb: support for VF configuration tools
[safe/jmp/linux-2.6] / drivers / hid / hid-core.c
index 397e1b2..eabe5f8 100644 (file)
  * Version Information
  */
 
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
 #define DRIVER_DESC "HID core driver"
 #define DRIVER_LICENSE "GPL"
 
-#ifdef CONFIG_HID_DEBUG
 int hid_debug = 0;
 module_param_named(debug, hid_debug, int, 0600);
-MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
+MODULE_PARM_DESC(debug, "toggle HID debugging messages");
 EXPORT_SYMBOL_GPL(hid_debug);
-#endif
 
 /*
  * Register a new report for a device.
@@ -270,9 +266,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 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;
+       case 1: return item->data.u8;
+       case 2: return item->data.u16;
+       case 4: return item->data.u32;
        }
        return 0;
 }
@@ -280,9 +276,9 @@ static u32 item_udata(struct hid_item *item)
 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;
+       case 1: return item->data.s8;
+       case 2: return item->data.s16;
+       case 4: return item->data.s32;
        }
        return 0;
 }
@@ -294,87 +290,91 @@ static s32 item_sdata(struct hid_item *item)
 static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 {
        switch (item->tag) {
+       case HID_GLOBAL_ITEM_TAG_PUSH:
 
-               case HID_GLOBAL_ITEM_TAG_PUSH:
-
-                       if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
-                               dbg_hid("global enviroment stack overflow\n");
-                               return -1;
-                       }
-
-                       memcpy(parser->global_stack + parser->global_stack_ptr++,
-                               &parser->global, sizeof(struct hid_global));
-                       return 0;
+               if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+                       dbg_hid("global enviroment stack overflow\n");
+                       return -1;
+               }
 
-               case HID_GLOBAL_ITEM_TAG_POP:
+               memcpy(parser->global_stack + parser->global_stack_ptr++,
+                       &parser->global, sizeof(struct hid_global));
+               return 0;
 
-                       if (!parser->global_stack_ptr) {
-                               dbg_hid("global enviroment stack underflow\n");
-                               return -1;
-                       }
+       case HID_GLOBAL_ITEM_TAG_POP:
 
-                       memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
-                               sizeof(struct hid_global));
-                       return 0;
+               if (!parser->global_stack_ptr) {
+                       dbg_hid("global enviroment stack underflow\n");
+                       return -1;
+               }
 
-               case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-                       parser->global.usage_page = item_udata(item);
-                       return 0;
+               memcpy(&parser->global, parser->global_stack +
+                       --parser->global_stack_ptr, sizeof(struct hid_global));
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-                       parser->global.logical_minimum = item_sdata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+               parser->global.usage_page = item_udata(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_LOGICAL_MINIMUM:
+               parser->global.logical_minimum = item_sdata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-                       parser->global.physical_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_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_PHYSICAL_MINIMUM:
+               parser->global.physical_minimum = item_sdata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-                       parser->global.unit_exponent = 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:
-                       parser->global.unit = 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_REPORT_SIZE:
-                       if ((parser->global.report_size = item_udata(item)) > 32) {
-                               dbg_hid("invalid report_size %d\n", parser->global.report_size);
-                               return -1;
-                       }
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_UNIT:
+               parser->global.unit = item_udata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-                       if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-                               dbg_hid("invalid report_count %d\n", parser->global.report_count);
-                               return -1;
-                       }
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+               parser->global.report_size = item_udata(item);
+               if (parser->global.report_size > 32) {
+                       dbg_hid("invalid report_size %d\n",
+                                       parser->global.report_size);
+                       return -1;
+               }
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-                       if ((parser->global.report_id = item_udata(item)) == 0) {
-                               dbg_hid("report_id 0 is invalid\n");
-                               return -1;
-                       }
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+               parser->global.report_count = item_udata(item);
+               if (parser->global.report_count > HID_MAX_USAGES) {
+                       dbg_hid("invalid report_count %d\n",
+                                       parser->global.report_count);
+                       return -1;
+               }
+               return 0;
 
-               default:
-                       dbg_hid("unknown global tag 0x%x\n", item->tag);
+       case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+               parser->global.report_id = item_udata(item);
+               if (parser->global.report_id == 0) {
+                       dbg_hid("report_id 0 is invalid\n");
                        return -1;
+               }
+               return 0;
+
+       default:
+               dbg_hid("unknown global tag 0x%x\n", item->tag);
+               return -1;
        }
 }
 
@@ -395,77 +395,76 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
        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_hid("nested delimiters\n");
-                                       return -1;
-                               }
-                               parser->local.delimiter_depth++;
-                               parser->local.delimiter_branch++;
-                       } else {
-                               if (parser->local.delimiter_depth < 1) {
-                                       dbg_hid("bogus close delimiter\n");
-                                       return -1;
-                               }
-                               parser->local.delimiter_depth--;
+       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_hid("nested delimiters\n");
+                               return -1;
                        }
-                       return 1;
-
-               case HID_LOCAL_ITEM_TAG_USAGE:
-
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg_hid("alternative usage ignored\n");
-                               return 0;
+                       parser->local.delimiter_depth++;
+                       parser->local.delimiter_branch++;
+               } else {
+                       if (parser->local.delimiter_depth < 1) {
+                               dbg_hid("bogus close delimiter\n");
+                               return -1;
                        }
+                       parser->local.delimiter_depth--;
+               }
+               return 1;
 
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
+       case HID_LOCAL_ITEM_TAG_USAGE:
 
-                       return hid_add_usage(parser, data);
+               if (parser->local.delimiter_branch > 1) {
+                       dbg_hid("alternative usage ignored\n");
+                       return 0;
+               }
 
-               case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+               if (item->size <= 2)
+                       data = (parser->global.usage_page << 16) + data;
 
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg_hid("alternative usage ignored\n");
-                               return 0;
-                       }
+               return hid_add_usage(parser, data);
 
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
+       case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
 
-                       parser->local.usage_minimum = data;
+               if (parser->local.delimiter_branch > 1) {
+                       dbg_hid("alternative usage ignored\n");
                        return 0;
+               }
 
-               case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+               if (item->size <= 2)
+                       data = (parser->global.usage_page << 16) + data;
 
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg_hid("alternative usage ignored\n");
-                               return 0;
-                       }
+               parser->local.usage_minimum = data;
+               return 0;
 
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
+       case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
 
-                       for (n = parser->local.usage_minimum; n <= data; n++)
-                               if (hid_add_usage(parser, n)) {
-                                       dbg_hid("hid_add_usage failed\n");
-                                       return -1;
-                               }
+               if (parser->local.delimiter_branch > 1) {
+                       dbg_hid("alternative usage ignored\n");
                        return 0;
+               }
 
-               default:
+               if (item->size <= 2)
+                       data = (parser->global.usage_page << 16) + data;
 
-                       dbg_hid("unknown local item tag 0x%x\n", item->tag);
-                       return 0;
+               for (n = parser->local.usage_minimum; n <= data; n++)
+                       if (hid_add_usage(parser, n)) {
+                               dbg_hid("hid_add_usage failed\n");
+                               return -1;
+                       }
+               return 0;
+
+       default:
+
+               dbg_hid("unknown local item tag 0x%x\n", item->tag);
+               return 0;
        }
        return 0;
 }
@@ -482,24 +481,24 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
        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_hid("unknown main item tag 0x%x\n", item->tag);
-                       ret = 0;
+       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_hid("unknown main item tag 0x%x\n", item->tag);
+               ret = 0;
        }
 
        memset(&parser->local, 0, sizeof(parser->local));       /* Reset the local parser environment */
@@ -595,30 +594,29 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
        item->size = b & 3;
 
        switch (item->size) {
+       case 0:
+               return start;
 
-               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 = get_unaligned_le16(start);
-                       start = (__u8 *)((__le16 *)start + 1);
-                       return start;
-
-               case 3:
-                       item->size++;
-                       if ((end - start) < 4)
-                               return NULL;
-                       item->data.u32 = get_unaligned_le32(start);
-                       start = (__u8 *)((__le32 *)start + 1);
-                       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 = get_unaligned_le16(start);
+               start = (__u8 *)((__le16 *)start + 1);
+               return start;
+
+       case 3:
+               item->size++;
+               if ((end - start) < 4)
+                       return NULL;
+               item->data.u32 = get_unaligned_le32(start);
+               start = (__u8 *)((__le32 *)start + 1);
+               return start;
        }
 
        return NULL;
@@ -713,9 +711,9 @@ EXPORT_SYMBOL_GPL(hid_parse_report);
 static s32 snto32(__u32 value, unsigned n)
 {
        switch (n) {
-               case 8:  return ((__s8)value);
-               case 16: return ((__s16)value);
-               case 32: return ((__s32)value);
+       case 8:  return ((__s8)value);
+       case 16: return ((__s16)value);
+       case 32: return ((__s32)value);
        }
        return value & (1 << (n - 1)) ? value | (-1 << n) : value;
 }
@@ -859,7 +857,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
        struct hid_driver *hdrv = hid->driver;
        int ret;
 
-       hid_dump_input(usage, value);
+       hid_dump_input(hid, usage, value);
 
        if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
                ret = hdrv->event(hid, field, usage, value);
@@ -981,11 +979,10 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
 {
        unsigned size = field->report_size;
 
-       hid_dump_input(field->usage + offset, value);
+       hid_dump_input(field->report->device, field->usage + offset, value);
 
        if (offset >= field->report_count) {
                dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count);
-               hid_dump_field(field, 8);
                return -1;
        }
        if (field->logical_minimum < 0) {
@@ -1067,38 +1064,60 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event);
  * @type: HID report type (HID_*_REPORT)
  * @data: report contents
  * @size: size of data parameter
- * @interrupt: called from atomic?
+ * @interrupt: distinguish between interrupt and control transfers
  *
  * This is data entry for lower layers.
  */
 int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
 {
-       struct hid_report_enum *report_enum = hid->report_enum + type;
-       struct hid_driver *hdrv = hid->driver;
+       struct hid_report_enum *report_enum;
+       struct hid_driver *hdrv;
        struct hid_report *report;
+       char *buf;
        unsigned int i;
        int ret;
 
        if (!hid || !hid->driver)
                return -ENODEV;
+       report_enum = hid->report_enum + type;
+       hdrv = hid->driver;
 
        if (!size) {
                dbg_hid("empty report\n");
                return -1;
        }
 
-       dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+       buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
+
+       if (!buf) {
+               report = hid_get_report(report_enum, data);
+               goto nomem;
+       }
+
+       snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+                       "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+       hid_debug_event(hid, buf);
 
        report = hid_get_report(report_enum, data);
-       if (!report)
+       if (!report) {
+               kfree(buf);
                return -1;
+       }
 
        /* dump the report */
-       dbg_hid("report %d (size %u) = ", report->id, size);
-       for (i = 0; i < size; i++)
-               dbg_hid_line(" %02x", data[i]);
-       dbg_hid_line("\n");
+       snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+                       "report %d (size %u) = ", report->id, size);
+       hid_debug_event(hid, buf);
+       for (i = 0; i < size; i++) {
+               snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+                               " %02x", data[i]);
+               hid_debug_event(hid, buf);
+       }
+       hid_debug_event(hid, "\n");
+
+       kfree(buf);
 
+nomem:
        if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
                ret = hdrv->raw_event(hid, report, data, size);
                if (ret != 0)
@@ -1129,7 +1148,109 @@ static const struct hid_device_id *hid_match_id(struct hid_device *hdev,
        return NULL;
 }
 
+static const struct hid_device_id hid_hiddev_list[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1) },
+       { }
+};
+
+static bool hid_hiddev(struct hid_device *hdev)
+{
+       return !!hid_match_id(hdev, hid_hiddev_list);
+}
+
+int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
+{
+       static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
+               "Joystick", "Gamepad", "Keyboard", "Keypad",
+               "Multi-Axis Controller"
+       };
+       const char *type, *bus;
+       char buf[64];
+       unsigned int i;
+       int len;
+
+       if (hdev->bus != BUS_USB)
+               connect_mask &= ~HID_CONNECT_HIDDEV;
+       if (hid_hiddev(hdev))
+               connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+
+       if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
+                               connect_mask & HID_CONNECT_HIDINPUT_FORCE))
+               hdev->claimed |= HID_CLAIMED_INPUT;
+       if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
+                       !hdev->hiddev_connect(hdev,
+                               connect_mask & HID_CONNECT_HIDDEV_FORCE))
+               hdev->claimed |= HID_CLAIMED_HIDDEV;
+       if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
+               hdev->claimed |= HID_CLAIMED_HIDRAW;
+
+       if (!hdev->claimed) {
+               dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
+                               "hidraw\n");
+               return -ENODEV;
+       }
+
+       if ((hdev->claimed & HID_CLAIMED_INPUT) &&
+                       (connect_mask & HID_CONNECT_FF) && hdev->ff_init)
+               hdev->ff_init(hdev);
+
+       len = 0;
+       if (hdev->claimed & HID_CLAIMED_INPUT)
+               len += sprintf(buf + len, "input");
+       if (hdev->claimed & HID_CLAIMED_HIDDEV)
+               len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
+                               hdev->minor);
+       if (hdev->claimed & HID_CLAIMED_HIDRAW)
+               len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
+                               ((struct hidraw *)hdev->hidraw)->minor);
+
+       type = "Device";
+       for (i = 0; i < hdev->maxcollection; i++) {
+               struct hid_collection *col = &hdev->collection[i];
+               if (col->type == HID_COLLECTION_APPLICATION &&
+                  (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+                  (col->usage & 0xffff) < ARRAY_SIZE(types)) {
+                       type = types[col->usage & 0xffff];
+                       break;
+               }
+       }
+
+       switch (hdev->bus) {
+       case BUS_USB:
+               bus = "USB";
+               break;
+       case BUS_BLUETOOTH:
+               bus = "BLUETOOTH";
+               break;
+       default:
+               bus = "<UNKNOWN>";
+       }
+
+       dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+                       buf, bus, hdev->version >> 8, hdev->version & 0xff,
+                       type, hdev->name, hdev->phys);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hid_connect);
+
+void hid_disconnect(struct hid_device *hdev)
+{
+       if (hdev->claimed & HID_CLAIMED_INPUT)
+               hidinput_disconnect(hdev);
+       if (hdev->claimed & HID_CLAIMED_HIDDEV)
+               hdev->hiddev_disconnect(hdev);
+       if (hdev->claimed & HID_CLAIMED_HIDRAW)
+               hidraw_disconnect(hdev);
+}
+EXPORT_SYMBOL_GPL(hid_disconnect);
+
+/* a list of devices for which there is a specialized driver on HID bus */
 static const struct hid_device_id hid_blacklist[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
@@ -1143,23 +1264,50 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1167,24 +1315,136 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
-
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
        { }
 };
 
+struct hid_dynid {
+       struct list_head list;
+       struct hid_device_id id;
+};
+
+/**
+ * store_new_id - add a new HID device ID to this driver and re-probe devices
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Adds a new dynamic hid device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static ssize_t store_new_id(struct device_driver *drv, const char *buf,
+               size_t count)
+{
+       struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+       struct hid_dynid *dynid;
+       __u32 bus, vendor, product;
+       unsigned long driver_data = 0;
+       int ret;
+
+       ret = sscanf(buf, "%x %x %x %lx",
+                       &bus, &vendor, &product, &driver_data);
+       if (ret < 3)
+               return -EINVAL;
+
+       dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
+       if (!dynid)
+               return -ENOMEM;
+
+       dynid->id.bus = bus;
+       dynid->id.vendor = vendor;
+       dynid->id.product = product;
+       dynid->id.driver_data = driver_data;
+
+       spin_lock(&hdrv->dyn_lock);
+       list_add_tail(&dynid->list, &hdrv->dyn_list);
+       spin_unlock(&hdrv->dyn_lock);
+
+       ret = 0;
+       if (get_driver(&hdrv->driver)) {
+               ret = driver_attach(&hdrv->driver);
+               put_driver(&hdrv->driver);
+       }
+
+       return ret ? : count;
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+
+static void hid_free_dynids(struct hid_driver *hdrv)
+{
+       struct hid_dynid *dynid, *n;
+
+       spin_lock(&hdrv->dyn_lock);
+       list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) {
+               list_del(&dynid->list);
+               kfree(dynid);
+       }
+       spin_unlock(&hdrv->dyn_lock);
+}
+
+static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
+               struct hid_driver *hdrv)
+{
+       struct hid_dynid *dynid;
+
+       spin_lock(&hdrv->dyn_lock);
+       list_for_each_entry(dynid, &hdrv->dyn_list, list) {
+               if (hid_match_one_id(hdev, &dynid->id)) {
+                       spin_unlock(&hdrv->dyn_lock);
+                       return &dynid->id;
+               }
+       }
+       spin_unlock(&hdrv->dyn_lock);
+
+       return hid_match_id(hdev, hdrv->id_table);
+}
+
 static int hid_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
 
-       if (!hid_match_id(hdev, hdrv->id_table))
+       if (!hid_match_device(hdev, hdrv))
                return 0;
 
        /* generic wants all non-blacklisted */
@@ -1203,7 +1463,7 @@ static int hid_device_probe(struct device *dev)
        int ret = 0;
 
        if (!hdev->driver) {
-               id = hid_match_id(hdev, hdrv->id_table);
+               id = hid_match_device(hdev, hdrv);
                if (id == NULL)
                        return -ENODEV;
 
@@ -1213,7 +1473,7 @@ static int hid_device_probe(struct device *dev)
                } else { /* default probe */
                        ret = hid_parse(hdev);
                        if (!ret)
-                               ret = hid_hw_start(hdev);
+                               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
                }
                if (ret)
                        hdev->driver = NULL;
@@ -1269,6 +1529,7 @@ static struct bus_type hid_bus_type = {
        .uevent         = hid_uevent,
 };
 
+/* a list of devices that shouldn't be handled by HID core at all */
 static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
@@ -1283,15 +1544,19 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
@@ -1358,7 +1623,9 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
        { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
@@ -1375,8 +1642,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
@@ -1394,7 +1659,10 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
@@ -1408,6 +1676,43 @@ static const struct hid_device_id hid_ignore_list[] = {
        { }
 };
 
+/**
+ * hid_mouse_ignore_list - mouse devices which should not be handled by the hid layer
+ *
+ * There are composite devices for which we want to ignore only a certain
+ * interface. This is a list of devices for which only the mouse interface will
+ * be ignored. This allows a dedicated driver to take care of the interface.
+ */
+static const struct hid_device_id hid_mouse_ignore_list[] = {
+       /* appletouch driver */
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+       { }
+};
+
 static bool hid_ignore(struct hid_device *hdev)
 {
        switch (hdev->vendor) {
@@ -1422,8 +1727,17 @@ static bool hid_ignore(struct hid_device *hdev)
                                hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
                        return true;
                break;
+       case USB_VENDOR_ID_SOUNDGRAPH:
+               if (hdev->product >= USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST &&
+                   hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
+                       return true;
+               break;
        }
 
+       if (hdev->type == HID_TYPE_USBMOUSE &&
+                       hid_match_id(hdev, hid_mouse_ignore_list))
+               return true;
+
        return !!hid_match_id(hdev, hid_ignore_list);
 }
 
@@ -1440,14 +1754,17 @@ int hid_add_device(struct hid_device *hdev)
        if (hid_ignore(hdev))
                return -ENODEV;
 
-       /* XXX hack, any other cleaner solution < 20 bus_id bytes? */
-       sprintf(hdev->dev.bus_id, "%04X:%04X:%04X.%04X", hdev->bus,
-                       hdev->vendor, hdev->product, atomic_inc_return(&id));
+       /* XXX hack, any other cleaner solution after the driver core
+        * is converted to allow more than 20 bytes as the device name? */
+       dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
+                    hdev->vendor, hdev->product, atomic_inc_return(&id));
 
        ret = device_add(&hdev->dev);
        if (!ret)
                hdev->status |= HID_STAT_ADDED;
 
+       hid_debug_register(hdev, dev_name(&hdev->dev));
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(hid_add_device);
@@ -1484,6 +1801,9 @@ struct hid_device *hid_allocate_device(void)
        for (i = 0; i < HID_REPORT_TYPES; i++)
                INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
 
+       init_waitqueue_head(&hdev->debug_wait);
+       INIT_LIST_HEAD(&hdev->debug_list);
+
        return hdev;
 err:
        put_device(&hdev->dev);
@@ -1495,6 +1815,7 @@ static void hid_remove_device(struct hid_device *hdev)
 {
        if (hdev->status & HID_STAT_ADDED) {
                device_del(&hdev->dev);
+               hid_debug_unregister(hdev);
                hdev->status &= ~HID_STAT_ADDED;
        }
 }
@@ -1517,33 +1838,63 @@ EXPORT_SYMBOL_GPL(hid_destroy_device);
 int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
                const char *mod_name)
 {
+       int ret;
+
        hdrv->driver.name = hdrv->name;
        hdrv->driver.bus = &hid_bus_type;
        hdrv->driver.owner = owner;
        hdrv->driver.mod_name = mod_name;
 
-       return driver_register(&hdrv->driver);
+       INIT_LIST_HEAD(&hdrv->dyn_list);
+       spin_lock_init(&hdrv->dyn_lock);
+
+       ret = driver_register(&hdrv->driver);
+       if (ret)
+               return ret;
+
+       ret = driver_create_file(&hdrv->driver, &driver_attr_new_id);
+       if (ret)
+               driver_unregister(&hdrv->driver);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(__hid_register_driver);
 
 void hid_unregister_driver(struct hid_driver *hdrv)
 {
+       driver_remove_file(&hdrv->driver, &driver_attr_new_id);
        driver_unregister(&hdrv->driver);
+       hid_free_dynids(hdrv);
 }
 EXPORT_SYMBOL_GPL(hid_unregister_driver);
 
-#ifdef CONFIG_HID_COMPAT
-static void hid_compat_load(struct work_struct *ws)
+int hid_check_keys_pressed(struct hid_device *hid)
 {
-       request_module("hid-dummy");
+       struct hid_input *hidinput;
+       int i;
+
+       if (!(hid->claimed & HID_CLAIMED_INPUT))
+               return 0;
+
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+               for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++)
+                       if (hidinput->input->key[i])
+                               return 1;
+       }
+
+       return 0;
 }
-static DECLARE_WORK(hid_compat_work, hid_compat_load);
-#endif
+
+EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
 
 static int __init hid_init(void)
 {
        int ret;
 
+       if (hid_debug)
+               printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n"
+                               "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n");
+
        ret = bus_register(&hid_bus_type);
        if (ret) {
                printk(KERN_ERR "HID: can't register hid bus\n");
@@ -1554,9 +1905,7 @@ static int __init hid_init(void)
        if (ret)
                goto err_bus;
 
-#ifdef CONFIG_HID_COMPAT
-       schedule_work(&hid_compat_work);
-#endif
+       hid_debug_init();
 
        return 0;
 err_bus:
@@ -1567,6 +1916,7 @@ err:
 
 static void __exit hid_exit(void)
 {
+       hid_debug_exit();
        hidraw_exit();
        bus_unregister(&hid_bus_type);
 }
@@ -1574,5 +1924,8 @@ static void __exit hid_exit(void)
 module_init(hid_init);
 module_exit(hid_exit);
 
+MODULE_AUTHOR("Andreas Gal");
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Jiri Kosina");
 MODULE_LICENSE(DRIVER_LICENSE);