Merge branch 'master' into upstream
authorJiri Kosina <jkosina@suse.cz>
Fri, 10 Dec 2010 14:19:18 +0000 (15:19 +0100)
committerJiri Kosina <jkosina@suse.cz>
Fri, 10 Dec 2010 14:19:18 +0000 (15:19 +0100)
1  2 
drivers/hid/hid-core.c
drivers/hid/hid-egalax.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-tmff.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hiddev.c

diff --combined drivers/hid/hid-core.c
@@@ -14,8 -14,6 +14,8 @@@
   * any later version.
   */
  
 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 +
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/init.h>
@@@ -61,8 -59,7 +61,8 @@@ struct hid_report *hid_register_report(
        if (report_enum->report_id_hash[id])
                return report_enum->report_id_hash[id];
  
 -      if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
 +      report = kzalloc(sizeof(struct hid_report), GFP_KERNEL);
 +      if (!report)
                return NULL;
  
        if (id != 0)
@@@ -93,11 -90,8 +93,11 @@@ static struct hid_field *hid_register_f
                return NULL;
        }
  
 -      if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
 -              + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
 +      field = kzalloc((sizeof(struct hid_field) +
 +                       usages * sizeof(struct hid_usage) +
 +                       values * sizeof(unsigned)), GFP_KERNEL);
 +      if (!field)
 +              return NULL;
  
        field->index = report->maxfield++;
        report->field[field->index] = field;
