summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-core.c')
-rw-r--r--drivers/hid/hid-core.c126
1 files changed, 83 insertions, 43 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 3f9673d94da9..d678cf3d33d5 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -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>
@@ -59,7 +61,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
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)
@@ -90,8 +93,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
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;
@@ -172,10 +178,14 @@ static int close_collection(struct hid_parser *parser)
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 */
}
@@ -209,7 +219,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
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;
}
@@ -227,7 +238,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
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);
@@ -652,13 +664,12 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
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;
@@ -672,7 +683,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
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;
}
@@ -737,13 +749,14 @@ static u32 s32ton(__s32 value, unsigned n)
* 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 */
@@ -760,18 +773,19 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
* 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;
@@ -788,7 +802,7 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
* 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)
@@ -887,18 +901,22 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
__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++) {
@@ -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;
@@ -937,9 +956,11 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
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]);
}
}
@@ -956,7 +977,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
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);
@@ -1169,8 +1190,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
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;
}
@@ -1210,9 +1230,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
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;
}
@@ -1230,7 +1250,7 @@ void hid_disconnect(struct hid_device *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[] = {
+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) },
@@ -1276,6 +1296,12 @@ static const struct hid_device_id hid_blacklist[] = {
{ 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) },
@@ -1286,17 +1312,21 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ 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_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_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ 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) },
@@ -1304,14 +1334,17 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ 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_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
{ 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_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ 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) },
@@ -1372,6 +1405,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
@@ -1393,6 +1427,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ 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) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
@@ -1499,9 +1534,9 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
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;
}
@@ -1611,7 +1646,6 @@ static const struct hid_device_id hid_ignore_list[] = {
{ 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_ETT, USB_DEVICE_ID_TC4UM) },
- { 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
@@ -1761,6 +1795,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ 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) },
{ }
@@ -1952,12 +1992,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;
}