diff options
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r-- | drivers/hid/hid-input.c | 228 |
1 files changed, 222 insertions, 6 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index f333139d1a48..9333d692a786 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/hid.h> | 32 | #include <linux/hid.h> |
33 | #include <linux/hid-debug.h> | 33 | #include <linux/hid-debug.h> |
34 | 34 | ||
35 | #include "hid-ids.h" | ||
36 | |||
35 | #define unk KEY_UNKNOWN | 37 | #define unk KEY_UNKNOWN |
36 | 38 | ||
37 | static const unsigned char hid_keyboard[256] = { | 39 | static const unsigned char hid_keyboard[256] = { |
@@ -271,6 +273,161 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) | |||
271 | return logical_extents / physical_extents; | 273 | return logical_extents / physical_extents; |
272 | } | 274 | } |
273 | 275 | ||
276 | #ifdef CONFIG_HID_BATTERY_STRENGTH | ||
277 | static enum power_supply_property hidinput_battery_props[] = { | ||
278 | POWER_SUPPLY_PROP_PRESENT, | ||
279 | POWER_SUPPLY_PROP_ONLINE, | ||
280 | POWER_SUPPLY_PROP_CAPACITY, | ||
281 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
282 | POWER_SUPPLY_PROP_STATUS | ||
283 | }; | ||
284 | |||
285 | #define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */ | ||
286 | #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ | ||
287 | |||
288 | static const struct hid_device_id hid_battery_quirks[] = { | ||
289 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, | ||
290 | USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), | ||
291 | HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, | ||
292 | {} | ||
293 | }; | ||
294 | |||
295 | static unsigned find_battery_quirk(struct hid_device *hdev) | ||
296 | { | ||
297 | unsigned quirks = 0; | ||
298 | const struct hid_device_id *match; | ||
299 | |||
300 | match = hid_match_id(hdev, hid_battery_quirks); | ||
301 | if (match != NULL) | ||
302 | quirks = match->driver_data; | ||
303 | |||
304 | return quirks; | ||
305 | } | ||
306 | |||
307 | static int hidinput_get_battery_property(struct power_supply *psy, | ||
308 | enum power_supply_property prop, | ||
309 | union power_supply_propval *val) | ||
310 | { | ||
311 | struct hid_device *dev = container_of(psy, struct hid_device, battery); | ||
312 | int ret = 0; | ||
313 | __u8 buf[2] = {}; | ||
314 | |||
315 | switch (prop) { | ||
316 | case POWER_SUPPLY_PROP_PRESENT: | ||
317 | case POWER_SUPPLY_PROP_ONLINE: | ||
318 | val->intval = 1; | ||
319 | break; | ||
320 | |||
321 | case POWER_SUPPLY_PROP_CAPACITY: | ||
322 | ret = dev->hid_get_raw_report(dev, dev->battery_report_id, | ||
323 | buf, sizeof(buf), | ||
324 | dev->battery_report_type); | ||
325 | |||
326 | if (ret != 2) { | ||
327 | if (ret >= 0) | ||
328 | ret = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | if (dev->battery_min < dev->battery_max && | ||
333 | buf[1] >= dev->battery_min && | ||
334 | buf[1] <= dev->battery_max) | ||
335 | val->intval = (100 * (buf[1] - dev->battery_min)) / | ||
336 | (dev->battery_max - dev->battery_min); | ||
337 | break; | ||
338 | |||
339 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
340 | val->strval = dev->name; | ||
341 | break; | ||
342 | |||
343 | case POWER_SUPPLY_PROP_STATUS: | ||
344 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
345 | break; | ||
346 | |||
347 | default: | ||
348 | ret = -EINVAL; | ||
349 | break; | ||
350 | } | ||
351 | |||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) | ||
356 | { | ||
357 | struct power_supply *battery = &dev->battery; | ||
358 | int ret; | ||
359 | unsigned quirks; | ||
360 | s32 min, max; | ||
361 | |||
362 | if (field->usage->hid != HID_DC_BATTERYSTRENGTH) | ||
363 | return false; /* no match */ | ||
364 | |||
365 | if (battery->name != NULL) | ||
366 | goto out; /* already initialized? */ | ||
367 | |||
368 | battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq); | ||
369 | if (battery->name == NULL) | ||
370 | goto out; | ||
371 | |||
372 | battery->type = POWER_SUPPLY_TYPE_BATTERY; | ||
373 | battery->properties = hidinput_battery_props; | ||
374 | battery->num_properties = ARRAY_SIZE(hidinput_battery_props); | ||
375 | battery->use_for_apm = 0; | ||
376 | battery->get_property = hidinput_get_battery_property; | ||
377 | |||
378 | quirks = find_battery_quirk(dev); | ||
379 | |||
380 | hid_dbg(dev, "device %x:%x:%x %d quirks %d\n", | ||
381 | dev->bus, dev->vendor, dev->product, dev->version, quirks); | ||
382 | |||
383 | min = field->logical_minimum; | ||
384 | max = field->logical_maximum; | ||
385 | |||
386 | if (quirks & HID_BATTERY_QUIRK_PERCENT) { | ||
387 | min = 0; | ||
388 | max = 100; | ||
389 | } | ||
390 | |||
391 | if (quirks & HID_BATTERY_QUIRK_FEATURE) | ||
392 | report_type = HID_FEATURE_REPORT; | ||
393 | |||
394 | dev->battery_min = min; | ||
395 | dev->battery_max = max; | ||
396 | dev->battery_report_type = report_type; | ||
397 | dev->battery_report_id = field->report->id; | ||
398 | |||
399 | ret = power_supply_register(&dev->dev, battery); | ||
400 | if (ret != 0) { | ||
401 | hid_warn(dev, "can't register power supply: %d\n", ret); | ||
402 | kfree(battery->name); | ||
403 | battery->name = NULL; | ||
404 | } | ||
405 | |||
406 | out: | ||
407 | return true; | ||
408 | } | ||
409 | |||
410 | static void hidinput_cleanup_battery(struct hid_device *dev) | ||
411 | { | ||
412 | if (!dev->battery.name) | ||
413 | return; | ||
414 | |||
415 | power_supply_unregister(&dev->battery); | ||
416 | kfree(dev->battery.name); | ||
417 | dev->battery.name = NULL; | ||
418 | } | ||
419 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ | ||
420 | static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, | ||
421 | struct hid_field *field) | ||
422 | { | ||
423 | return false; | ||
424 | } | ||
425 | |||
426 | static void hidinput_cleanup_battery(struct hid_device *dev) | ||
427 | { | ||
428 | } | ||
429 | #endif /* CONFIG_HID_BATTERY_STRENGTH */ | ||
430 | |||
274 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, | 431 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, |
275 | struct hid_usage *usage) | 432 | struct hid_usage *usage) |
276 | { | 433 | { |
@@ -629,6 +786,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
629 | } | 786 | } |
630 | break; | 787 | break; |
631 | 788 | ||
789 | case HID_UP_GENDEVCTRLS: | ||
790 | if (hidinput_setup_battery(device, HID_INPUT_REPORT, field)) | ||
791 | goto ignore; | ||
792 | else | ||
793 | goto unknown; | ||
794 | break; | ||
795 | |||
632 | case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ | 796 | case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ |
633 | set_bit(EV_REP, input->evbit); | 797 | set_bit(EV_REP, input->evbit); |
634 | switch (usage->hid & HID_USAGE) { | 798 | switch (usage->hid & HID_USAGE) { |
@@ -822,6 +986,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
822 | return; | 986 | return; |
823 | } | 987 | } |
824 | 988 | ||
989 | /* Ignore out-of-range values as per HID specification, section 5.10 */ | ||
990 | if (value < field->logical_minimum || value > field->logical_maximum) { | ||
991 | dbg_hid("Ignoring out-of-range value %x\n", value); | ||
992 | return; | ||
993 | } | ||
994 | |||
825 | /* report the usage code as scancode if the key status has changed */ | 995 | /* report the usage code as scancode if the key status has changed */ |
826 | if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) | 996 | if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) |
827 | input_event(input, EV_MSC, MSC_SCAN, usage->hid); | 997 | input_event(input, EV_MSC, MSC_SCAN, usage->hid); |
@@ -861,6 +1031,48 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int | |||
861 | } | 1031 | } |
862 | EXPORT_SYMBOL_GPL(hidinput_find_field); | 1032 | EXPORT_SYMBOL_GPL(hidinput_find_field); |
863 | 1033 | ||
1034 | struct hid_field *hidinput_get_led_field(struct hid_device *hid) | ||
1035 | { | ||
1036 | struct hid_report *report; | ||
1037 | struct hid_field *field; | ||
1038 | int i, j; | ||
1039 | |||
1040 | list_for_each_entry(report, | ||
1041 | &hid->report_enum[HID_OUTPUT_REPORT].report_list, | ||
1042 | list) { | ||
1043 | for (i = 0; i < report->maxfield; i++) { | ||
1044 | field = report->field[i]; | ||
1045 | for (j = 0; j < field->maxusage; j++) | ||
1046 | if (field->usage[j].type == EV_LED) | ||
1047 | return field; | ||
1048 | } | ||
1049 | } | ||
1050 | return NULL; | ||
1051 | } | ||
1052 | EXPORT_SYMBOL_GPL(hidinput_get_led_field); | ||
1053 | |||
1054 | unsigned int hidinput_count_leds(struct hid_device *hid) | ||
1055 | { | ||
1056 | struct hid_report *report; | ||
1057 | struct hid_field *field; | ||
1058 | int i, j; | ||
1059 | unsigned int count = 0; | ||
1060 | |||
1061 | list_for_each_entry(report, | ||
1062 | &hid->report_enum[HID_OUTPUT_REPORT].report_list, | ||
1063 | list) { | ||
1064 | for (i = 0; i < report->maxfield; i++) { | ||
1065 | field = report->field[i]; | ||
1066 | for (j = 0; j < field->maxusage; j++) | ||
1067 | if (field->usage[j].type == EV_LED && | ||
1068 | field->value[j]) | ||
1069 | count += 1; | ||
1070 | } | ||
1071 | } | ||
1072 | return count; | ||
1073 | } | ||
1074 | EXPORT_SYMBOL_GPL(hidinput_count_leds); | ||
1075 | |||
864 | static int hidinput_open(struct input_dev *dev) | 1076 | static int hidinput_open(struct input_dev *dev) |
865 | { | 1077 | { |
866 | struct hid_device *hid = input_get_drvdata(dev); | 1078 | struct hid_device *hid = input_get_drvdata(dev); |
@@ -882,15 +1094,17 @@ static void report_features(struct hid_device *hid) | |||
882 | struct hid_report *rep; | 1094 | struct hid_report *rep; |
883 | int i, j; | 1095 | int i, j; |
884 | 1096 | ||
885 | if (!drv->feature_mapping) | ||
886 | return; | ||
887 | |||
888 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | 1097 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
889 | list_for_each_entry(rep, &rep_enum->report_list, list) | 1098 | list_for_each_entry(rep, &rep_enum->report_list, list) |
890 | for (i = 0; i < rep->maxfield; i++) | 1099 | for (i = 0; i < rep->maxfield; i++) |
891 | for (j = 0; j < rep->field[i]->maxusage; j++) | 1100 | for (j = 0; j < rep->field[i]->maxusage; j++) { |
892 | drv->feature_mapping(hid, rep->field[i], | 1101 | /* Verify if Battery Strength feature is available */ |
893 | rep->field[i]->usage + j); | 1102 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); |
1103 | |||
1104 | if (drv->feature_mapping) | ||
1105 | drv->feature_mapping(hid, rep->field[i], | ||
1106 | rep->field[i]->usage + j); | ||
1107 | } | ||
894 | } | 1108 | } |
895 | 1109 | ||
896 | /* | 1110 | /* |
@@ -1010,6 +1224,8 @@ void hidinput_disconnect(struct hid_device *hid) | |||
1010 | { | 1224 | { |
1011 | struct hid_input *hidinput, *next; | 1225 | struct hid_input *hidinput, *next; |
1012 | 1226 | ||
1227 | hidinput_cleanup_battery(hid); | ||
1228 | |||
1013 | list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { | 1229 | list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { |
1014 | list_del(&hidinput->list); | 1230 | list_del(&hidinput->list); |
1015 | input_unregister_device(hidinput->input); | 1231 | input_unregister_device(hidinput->input); |