@@@ -178,14 -172,10 +178,14 @@@ static int close_collection(struct hid_
  
  static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
  {
 +      struct hid_collection *collection = parser->device->collection;
        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;
 +
 +      for (n = parser->collection_stack_ptr - 1; n >= 0; n--) {
 +              unsigned index = parser->collection_stack[n];
 +              if (collection[index].type == type)
 +                      return collection[index].usage;
 +      }
        return 0; /* we know nothing about this usage type */
  }
  
@@@ -219,8 -209,7 +219,8 @@@ static int hid_add_field(struct hid_par
        unsigned offset;
        int i;
  
 -      if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
 +      report = hid_register_report(parser->device, report_type, parser->global.report_id);
 +      if (!report) {
                dbg_hid("hid_register_report failed\n");
                return -1;
        }
  
        usages = max_t(int, parser->local.usage_index, parser->global.report_count);
  
 -      if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
 +      field = hid_register_field(report, usages, parser->global.report_count);
 +      if (!field)
                return 0;
  
        field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
@@@ -664,12 -652,13 +664,12 @@@ int hid_parse_report(struct hid_device 
                return -ENOMEM;
        device->rsize = size;
  
 -      parser = vmalloc(sizeof(struct hid_parser));
 +      parser = vzalloc(sizeof(struct hid_parser));
        if (!parser) {
                ret = -ENOMEM;
                goto err;
        }
  
 -      memset(parser, 0, sizeof(struct hid_parser));
        parser->device = device;
  
        end = start + size;
  
                if (dispatch_type[item.type](parser, &item)) {
                        dbg_hid("item %u %u %u %u parsing failed\n",
 -                              item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
 +                              item.format, (unsigned)item.size,
 +                              (unsigned)item.type, (unsigned)item.tag);
                        goto err;
                }
  
@@@ -749,14 -737,13 +749,14 @@@ static u32 s32ton(__s32 value, unsigne
   * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
   */
  
 -static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
 +static __u32 extract(const struct hid_device *hid, __u8 *report,
 +                   unsigned offset, unsigned n)
  {
        u64 x;
  
        if (n > 32)
 -              printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
 -                              n, current->comm);
 +              hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n",
 +                       n, current->comm);
  
        report += offset >> 3;  /* adjust byte index */
        offset &= 7;            /* now only need bit offset into one byte */
   * 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)
 +static void implement(const struct hid_device *hid, __u8 *report,
 +                    unsigned offset, unsigned n, __u32 value)
  {
        u64 x;
        u64 m = (1ULL << n) - 1;
  
        if (n > 32)
 -              printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
 -                              n, current->comm);
 +              hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n",
 +                       __func__, n, current->comm);
  
        if (value > m)
 -              printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
 -                              value, current->comm);
 +              hid_warn(hid, "%s() called with too large value %d! (%s)\n",
 +                       __func__, value, current->comm);
        WARN_ON(value > m);
        value &= m;
  
   * Search an array for a value.
   */
  
 -static __inline__ int search(__s32 *array, __s32 value, unsigned n)
 +static int search(__s32 *array, __s32 value, unsigned n)
  {
        while (n--) {
                if (*array++ == value)
@@@ -901,22 -887,18 +901,22 @@@ static void hid_input_field(struct hid_
        __s32 max = field->logical_maximum;
        __s32 *value;
  
 -      if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
 +      value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC);
 +      if (!value)
                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);
 +              value[n] = min < 0 ?
 +                      snto32(extract(hid, data, offset + n * size, size),
 +                             size) :
 +                      extract(hid, 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;
 +              /* Ignore report if ErrorRollOver */
 +              if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
 +                  value[n] >= min && value[n] <= max &&
 +                  field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
 +                      goto exit;
        }
  
        for (n = 0; n < count; n++) {
@@@ -946,8 -928,7 +946,8 @@@ exit
   * Output the field into the report.
   */
  
 -static void hid_output_field(struct hid_field *field, __u8 *data)
 +static void hid_output_field(const struct hid_device *hid,
 +                           struct hid_field *field, __u8 *data)
  {
        unsigned count = field->report_count;
        unsigned offset = field->report_offset;
  
        for (n = 0; n < count; n++) {
                if (field->logical_minimum < 0) /* signed values */
 -                      implement(data, offset + n * size, size, s32ton(field->value[n], size));
 +                      implement(hid, data, offset + n * size, size,
 +                                s32ton(field->value[n], size));
                else                            /* unsigned values */
 -                      implement(data, offset + n * size, size, field->value[n]);
 +                      implement(hid, data, offset + n * size, size,
 +                                field->value[n]);
        }
  }
  
@@@ -977,7 -956,7 +977,7 @@@ void hid_output_report(struct hid_repor
  
        memset(data, 0, ((report->size - 1) >> 3) + 1);
        for (n = 0; n < report->maxfield; n++)
 -              hid_output_field(report->field[n], data);
 +              hid_output_field(report->device, report->field[n], data);
  }
  EXPORT_SYMBOL_GPL(hid_output_report);
  
@@@ -1190,7 -1169,8 +1190,7 @@@ int hid_connect(struct hid_device *hdev
                hdev->claimed |= HID_CLAIMED_HIDRAW;
  
        if (!hdev->claimed) {
 -              dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
 -                              "hidraw\n");
 +              hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n");
                return -ENODEV;
        }
  
                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);
 +      hid_info(hdev, "%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;
  }
@@@ -1250,7 -1230,7 +1250,7 @@@ void hid_disconnect(struct hid_device *
  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[] = {
 +static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
        { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
        { 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_WELLSPRING4_ANSI) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_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_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
        { 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_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
        { 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_THRUSTMASTER, 0xb651) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
@@@ -1523,9 -1496,9 +1524,9 @@@ static int hid_bus_match(struct device 
        if (!hid_match_device(hdev, hdrv))
                return 0;
  
 -      /* generic wants all non-blacklisted */
 +      /* generic wants all that don't have specialized driver */
        if (!strncmp(hdrv->name, "generic-", 8))
 -              return !hid_match_id(hdev, hid_blacklist);
 +              return !hid_match_id(hdev, hid_have_special_driver);
  
        return 1;
  }
@@@ -1784,12 -1757,6 +1785,12 @@@ static const struct hid_device_id hid_m
        { 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_WELLSPRING4_ANSI) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_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) },
        { }
@@@ -1814,6 -1781,11 +1815,11 @@@ static bool hid_ignore(struct hid_devic
                    hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
                        return true;
                break;
+       case USB_VENDOR_ID_HANWANG:
+               if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
+                   hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
+                       return true;
+               break;
        }
  
        if (hdev->type == HID_TYPE_USBMOUSE &&
@@@ -1976,12 -1948,12 +1982,12 @@@ 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");
 +              pr_warn("hid_debug is now used solely for parser and driver debugging.\n"
 +                      "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");
 +              pr_err("can't register hid bus\n");
                goto err;
        }
  
diff --combined drivers/hid/hid-egalax.c
@@@ -221,9 -221,9 +221,9 @@@ static int egalax_probe(struct hid_devi
        struct egalax_data *td;
        struct hid_report *report;
  
-       td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL);
+       td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
        if (!td) {
 -              dev_err(&hdev->dev, "cannot allocate eGalax data\n");
 +              hid_err(hdev, "cannot allocate eGalax data\n");
                return -ENOMEM;
        }
        hid_set_drvdata(hdev, td);
diff --combined drivers/hid/hid-ids.h
  #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI  0x0236
  #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO   0x0237
  #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS   0x0238
 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI  0x023f
 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO   0x0240
 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS   0x0241
 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO  0x0243
 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS  0x0244
  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
  #define USB_VENDOR_ID_CHICONY         0x04f2
  #define USB_DEVICE_ID_CHICONY_TACTICAL_PAD    0x0418
  #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH     0xb19d
 +#define USB_DEVICE_ID_CHICONY_WIRELESS        0x0618
  
  #define USB_VENDOR_ID_CIDC            0x1677
  
  #define USB_VENDOR_ID_ELO             0x04E7
  #define USB_DEVICE_ID_ELO_TS2700      0x0020
  
 +#define USB_VENDOR_ID_EMS             0x2006
 +#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
 +
  #define USB_VENDOR_ID_ESSENTIAL_REALITY       0x0d7f
  #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
  
  #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
  #define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
  
+ #define USB_VENDOR_ID_HANWANG         0x0b57
+ #define USB_DEVICE_ID_HANWANG_TABLET_FIRST    0x5000
+ #define USB_DEVICE_ID_HANWANG_TABLET_LAST     0x8fff
  #define USB_VENDOR_ID_HAPP            0x078b
  #define USB_DEVICE_ID_UGCI_DRIVING    0x0010
  #define USB_DEVICE_ID_UGCI_FLYING     0x0020
diff --combined drivers/hid/hid-input.c
@@@ -68,39 -68,52 +68,52 @@@ static const struct 
  #define map_key_clear(c)      hid_map_usage_clear(hidinput, usage, &bit, \
                &max, EV_KEY, (c))
  
- static inline int match_scancode(unsigned int code, unsigned int scancode)
+ static bool match_scancode(struct hid_usage *usage,
+                          unsigned int cur_idx, unsigned int scancode)
  {
-       if (scancode == 0)
-               return 1;
-       return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
+       return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
  }
  
- static inline int match_keycode(unsigned int code, unsigned int keycode)
+ static bool match_keycode(struct hid_usage *usage,
+                         unsigned int cur_idx, unsigned int keycode)
  {
-       if (keycode == 0)
-               return 1;
+       /*
+        * We should exclude unmapped usages when doing lookup by keycode.
+        */
+       return (usage->type == EV_KEY && usage->code == keycode);
+ }
  
-       return code == keycode;
+ static bool match_index(struct hid_usage *usage,
+                       unsigned int cur_idx, unsigned int idx)
+ {
+       return cur_idx == idx;
  }
  
+ typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
+                               unsigned int cur_idx, unsigned int val);
  static struct hid_usage *hidinput_find_key(struct hid_device *hid,
-                                          unsigned int scancode,
-                                          unsigned int keycode)
+                                          hid_usage_cmp_t match,
+                                          unsigned int value,
+                                          unsigned int *usage_idx)
  {
-       int i, j, k;
+       unsigned int i, j, k, cur_idx = 0;
        struct hid_report *report;
        struct hid_usage *usage;
  
        for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
                list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
                        for (i = 0; i < report->maxfield; i++) {
-                               for ( j = 0; j < report->field[i]->maxusage; j++) {
+                               for (j = 0; j < report->field[i]->maxusage; j++) {
                                        usage = report->field[i]->usage + j;
-                                       if (usage->type == EV_KEY &&
-                                               match_scancode(usage->hid, scancode) &&
-                                               match_keycode(usage->code, keycode))
-                                               return usage;
+                                       if (usage->type == EV_KEY || usage->type == 0) {
+                                               if (match(usage, cur_idx, value)) {
+                                                       if (usage_idx)
+                                                               *usage_idx = cur_idx;
+                                                       return usage;
+                                               }
+                                               cur_idx++;
+                                       }
                                }
                        }
                }
        return NULL;
  }
  
+ static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
+                                       const struct input_keymap_entry *ke,
+                                       unsigned int *index)
+ {
+       struct hid_usage *usage;
+       unsigned int scancode;
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+               usage = hidinput_find_key(hid, match_index, ke->index, index);
+       else if (input_scancode_to_scalar(ke, &scancode) == 0)
+               usage = hidinput_find_key(hid, match_scancode, scancode, index);
+       else
+               usage = NULL;
+       return usage;
+ }
  static int hidinput_getkeycode(struct input_dev *dev,
-                              unsigned int scancode, unsigned int *keycode)
+                              struct input_keymap_entry *ke)
  {
        struct hid_device *hid = input_get_drvdata(dev);
        struct hid_usage *usage;
+       unsigned int scancode, index;
  
-       usage = hidinput_find_key(hid, scancode, 0);
+       usage = hidinput_locate_usage(hid, ke, &index);
        if (usage) {
-               *keycode = usage->code;
+               ke->keycode = usage->type == EV_KEY ?
+                               usage->code : KEY_RESERVED;
+               ke->index = index;
+               scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
+               ke->len = sizeof(scancode);
+               memcpy(ke->scancode, &scancode, sizeof(scancode));
                return 0;
        }
        return -EINVAL;
  }
  
  static int hidinput_setkeycode(struct input_dev *dev,
-                              unsigned int scancode, unsigned int keycode)
+                              const struct input_keymap_entry *ke,
+                              unsigned int *old_keycode)
  {
        struct hid_device *hid = input_get_drvdata(dev);
        struct hid_usage *usage;
-       int old_keycode;
  
-       usage = hidinput_find_key(hid, scancode, 0);
+       usage = hidinput_locate_usage(hid, ke, NULL);
        if (usage) {
-               old_keycode = usage->code;
-               usage->code = keycode;
+               *old_keycode = usage->type == EV_KEY ?
+                               usage->code : KEY_RESERVED;
+               usage->code = ke->keycode;
  
-               clear_bit(old_keycode, dev->keybit);
+               clear_bit(*old_keycode, dev->keybit);
                set_bit(usage->code, dev->keybit);
-               dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
-               /* Set the keybit for the old keycode if the old keycode is used
-                * by another key */
-               if (hidinput_find_key (hid, 0, old_keycode))
-                       set_bit(old_keycode, dev->keybit);
+               dbg_hid("Assigned keycode %d to HID usage code %x\n",
+                       usage->code, usage->hid);
+               /*
+                * Set the keybit for the old keycode if the old keycode is used
+                * by another key
+                */
+               if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
+                       set_bit(*old_keycode, dev->keybit);
  
                return 0;
        }
   *
   * as seen in the HID specification v1.11 6.2.2.7 Global Items.
   *
-  * Only exponent 1 length units are processed. Centimeters are converted to
-  * inches. Degrees are converted to radians.
+  * Only exponent 1 length units are processed. Centimeters and inches are
+  * converted to millimeters. Degrees are converted to radians.
   */
  static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
  {
         */
        if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
                if (field->unit == 0x11) {              /* If centimeters */
-                       /* Convert to inches */
-                       prev = logical_extents;
-                       logical_extents *= 254;
-                       if (logical_extents < prev)
+                       /* Convert to millimeters */
+                       unit_exponent += 1;
+               } else if (field->unit == 0x13) {       /* If inches */
+                       /* Convert to millimeters */
+                       prev = physical_extents;
+                       physical_extents *= 254;
+                       if (physical_extents < prev)
                                return 0;
-                       unit_exponent += 2;
-               } else if (field->unit != 0x13) {       /* If not inches */
+                       unit_exponent -= 1;
+               } else {
                        return 0;
                }
        } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
@@@ -772,14 -817,14 +817,14 @@@ static int hidinput_open(struct input_d
  {
        struct hid_device *hid = input_get_drvdata(dev);
  
 -      return hid->ll_driver->open(hid);
 +      return hid_hw_open(hid);
  }
  
  static void hidinput_close(struct input_dev *dev)
  {
        struct hid_device *hid = input_get_drvdata(dev);
  
 -      hid->ll_driver->close(hid);
 +      hid_hw_close(hid);
  }
  
  /*
@@@ -826,7 -871,7 +871,7 @@@ int hidinput_connect(struct hid_device 
                                if (!hidinput || !input_dev) {
                                        kfree(hidinput);
                                        input_free_device(input_dev);
 -                                      err_hid("Out of memory during hid input probe");
 +                                      hid_err(hid, "Out of memory during hid input probe\n");
                                        goto out_unwind;
                                }
  
                                        hid->ll_driver->hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
-                               input_dev->setkeycode = hidinput_setkeycode;
-                               input_dev->getkeycode = hidinput_getkeycode;
+                               input_dev->setkeycode_new = hidinput_setkeycode;
+                               input_dev->getkeycode_new = hidinput_getkeycode;
  
                                input_dev->name = hid->name;
                                input_dev->phys = hid->phys;
diff --combined drivers/hid/hid-tmff.c
@@@ -151,23 -151,28 +151,23 @@@ static int tmff_init(struct hid_device 
                        switch (field->usage[0].hid) {
                        case THRUSTMASTER_USAGE_FF:
                                if (field->report_count < 2) {
 -                                      dev_warn(&hid->dev, "ignoring FF field "
 -                                              "with report_count < 2\n");
 +                                      hid_warn(hid, "ignoring FF field with report_count < 2\n");
                                        continue;
                                }
  
                                if (field->logical_maximum ==
                                                field->logical_minimum) {
 -                                      dev_warn(&hid->dev, "ignoring FF field "
 -                                                      "with logical_maximum "
 -                                                      "== logical_minimum\n");
 +                                      hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n");
                                        continue;
                                }
  
                                if (tmff->report && tmff->report != report) {
 -                                      dev_warn(&hid->dev, "ignoring FF field "
 -                                                      "in other report\n");
 +                                      hid_warn(hid, "ignoring FF field in other report\n");
                                        continue;
                                }
  
                                if (tmff->ff_field && tmff->ff_field != field) {
 -                                      dev_warn(&hid->dev, "ignoring "
 -                                                      "duplicate FF field\n");
 +                                      hid_warn(hid, "ignoring duplicate FF field\n");
                                        continue;
                                }
  
                                break;
  
                        default:
 -                              dev_warn(&hid->dev, "ignoring unknown output "
 -                                              "usage %08x\n",
 -                                              field->usage[0].hid);
 +                              hid_warn(hid, "ignoring unknown output usage %08x\n",
 +                                       field->usage[0].hid);
                                continue;
                        }
                }
        }
  
        if (!tmff->report) {
 -              dev_err(&hid->dev, "can't find FF field in output reports\n");
 +              hid_err(hid, "can't find FF field in output reports\n");
                error = -ENODEV;
                goto fail;
        }
        if (error)
                goto fail;
  
 -      dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
 -                      "Verituse <zinx@epicsol.org>");
 +      hid_info(hid, "force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>\n");
        return 0;
  
  fail:
@@@ -217,13 -224,13 +217,13 @@@ static int tm_probe(struct hid_device *
  
        ret = hid_parse(hdev);
        if (ret) {
 -              dev_err(&hdev->dev, "parse failed\n");
 +              hid_err(hdev, "parse failed\n");
                goto err;
        }
  
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
 -              dev_err(&hdev->dev, "hw start failed\n");
 +              hid_err(hdev, "hw start failed\n");
                goto err;
        }
  
@@@ -249,6 -256,8 +249,8 @@@ static const struct hid_device_id tm_de
                .driver_data = (unsigned long)ff_joystick },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654),   /* FGT Force Feedback Wheel */
                .driver_data = (unsigned long)ff_joystick },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a),   /* F430 Force Feedback Wheel */
+               .driver_data = (unsigned long)ff_joystick },
        { }
  };
  MODULE_DEVICE_TABLE(hid, tm_devices);
diff --combined drivers/hid/hidraw.c
@@@ -19,8 -19,6 +19,8 @@@
   * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   */
  
 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 +
  #include <linux/fs.h>
  #include <linux/module.h>
  #include <linux/errno.h>
@@@ -34,7 -32,6 +34,6 @@@
  #include <linux/hid.h>
  #include <linux/mutex.h>
  #include <linux/sched.h>
- #include <linux/smp_lock.h>
  
  #include <linux/hidraw.h>
  
@@@ -125,15 -122,15 +124,15 @@@ static ssize_t hidraw_write(struct fil
        }
  
        if (count > HID_MAX_BUFFER_SIZE) {
 -              printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
 -                              task_pid_nr(current));
 +              hid_warn(dev, "pid %d passed too large report\n",
 +                       task_pid_nr(current));
                ret = -EINVAL;
                goto out;
        }
  
        if (count < 2) {
 -              printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
 -                              task_pid_nr(current));
 +              hid_warn(dev, "pid %d passed too short report\n",
 +                       task_pid_nr(current));
                ret = -EINVAL;
                goto out;
        }
@@@ -195,13 -192,15 +194,13 @@@ static int hidraw_open(struct inode *in
  
        dev = hidraw_table[minor];
        if (!dev->open++) {
 -              if (dev->hid->ll_driver->power) {
 -                      err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
 -                      if (err < 0)
 -                              goto out_unlock;
 -              }
 -              err = dev->hid->ll_driver->open(dev->hid);
 +              err = hid_hw_power(dev->hid, PM_HINT_FULLON);
 +              if (err < 0)
 +                      goto out_unlock;
 +
 +              err = hid_hw_open(dev->hid);
                if (err < 0) {
 -                      if (dev->hid->ll_driver->power)
 -                              dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
 +                      hid_hw_power(dev->hid, PM_HINT_NORMAL);
                        dev->open--;
                }
        }
@@@ -230,8 -229,9 +229,8 @@@ static int hidraw_release(struct inode 
        dev = hidraw_table[minor];
        if (!--dev->open) {
                if (list->hidraw->exist) {
 -                      if (dev->hid->ll_driver->power)
 -                              dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
 -                      dev->hid->ll_driver->close(dev->hid);
 +                      hid_hw_power(dev->hid, PM_HINT_NORMAL);
 +                      hid_hw_close(dev->hid);
                } else {
                        kfree(list->hidraw);
                }
@@@ -433,7 -433,7 +432,7 @@@ void hidraw_disconnect(struct hid_devic
        device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
  
        if (hidraw->open) {
 -              hid->ll_driver->close(hid);
 +              hid_hw_close(hid);
                wake_up_interruptible(&hidraw->wait);
        } else {
                kfree(hidraw);
@@@ -452,7 -452,7 +451,7 @@@ int __init hidraw_init(void
        hidraw_major = MAJOR(dev_id);
  
        if (result < 0) {
 -              printk(KERN_WARNING "hidraw: can't get major number\n");
 +              pr_warn("can't get major number\n");
                result = 0;
                goto out;
        }
@@@ -29,7 -29,6 +29,6 @@@
  #include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/init.h>
- #include <linux/smp_lock.h>
  #include <linux/input.h>
  #include <linux/usb.h>
  #include <linux/hid.h>
@@@ -586,168 -585,163 +585,168 @@@ static long hiddev_ioctl(struct file *f
  {
        struct hiddev_list *list = file->private_data;
        struct hiddev *hiddev = list->hiddev;
 -      struct hid_device *hid = hiddev->hid;
 -      struct usb_device *dev;
 +      struct hid_device *hid;
        struct hiddev_collection_info cinfo;
        struct hiddev_report_info rinfo;
        struct hiddev_field_info finfo;
        struct hiddev_devinfo dinfo;
        struct hid_report *report;
        struct hid_field *field;
 -      struct usbhid_device *usbhid = hid->driver_data;
        void __user *user_arg = (void __user *)arg;
 -      int i, r;
 -      
 +      int i, r = -EINVAL;
 +
        /* Called without BKL by compat methods so no BKL taken */
  
 -      /* FIXME: Who or what stop this racing with a disconnect ?? */
 -      if (!hiddev->exist || !hid)
 -              return -EIO;
 +      mutex_lock(&hiddev->existancelock);
 +      if (!hiddev->exist) {
 +              r = -ENODEV;
 +              goto ret_unlock;
 +      }
  
 -      dev = hid_to_usb_dev(hid);
 +      hid = hiddev->hid;
  
        switch (cmd) {
  
        case HIDIOCGVERSION:
 -              return put_user(HID_VERSION, (int __user *)arg);
 +              r = put_user(HID_VERSION, (int __user *)arg) ?
 +                      -EFAULT : 0;
 +              break;
  
        case HIDIOCAPPLICATION:
                if (arg < 0 || arg >= hid->maxapplication)
 -                      return -EINVAL;
 +                      break;
  
                for (i = 0; i < hid->maxcollection; i++)
                        if (hid->collection[i].type ==
                            HID_COLLECTION_APPLICATION && arg-- == 0)
                                break;
  
 -              if (i == hid->maxcollection)
 -                      return -EINVAL;
 -
 -              return hid->collection[i].usage;
 +              if (i < hid->maxcollection)
 +                      r = hid->collection[i].usage;
 +              break;
  
        case HIDIOCGDEVINFO:
 -              dinfo.bustype = BUS_USB;
 -              dinfo.busnum = dev->bus->busnum;
 -              dinfo.devnum = dev->devnum;
 -              dinfo.ifnum = usbhid->ifnum;
 -              dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
 -              dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
 -              dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
 -              dinfo.num_applications = hid->maxapplication;
 -              if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
 -                      return -EFAULT;
 -
 -              return 0;
 +              {
 +                      struct usb_device *dev = hid_to_usb_dev(hid);
 +                      struct usbhid_device *usbhid = hid->driver_data;
 +
 +                      dinfo.bustype = BUS_USB;
 +                      dinfo.busnum = dev->bus->busnum;
 +                      dinfo.devnum = dev->devnum;
 +                      dinfo.ifnum = usbhid->ifnum;
 +                      dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
 +                      dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
 +                      dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
 +                      dinfo.num_applications = hid->maxapplication;
 +
 +                      r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
 +                              -EFAULT : 0;
 +                      break;
 +              }
  
        case HIDIOCGFLAG:
 -              if (put_user(list->flags, (int __user *)arg))
 -                      return -EFAULT;
 -
 -              return 0;
 +              r = put_user(list->flags, (int __user *)arg) ?
 +                      -EFAULT : 0;
 +              break;
  
        case HIDIOCSFLAG:
                {
                        int newflags;
 -                      if (get_user(newflags, (int __user *)arg))
 -                              return -EFAULT;
 +
 +                      if (get_user(newflags, (int __user *)arg)) {
 +                              r = -EFAULT;
 +                              break;
 +                      }
  
                        if ((newflags & ~HIDDEV_FLAGS) != 0 ||
                            ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
                             (newflags & HIDDEV_FLAG_UREF) == 0))
 -                              return -EINVAL;
 +                              break;
  
                        list->flags = newflags;
  
 -                      return 0;
 +                      r = 0;
 +                      break;
                }
  
        case HIDIOCGSTRING:
 -              mutex_lock(&hiddev->existancelock);
 -              if (hiddev->exist)
 -                      r = hiddev_ioctl_string(hiddev, cmd, user_arg);
 -              else
 -                      r = -ENODEV;
 -              mutex_unlock(&hiddev->existancelock);
 -              return r;
 +              r = hiddev_ioctl_string(hiddev, cmd, user_arg);
 +              break;
  
        case HIDIOCINITREPORT:
 -              mutex_lock(&hiddev->existancelock);
 -              if (!hiddev->exist) {
 -                      mutex_unlock(&hiddev->existancelock);
 -                      return -ENODEV;
 -              }
                usbhid_init_reports(hid);
 -              mutex_unlock(&hiddev->existancelock);
 -
 -              return 0;
 +              r = 0;
 +              break;
  
        case HIDIOCGREPORT:
 -              if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
 -                      return -EFAULT;
 +              if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
 +                      r = -EFAULT;
 +                      break;
 +              }
  
                if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
 -                      return -EINVAL;
 +                      break;
  
 -              if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 -                      return -EINVAL;
 +              report = hiddev_lookup_report(hid, &rinfo);
 +              if (report == NULL)
 +                      break;
  
 -              mutex_lock(&hiddev->existancelock);
 -              if (hiddev->exist) {
 -                      usbhid_submit_report(hid, report, USB_DIR_IN);
 -                      usbhid_wait_io(hid);
 -              }
 -              mutex_unlock(&hiddev->existancelock);
 +              usbhid_submit_report(hid, report, USB_DIR_IN);
 +              usbhid_wait_io(hid);
  
 -              return 0;
 +              r = 0;
 +              break;
  
        case HIDIOCSREPORT:
 -              if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
 -                      return -EFAULT;
 +              if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
 +                      r = -EFAULT;
 +                      break;
 +              }
  
                if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
 -                      return -EINVAL;
 +                      break;
  
 -              if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 -                      return -EINVAL;
 +              report = hiddev_lookup_report(hid, &rinfo);
 +              if (report == NULL)
 +                      break;
  
 -              mutex_lock(&hiddev->existancelock);
 -              if (hiddev->exist) {
 -                      usbhid_submit_report(hid, report, USB_DIR_OUT);
 -                      usbhid_wait_io(hid);
 -              }
 -              mutex_unlock(&hiddev->existancelock);
 +              usbhid_submit_report(hid, report, USB_DIR_OUT);
 +              usbhid_wait_io(hid);
  
 -              return 0;
 +              r = 0;
 +              break;
  
        case HIDIOCGREPORTINFO:
 -              if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
 -                      return -EFAULT;
 +              if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
 +                      r = -EFAULT;
 +                      break;
 +              }
  
 -              if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 -                      return -EINVAL;
 +              report = hiddev_lookup_report(hid, &rinfo);
 +              if (report == NULL)
 +                      break;
  
                rinfo.num_fields = report->maxfield;
  
 -              if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
 -                      return -EFAULT;
 -
 -              return 0;
 +              r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
 +                      -EFAULT : 0;
 +              break;
  
        case HIDIOCGFIELDINFO:
 -              if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
 -                      return -EFAULT;
 +              if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
 +                      r = -EFAULT;
 +                      break;
 +              }
 +
                rinfo.report_type = finfo.report_type;
                rinfo.report_id = finfo.report_id;
 -              if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 -                      return -EINVAL;
 +
 +              report = hiddev_lookup_report(hid, &rinfo);
 +              if (report == NULL)
 +                      break;
  
                if (finfo.field_index >= report->maxfield)
 -                      return -EINVAL;
 +                      break;
  
                field = report->field[finfo.field_index];
                memset(&finfo, 0, sizeof(finfo));
                finfo.unit_exponent = field->unit_exponent;
                finfo.unit = field->unit;
  
 -              if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
 -                      return -EFAULT;
 -
 -              return 0;
 +              r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
 +                      -EFAULT : 0;
 +              break;
  
        case HIDIOCGUCODE:
                /* fall through */
        case HIDIOCGUSAGES:
        case HIDIOCSUSAGES:
        case HIDIOCGCOLLECTIONINDEX:
 -              mutex_lock(&hiddev->existancelock);
 -              if (hiddev->exist)
 -                      r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
 -              else
 -                      r = -ENODEV;
 -              mutex_unlock(&hiddev->existancelock);
 -              return r;
 +              r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
 +              break;
  
        case HIDIOCGCOLLECTIONINFO:
 -              if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
 -                      return -EFAULT;
 +              if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
 +                      r = -EFAULT;
 +                      break;
 +              }
  
                if (cinfo.index >= hid->maxcollection)
 -                      return -EINVAL;
 +                      break;
  
                cinfo.type = hid->collection[cinfo.index].type;
                cinfo.usage = hid->collection[cinfo.index].usage;
                cinfo.level = hid->collection[cinfo.index].level;
  
 -              if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
 -                      return -EFAULT;
 -              return 0;
 +              r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
 +                      -EFAULT : 0;
 +              break;
  
        default:
 -
                if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
 -                      return -EINVAL;
 +                      break;
  
                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
                        int len;
 -                      if (!hid->name)
 -                              return 0;
 +
 +                      if (!hid->name) {
 +                              r = 0;
 +                              break;
 +                      }
 +
                        len = strlen(hid->name) + 1;
                        if (len > _IOC_SIZE(cmd))
                                 len = _IOC_SIZE(cmd);
 -                      return copy_to_user(user_arg, hid->name, len) ?
 +                      r = copy_to_user(user_arg, hid->name, len) ?
                                -EFAULT : len;
 +                      break;
                }
  
                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
                        int len;
 -                      if (!hid->phys)
 -                              return 0;
 +
 +                      if (!hid->phys) {
 +                              r = 0;
 +                              break;
 +                      }
 +
                        len = strlen(hid->phys) + 1;
                        if (len > _IOC_SIZE(cmd))
                                len = _IOC_SIZE(cmd);
 -                      return copy_to_user(user_arg, hid->phys, len) ?
 +                      r = copy_to_user(user_arg, hid->phys, len) ?
                                -EFAULT : len;
 +                      break;
                }
        }
 -      return -EINVAL;
 +
 +ret_unlock:
 +      mutex_unlock(&hiddev->existancelock);
 +      return r;
  }
  
  #ifdef CONFIG_COMPAT
@@@ -906,7 -892,7 +905,7 @@@ int hiddev_connect(struct hid_device *h
        hiddev->exist = 1;
        retval = usb_register_dev(usbhid->intf, &hiddev_class);
        if (retval) {
 -              err_hid("Not able to get a minor for this device.");
 +              hid_err(hid, "Not able to get a minor for this device\n");
                hid->hiddev = NULL;
                kfree(hiddev);
                return -1;