13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * Copyright (c) 2000-2001 Vojtech Pavlik 43d0407baSopenharmony_ci * Copyright (c) 2006-2010 Jiri Kosina 53d0407baSopenharmony_ci * 63d0407baSopenharmony_ci * HID to Linux Input mapping 73d0407baSopenharmony_ci */ 83d0407baSopenharmony_ci 93d0407baSopenharmony_ci/* 103d0407baSopenharmony_ci * 113d0407baSopenharmony_ci * Should you need to contact me, the author, you can do so either by 123d0407baSopenharmony_ci * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 133d0407baSopenharmony_ci * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 143d0407baSopenharmony_ci */ 153d0407baSopenharmony_ci 163d0407baSopenharmony_ci#include <linux/module.h> 173d0407baSopenharmony_ci#include <linux/slab.h> 183d0407baSopenharmony_ci#include <linux/kernel.h> 193d0407baSopenharmony_ci 203d0407baSopenharmony_ci#include <linux/hid.h> 213d0407baSopenharmony_ci#include <linux/hid-debug.h> 223d0407baSopenharmony_ci 233d0407baSopenharmony_ci#include "hid-ids.h" 243d0407baSopenharmony_ci 253d0407baSopenharmony_ci#define unk KEY_UNKNOWN 263d0407baSopenharmony_ci#define HID_FIELD_UNIT_CENTIMETERS 0x11 273d0407baSopenharmony_ci#define HID_FIELD_UNIT_INCHES 0x13 283d0407baSopenharmony_ci#define HID_FIELD_UNIT_INCHES_MUL 254 293d0407baSopenharmony_ci#define HID_FIELD_UNIT_DEGREES 0x14 303d0407baSopenharmony_ci#define HID_FIELD_UNIT_DEGREES_MUL 573 313d0407baSopenharmony_ci#define HID_FIELD_UNIT_RADIANS 0x12 323d0407baSopenharmony_ci#define HID_LOGICAL_EXT_MUL 10 333d0407baSopenharmony_ci#define HID_PHYSICAL_EXT_MUL 10 343d0407baSopenharmony_ci#define HID_BATTERY_CAP_MUL 100 353d0407baSopenharmony_ci#define HID_KMALLOC_DEFAULT_SIZE 4 363d0407baSopenharmony_ci 373d0407baSopenharmony_cistatic const unsigned char hid_keyboard[256] = { 383d0407baSopenharmony_ci 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 393d0407baSopenharmony_ci 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 403d0407baSopenharmony_ci 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 413d0407baSopenharmony_ci 67, 68, 87, 88, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69, 98, 55, 74, 78, 423d0407baSopenharmony_ci 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 433d0407baSopenharmony_ci 189, 190, 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, 136, 113, 115, 114, unk, unk, 443d0407baSopenharmony_ci unk, 121, unk, 89, 93, 124, 92, 94, 95, unk, unk, unk, 122, 123, 90, 91, 85, unk, unk, unk, unk, unk, 453d0407baSopenharmony_ci unk, unk, 111, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, 463d0407baSopenharmony_ci unk, unk, unk, unk, unk, unk, 179, 180, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, 473d0407baSopenharmony_ci unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, unk, 111, unk, unk, unk, 483d0407baSopenharmony_ci unk, unk, unk, unk, 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, 114, 113, 150, 158, 493d0407baSopenharmony_ci 159, 128, 136, 177, 178, 176, 142, 152, 173, 140, unk, unk, unk, unk}; 503d0407baSopenharmony_ci 513d0407baSopenharmony_cistatic const struct { 523d0407baSopenharmony_ci __s32 x; 533d0407baSopenharmony_ci __s32 y; 543d0407baSopenharmony_ci} hid_hat_to_axis[] = {{0, 0}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}}; 553d0407baSopenharmony_ci 563d0407baSopenharmony_ci#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c)) 573d0407baSopenharmony_ci#define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c)) 583d0407baSopenharmony_ci#define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c)) 593d0407baSopenharmony_ci#define map_led(c) hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c)) 603d0407baSopenharmony_ci 613d0407baSopenharmony_ci#define map_abs_clear(c) hid_map_usage_clear(hidinput, usage, &bit, &max, EV_ABS, (c)) 623d0407baSopenharmony_ci#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, &max, EV_KEY, (c)) 633d0407baSopenharmony_ci 643d0407baSopenharmony_cistatic bool match_scancode(struct hid_usage *usage, unsigned int cur_idx, unsigned int scancode) 653d0407baSopenharmony_ci{ 663d0407baSopenharmony_ci return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode; 673d0407baSopenharmony_ci} 683d0407baSopenharmony_ci 693d0407baSopenharmony_cistatic bool match_keycode(struct hid_usage *usage, unsigned int cur_idx, unsigned int keycode) 703d0407baSopenharmony_ci{ 713d0407baSopenharmony_ci /* 723d0407baSopenharmony_ci * We should exclude unmapped usages when doing lookup by keycode. 733d0407baSopenharmony_ci */ 743d0407baSopenharmony_ci return (usage->type == EV_KEY && usage->code == keycode); 753d0407baSopenharmony_ci} 763d0407baSopenharmony_ci 773d0407baSopenharmony_cistatic bool match_index(struct hid_usage *usage, unsigned int cur_idx, unsigned int idx) 783d0407baSopenharmony_ci{ 793d0407baSopenharmony_ci return cur_idx == idx; 803d0407baSopenharmony_ci} 813d0407baSopenharmony_ci 823d0407baSopenharmony_citypedef bool (*hid_usage_cmp_t)(struct hid_usage *usage, unsigned int cur_idx, unsigned int val); 833d0407baSopenharmony_ci 843d0407baSopenharmony_cistatic struct hid_usage *hidinput_find_key(struct hid_device *hid, hid_usage_cmp_t match, unsigned int value, 853d0407baSopenharmony_ci unsigned int *usage_idx) 863d0407baSopenharmony_ci{ 873d0407baSopenharmony_ci unsigned int i, j, k, cur_idx = 0; 883d0407baSopenharmony_ci struct hid_report *report; 893d0407baSopenharmony_ci struct hid_usage *usage; 903d0407baSopenharmony_ci 913d0407baSopenharmony_ci for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { 923d0407baSopenharmony_ci list_for_each_entry(report, &hid->report_enum[k].report_list, list) 933d0407baSopenharmony_ci { 943d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 953d0407baSopenharmony_ci for (j = 0; j < report->field[i]->maxusage; j++) { 963d0407baSopenharmony_ci usage = report->field[i]->usage + j; 973d0407baSopenharmony_ci if (usage->type == EV_KEY || usage->type == 0) { 983d0407baSopenharmony_ci if (match(usage, cur_idx, value)) { 993d0407baSopenharmony_ci if (usage_idx) { 1003d0407baSopenharmony_ci *usage_idx = cur_idx; 1013d0407baSopenharmony_ci } 1023d0407baSopenharmony_ci return usage; 1033d0407baSopenharmony_ci } 1043d0407baSopenharmony_ci cur_idx++; 1053d0407baSopenharmony_ci } 1063d0407baSopenharmony_ci } 1073d0407baSopenharmony_ci } 1083d0407baSopenharmony_ci } 1093d0407baSopenharmony_ci } 1103d0407baSopenharmony_ci return NULL; 1113d0407baSopenharmony_ci} 1123d0407baSopenharmony_ci 1133d0407baSopenharmony_cistatic struct hid_usage *hidinput_locate_usage(struct hid_device *hid, const struct input_keymap_entry *ke, 1143d0407baSopenharmony_ci unsigned int *index) 1153d0407baSopenharmony_ci{ 1163d0407baSopenharmony_ci struct hid_usage *usage; 1173d0407baSopenharmony_ci unsigned int scancode; 1183d0407baSopenharmony_ci 1193d0407baSopenharmony_ci if (ke->flags & INPUT_KEYMAP_BY_INDEX) { 1203d0407baSopenharmony_ci usage = hidinput_find_key(hid, match_index, ke->index, index); 1213d0407baSopenharmony_ci } else if (input_scancode_to_scalar(ke, &scancode) == 0) { 1223d0407baSopenharmony_ci usage = hidinput_find_key(hid, match_scancode, scancode, index); 1233d0407baSopenharmony_ci } else { 1243d0407baSopenharmony_ci usage = NULL; 1253d0407baSopenharmony_ci } 1263d0407baSopenharmony_ci 1273d0407baSopenharmony_ci return usage; 1283d0407baSopenharmony_ci} 1293d0407baSopenharmony_ci 1303d0407baSopenharmony_cistatic int hidinput_getkeycode(struct input_dev *dev, struct input_keymap_entry *ke) 1313d0407baSopenharmony_ci{ 1323d0407baSopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 1333d0407baSopenharmony_ci struct hid_usage *usage; 1343d0407baSopenharmony_ci unsigned int scancode, index; 1353d0407baSopenharmony_ci 1363d0407baSopenharmony_ci usage = hidinput_locate_usage(hid, ke, &index); 1373d0407baSopenharmony_ci if (usage) { 1383d0407baSopenharmony_ci ke->keycode = usage->type == EV_KEY ? usage->code : KEY_RESERVED; 1393d0407baSopenharmony_ci ke->index = index; 1403d0407baSopenharmony_ci scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE); 1413d0407baSopenharmony_ci ke->len = sizeof(scancode); 1423d0407baSopenharmony_ci memcpy(ke->scancode, &scancode, sizeof(scancode)); 1433d0407baSopenharmony_ci return 0; 1443d0407baSopenharmony_ci } 1453d0407baSopenharmony_ci 1463d0407baSopenharmony_ci return -EINVAL; 1473d0407baSopenharmony_ci} 1483d0407baSopenharmony_ci 1493d0407baSopenharmony_cistatic int hidinput_setkeycode(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *old_keycode) 1503d0407baSopenharmony_ci{ 1513d0407baSopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 1523d0407baSopenharmony_ci struct hid_usage *usage; 1533d0407baSopenharmony_ci 1543d0407baSopenharmony_ci usage = hidinput_locate_usage(hid, ke, NULL); 1553d0407baSopenharmony_ci if (usage) { 1563d0407baSopenharmony_ci *old_keycode = usage->type == EV_KEY ? usage->code : KEY_RESERVED; 1573d0407baSopenharmony_ci usage->code = ke->keycode; 1583d0407baSopenharmony_ci 1593d0407baSopenharmony_ci clear_bit(*old_keycode, dev->keybit); 1603d0407baSopenharmony_ci set_bit(usage->code, dev->keybit); 1613d0407baSopenharmony_ci dbg_hid("Assigned keycode %d to HID usage code %x\n", usage->code, usage->hid); 1623d0407baSopenharmony_ci 1633d0407baSopenharmony_ci /* 1643d0407baSopenharmony_ci * Set the keybit for the old keycode if the old keycode is used 1653d0407baSopenharmony_ci * by another key 1663d0407baSopenharmony_ci */ 1673d0407baSopenharmony_ci if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL)) { 1683d0407baSopenharmony_ci set_bit(*old_keycode, dev->keybit); 1693d0407baSopenharmony_ci } 1703d0407baSopenharmony_ci 1713d0407baSopenharmony_ci return 0; 1723d0407baSopenharmony_ci } 1733d0407baSopenharmony_ci 1743d0407baSopenharmony_ci return -EINVAL; 1753d0407baSopenharmony_ci} 1763d0407baSopenharmony_ci 1773d0407baSopenharmony_ci/** 1783d0407baSopenharmony_ci * hidinput_calc_abs_res - calculate an absolute axis resolution 1793d0407baSopenharmony_ci * @field: the HID report field to calculate resolution for 1803d0407baSopenharmony_ci * @code: axis code 1813d0407baSopenharmony_ci * 1823d0407baSopenharmony_ci * The formula is: 1833d0407baSopenharmony_ci * (logical_maximum - logical_minimum) 1843d0407baSopenharmony_ci * resolution = ---------------------------------------------------------- 1853d0407baSopenharmony_ci * (physical_maximum - physical_minimum) * 10 ^ unit_exponent 1863d0407baSopenharmony_ci * 1873d0407baSopenharmony_ci * as seen in the HID specification v1.11 6.2.2.7 Global Items. 1883d0407baSopenharmony_ci * 1893d0407baSopenharmony_ci * Only exponent 1 length units are processed. Centimeters and inches are 1903d0407baSopenharmony_ci * converted to millimeters. Degrees are converted to radians. 1913d0407baSopenharmony_ci */ 1923d0407baSopenharmony_ci__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) 1933d0407baSopenharmony_ci{ 1943d0407baSopenharmony_ci __s32 unit_exponent = field->unit_exponent; 1953d0407baSopenharmony_ci __s32 logical_extents = field->logical_maximum - field->logical_minimum; 1963d0407baSopenharmony_ci __s32 physical_extents = field->physical_maximum - field->physical_minimum; 1973d0407baSopenharmony_ci __s32 prev; 1983d0407baSopenharmony_ci 1993d0407baSopenharmony_ci /* Check if the extents are sane */ 2003d0407baSopenharmony_ci if (logical_extents <= 0 || physical_extents <= 0) { 2013d0407baSopenharmony_ci return 0; 2023d0407baSopenharmony_ci } 2033d0407baSopenharmony_ci 2043d0407baSopenharmony_ci /* 2053d0407baSopenharmony_ci * Verify and convert units. 2063d0407baSopenharmony_ci * See HID specification v1.11 6.2.2.7 Global Items for unit decoding 2073d0407baSopenharmony_ci */ 2083d0407baSopenharmony_ci switch (code) { 2093d0407baSopenharmony_ci case ABS_X: 2103d0407baSopenharmony_ci case ABS_Y: 2113d0407baSopenharmony_ci case ABS_Z: 2123d0407baSopenharmony_ci case ABS_MT_POSITION_X: 2133d0407baSopenharmony_ci case ABS_MT_POSITION_Y: 2143d0407baSopenharmony_ci case ABS_MT_TOOL_X: 2153d0407baSopenharmony_ci case ABS_MT_TOOL_Y: 2163d0407baSopenharmony_ci case ABS_MT_TOUCH_MAJOR: 2173d0407baSopenharmony_ci case ABS_MT_TOUCH_MINOR: 2183d0407baSopenharmony_ci if (field->unit == HID_FIELD_UNIT_CENTIMETERS) { /* If centimeters */ 2193d0407baSopenharmony_ci /* Convert to millimeters */ 2203d0407baSopenharmony_ci unit_exponent += 1; 2213d0407baSopenharmony_ci } else if (field->unit == HID_FIELD_UNIT_INCHES) { /* If inches */ 2223d0407baSopenharmony_ci /* Convert to millimeters */ 2233d0407baSopenharmony_ci prev = physical_extents; 2243d0407baSopenharmony_ci physical_extents *= HID_FIELD_UNIT_INCHES_MUL; 2253d0407baSopenharmony_ci if (physical_extents < prev) { 2263d0407baSopenharmony_ci return 0; 2273d0407baSopenharmony_ci } 2283d0407baSopenharmony_ci unit_exponent -= 1; 2293d0407baSopenharmony_ci } else { 2303d0407baSopenharmony_ci return 0; 2313d0407baSopenharmony_ci } 2323d0407baSopenharmony_ci break; 2333d0407baSopenharmony_ci 2343d0407baSopenharmony_ci case ABS_RX: 2353d0407baSopenharmony_ci case ABS_RY: 2363d0407baSopenharmony_ci case ABS_RZ: 2373d0407baSopenharmony_ci case ABS_WHEEL: 2383d0407baSopenharmony_ci case ABS_TILT_X: 2393d0407baSopenharmony_ci case ABS_TILT_Y: 2403d0407baSopenharmony_ci if (field->unit == HID_FIELD_UNIT_DEGREES) { /* If degrees */ 2413d0407baSopenharmony_ci /* Convert to radians */ 2423d0407baSopenharmony_ci prev = logical_extents; 2433d0407baSopenharmony_ci logical_extents *= HID_FIELD_UNIT_DEGREES_MUL; 2443d0407baSopenharmony_ci if (logical_extents < prev) { 2453d0407baSopenharmony_ci return 0; 2463d0407baSopenharmony_ci } 2473d0407baSopenharmony_ci unit_exponent += 1; 2483d0407baSopenharmony_ci } else if (field->unit != HID_FIELD_UNIT_RADIANS) { /* If not radians */ 2493d0407baSopenharmony_ci return 0; 2503d0407baSopenharmony_ci } 2513d0407baSopenharmony_ci break; 2523d0407baSopenharmony_ci 2533d0407baSopenharmony_ci default: 2543d0407baSopenharmony_ci return 0; 2553d0407baSopenharmony_ci } 2563d0407baSopenharmony_ci 2573d0407baSopenharmony_ci /* Apply negative unit exponent */ 2583d0407baSopenharmony_ci for (; unit_exponent < 0; unit_exponent++) { 2593d0407baSopenharmony_ci prev = logical_extents; 2603d0407baSopenharmony_ci logical_extents *= HID_LOGICAL_EXT_MUL; 2613d0407baSopenharmony_ci if (logical_extents < prev) { 2623d0407baSopenharmony_ci return 0; 2633d0407baSopenharmony_ci } 2643d0407baSopenharmony_ci } 2653d0407baSopenharmony_ci /* Apply positive unit exponent */ 2663d0407baSopenharmony_ci for (; unit_exponent > 0; unit_exponent--) { 2673d0407baSopenharmony_ci prev = physical_extents; 2683d0407baSopenharmony_ci physical_extents *= HID_PHYSICAL_EXT_MUL; 2693d0407baSopenharmony_ci if (physical_extents < prev) { 2703d0407baSopenharmony_ci return 0; 2713d0407baSopenharmony_ci } 2723d0407baSopenharmony_ci } 2733d0407baSopenharmony_ci 2743d0407baSopenharmony_ci /* Calculate resolution */ 2753d0407baSopenharmony_ci return DIV_ROUND_CLOSEST(logical_extents, physical_extents); 2763d0407baSopenharmony_ci} 2773d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_calc_abs_res); 2783d0407baSopenharmony_ci 2793d0407baSopenharmony_ci#ifdef CONFIG_HID_BATTERY_STRENGTH 2803d0407baSopenharmony_cistatic enum power_supply_property hidinput_battery_props[] = { 2813d0407baSopenharmony_ci POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CAPACITY, 2823d0407baSopenharmony_ci POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_SCOPE, 2833d0407baSopenharmony_ci}; 2843d0407baSopenharmony_ci 2853d0407baSopenharmony_ci#define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */ 2863d0407baSopenharmony_ci#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ 2873d0407baSopenharmony_ci#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */ 2883d0407baSopenharmony_ci 2893d0407baSopenharmony_cistatic const struct hid_device_id hid_battery_quirks[] = { 2903d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), 2913d0407baSopenharmony_ci HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE}, 2923d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), 2933d0407baSopenharmony_ci HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE}, 2943d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), 2953d0407baSopenharmony_ci HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE}, 2963d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO), 2973d0407baSopenharmony_ci HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE}, 2983d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), 2993d0407baSopenharmony_ci HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE}, 3003d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084), HID_BATTERY_QUIRK_IGNORE}, 3013d0407baSopenharmony_ci {HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_3), HID_BATTERY_QUIRK_IGNORE}, 3023d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), HID_BATTERY_QUIRK_IGNORE}, 3033d0407baSopenharmony_ci {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD), HID_BATTERY_QUIRK_IGNORE}, 3043d0407baSopenharmony_ci {HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN), HID_BATTERY_QUIRK_IGNORE}, 3053d0407baSopenharmony_ci {}}; 3063d0407baSopenharmony_ci 3073d0407baSopenharmony_cistatic unsigned find_battery_quirk(struct hid_device *hdev) 3083d0407baSopenharmony_ci{ 3093d0407baSopenharmony_ci unsigned quirks = 0; 3103d0407baSopenharmony_ci const struct hid_device_id *match; 3113d0407baSopenharmony_ci 3123d0407baSopenharmony_ci match = hid_match_id(hdev, hid_battery_quirks); 3133d0407baSopenharmony_ci if (match != NULL) { 3143d0407baSopenharmony_ci quirks = match->driver_data; 3153d0407baSopenharmony_ci } 3163d0407baSopenharmony_ci 3173d0407baSopenharmony_ci return quirks; 3183d0407baSopenharmony_ci} 3193d0407baSopenharmony_ci 3203d0407baSopenharmony_cistatic int hidinput_scale_battery_capacity(struct hid_device *dev, int value) 3213d0407baSopenharmony_ci{ 3223d0407baSopenharmony_ci if (dev->battery_min < dev->battery_max && value >= dev->battery_min && value <= dev->battery_max) { 3233d0407baSopenharmony_ci value = ((value - dev->battery_min) * HID_BATTERY_CAP_MUL) / (dev->battery_max - dev->battery_min); 3243d0407baSopenharmony_ci } 3253d0407baSopenharmony_ci 3263d0407baSopenharmony_ci return value; 3273d0407baSopenharmony_ci} 3283d0407baSopenharmony_ci 3293d0407baSopenharmony_cistatic int hidinput_query_battery_capacity(struct hid_device *dev) 3303d0407baSopenharmony_ci{ 3313d0407baSopenharmony_ci u8 *buf; 3323d0407baSopenharmony_ci int ret; 3333d0407baSopenharmony_ci 3343d0407baSopenharmony_ci buf = kmalloc(HID_KMALLOC_DEFAULT_SIZE, GFP_KERNEL); 3353d0407baSopenharmony_ci if (!buf) { 3363d0407baSopenharmony_ci return -ENOMEM; 3373d0407baSopenharmony_ci } 3383d0407baSopenharmony_ci 3393d0407baSopenharmony_ci ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, HID_KMALLOC_DEFAULT_SIZE, dev->battery_report_type, 3403d0407baSopenharmony_ci HID_REQ_GET_REPORT); 3413d0407baSopenharmony_ci if (ret < ENOENT) { 3423d0407baSopenharmony_ci kfree(buf); 3433d0407baSopenharmony_ci return -ENODATA; 3443d0407baSopenharmony_ci } 3453d0407baSopenharmony_ci 3463d0407baSopenharmony_ci ret = hidinput_scale_battery_capacity(dev, buf[1]); 3473d0407baSopenharmony_ci kfree(buf); 3483d0407baSopenharmony_ci return ret; 3493d0407baSopenharmony_ci} 3503d0407baSopenharmony_ci 3513d0407baSopenharmony_cistatic int hidinput_get_battery_property(struct power_supply *psy, enum power_supply_property prop, 3523d0407baSopenharmony_ci union power_supply_propval *val) 3533d0407baSopenharmony_ci{ 3543d0407baSopenharmony_ci struct hid_device *dev = power_supply_get_drvdata(psy); 3553d0407baSopenharmony_ci int value; 3563d0407baSopenharmony_ci int ret = 0; 3573d0407baSopenharmony_ci 3583d0407baSopenharmony_ci switch (prop) { 3593d0407baSopenharmony_ci case POWER_SUPPLY_PROP_PRESENT: 3603d0407baSopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 3613d0407baSopenharmony_ci val->intval = 1; 3623d0407baSopenharmony_ci break; 3633d0407baSopenharmony_ci 3643d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY: 3653d0407baSopenharmony_ci if (dev->battery_status != HID_BATTERY_REPORTED && !dev->battery_avoid_query) { 3663d0407baSopenharmony_ci value = hidinput_query_battery_capacity(dev); 3673d0407baSopenharmony_ci if (value < 0) { 3683d0407baSopenharmony_ci return value; 3693d0407baSopenharmony_ci } 3703d0407baSopenharmony_ci } else { 3713d0407baSopenharmony_ci value = dev->battery_capacity; 3723d0407baSopenharmony_ci } 3733d0407baSopenharmony_ci 3743d0407baSopenharmony_ci val->intval = value; 3753d0407baSopenharmony_ci break; 3763d0407baSopenharmony_ci 3773d0407baSopenharmony_ci case POWER_SUPPLY_PROP_MODEL_NAME: 3783d0407baSopenharmony_ci val->strval = dev->name; 3793d0407baSopenharmony_ci break; 3803d0407baSopenharmony_ci 3813d0407baSopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 3823d0407baSopenharmony_ci if (dev->battery_status != HID_BATTERY_REPORTED && !dev->battery_avoid_query) { 3833d0407baSopenharmony_ci value = hidinput_query_battery_capacity(dev); 3843d0407baSopenharmony_ci if (value < 0) { 3853d0407baSopenharmony_ci return value; 3863d0407baSopenharmony_ci } 3873d0407baSopenharmony_ci 3883d0407baSopenharmony_ci dev->battery_capacity = value; 3893d0407baSopenharmony_ci dev->battery_status = HID_BATTERY_QUERIED; 3903d0407baSopenharmony_ci } 3913d0407baSopenharmony_ci 3923d0407baSopenharmony_ci if (dev->battery_status == HID_BATTERY_UNKNOWN) { 3933d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 3943d0407baSopenharmony_ci } else { 3953d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 3963d0407baSopenharmony_ci } 3973d0407baSopenharmony_ci break; 3983d0407baSopenharmony_ci 3993d0407baSopenharmony_ci case POWER_SUPPLY_PROP_SCOPE: 4003d0407baSopenharmony_ci val->intval = POWER_SUPPLY_SCOPE_DEVICE; 4013d0407baSopenharmony_ci break; 4023d0407baSopenharmony_ci 4033d0407baSopenharmony_ci default: 4043d0407baSopenharmony_ci ret = -EINVAL; 4053d0407baSopenharmony_ci break; 4063d0407baSopenharmony_ci } 4073d0407baSopenharmony_ci 4083d0407baSopenharmony_ci return ret; 4093d0407baSopenharmony_ci} 4103d0407baSopenharmony_ci 4113d0407baSopenharmony_cistatic int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) 4123d0407baSopenharmony_ci{ 4133d0407baSopenharmony_ci struct power_supply_desc *psy_desc; 4143d0407baSopenharmony_ci struct power_supply_config psy_cfg = { 4153d0407baSopenharmony_ci .drv_data = dev, 4163d0407baSopenharmony_ci }; 4173d0407baSopenharmony_ci unsigned quirks; 4183d0407baSopenharmony_ci s32 min, max; 4193d0407baSopenharmony_ci int error; 4203d0407baSopenharmony_ci 4213d0407baSopenharmony_ci if (dev->battery) { 4223d0407baSopenharmony_ci return 0; /* already initialized? */ 4233d0407baSopenharmony_ci } 4243d0407baSopenharmony_ci 4253d0407baSopenharmony_ci quirks = find_battery_quirk(dev); 4263d0407baSopenharmony_ci 4273d0407baSopenharmony_ci hid_dbg(dev, "device %x:%x:%x %d quirks %d\n", dev->bus, dev->vendor, dev->product, dev->version, quirks); 4283d0407baSopenharmony_ci 4293d0407baSopenharmony_ci if (quirks & HID_BATTERY_QUIRK_IGNORE) { 4303d0407baSopenharmony_ci return 0; 4313d0407baSopenharmony_ci } 4323d0407baSopenharmony_ci 4333d0407baSopenharmony_ci psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL); 4343d0407baSopenharmony_ci if (!psy_desc) { 4353d0407baSopenharmony_ci return -ENOMEM; 4363d0407baSopenharmony_ci } 4373d0407baSopenharmony_ci 4383d0407baSopenharmony_ci psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", strlen(dev->uniq) ? dev->uniq : dev_name(&dev->dev)); 4393d0407baSopenharmony_ci if (!psy_desc->name) { 4403d0407baSopenharmony_ci error = -ENOMEM; 4413d0407baSopenharmony_ci goto err_free_mem; 4423d0407baSopenharmony_ci } 4433d0407baSopenharmony_ci 4443d0407baSopenharmony_ci psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; 4453d0407baSopenharmony_ci psy_desc->properties = hidinput_battery_props; 4463d0407baSopenharmony_ci psy_desc->num_properties = ARRAY_SIZE(hidinput_battery_props); 4473d0407baSopenharmony_ci psy_desc->use_for_apm = 0; 4483d0407baSopenharmony_ci psy_desc->get_property = hidinput_get_battery_property; 4493d0407baSopenharmony_ci 4503d0407baSopenharmony_ci min = field->logical_minimum; 4513d0407baSopenharmony_ci max = field->logical_maximum; 4523d0407baSopenharmony_ci 4533d0407baSopenharmony_ci if (quirks & HID_BATTERY_QUIRK_PERCENT) { 4543d0407baSopenharmony_ci min = 0; 4553d0407baSopenharmony_ci max = 0x64; 4563d0407baSopenharmony_ci } 4573d0407baSopenharmony_ci 4583d0407baSopenharmony_ci if (quirks & HID_BATTERY_QUIRK_FEATURE) { 4593d0407baSopenharmony_ci report_type = HID_FEATURE_REPORT; 4603d0407baSopenharmony_ci } 4613d0407baSopenharmony_ci 4623d0407baSopenharmony_ci dev->battery_min = min; 4633d0407baSopenharmony_ci dev->battery_max = max; 4643d0407baSopenharmony_ci dev->battery_report_type = report_type; 4653d0407baSopenharmony_ci dev->battery_report_id = field->report->id; 4663d0407baSopenharmony_ci 4673d0407baSopenharmony_ci /* 4683d0407baSopenharmony_ci * Stylus is normally not connected to the device and thus we 4693d0407baSopenharmony_ci * can't query the device and get meaningful battery strength. 4703d0407baSopenharmony_ci * We have to wait for the device to report it on its own. 4713d0407baSopenharmony_ci */ 4723d0407baSopenharmony_ci dev->battery_avoid_query = report_type == HID_INPUT_REPORT && field->physical == HID_DG_STYLUS; 4733d0407baSopenharmony_ci 4743d0407baSopenharmony_ci dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); 4753d0407baSopenharmony_ci if (IS_ERR(dev->battery)) { 4763d0407baSopenharmony_ci error = PTR_ERR(dev->battery); 4773d0407baSopenharmony_ci hid_warn(dev, "can't register power supply: %d\n", error); 4783d0407baSopenharmony_ci goto err_free_name; 4793d0407baSopenharmony_ci } 4803d0407baSopenharmony_ci 4813d0407baSopenharmony_ci power_supply_powers(dev->battery, &dev->dev); 4823d0407baSopenharmony_ci return 0; 4833d0407baSopenharmony_ci 4843d0407baSopenharmony_cierr_free_name: 4853d0407baSopenharmony_ci kfree(psy_desc->name); 4863d0407baSopenharmony_cierr_free_mem: 4873d0407baSopenharmony_ci kfree(psy_desc); 4883d0407baSopenharmony_ci dev->battery = NULL; 4893d0407baSopenharmony_ci return error; 4903d0407baSopenharmony_ci} 4913d0407baSopenharmony_ci 4923d0407baSopenharmony_cistatic void hidinput_cleanup_battery(struct hid_device *dev) 4933d0407baSopenharmony_ci{ 4943d0407baSopenharmony_ci const struct power_supply_desc *psy_desc; 4953d0407baSopenharmony_ci 4963d0407baSopenharmony_ci if (!dev->battery) { 4973d0407baSopenharmony_ci return; 4983d0407baSopenharmony_ci } 4993d0407baSopenharmony_ci 5003d0407baSopenharmony_ci psy_desc = dev->battery->desc; 5013d0407baSopenharmony_ci power_supply_unregister(dev->battery); 5023d0407baSopenharmony_ci kfree(psy_desc->name); 5033d0407baSopenharmony_ci kfree(psy_desc); 5043d0407baSopenharmony_ci dev->battery = NULL; 5053d0407baSopenharmony_ci} 5063d0407baSopenharmony_ci 5073d0407baSopenharmony_cistatic void hidinput_update_battery(struct hid_device *dev, int value) 5083d0407baSopenharmony_ci{ 5093d0407baSopenharmony_ci int capacity; 5103d0407baSopenharmony_ci if (!dev->battery) { 5113d0407baSopenharmony_ci return; 5123d0407baSopenharmony_ci } 5133d0407baSopenharmony_ci if (value == 0 || value < dev->battery_min || value > dev->battery_max) { 5143d0407baSopenharmony_ci return; 5153d0407baSopenharmony_ci } 5163d0407baSopenharmony_ci capacity = hidinput_scale_battery_capacity(dev, value); 5173d0407baSopenharmony_ci if (dev->battery_status != HID_BATTERY_REPORTED || capacity != dev->battery_capacity) { 5183d0407baSopenharmony_ci dev->battery_capacity = capacity; 5193d0407baSopenharmony_ci dev->battery_status = HID_BATTERY_REPORTED; 5203d0407baSopenharmony_ci power_supply_changed(dev->battery); 5213d0407baSopenharmony_ci } 5223d0407baSopenharmony_ci} 5233d0407baSopenharmony_ci#else /* !CONFIG_HID_BATTERY_STRENGTH */ 5243d0407baSopenharmony_cistatic int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) 5253d0407baSopenharmony_ci{ 5263d0407baSopenharmony_ci return 0; 5273d0407baSopenharmony_ci} 5283d0407baSopenharmony_ci 5293d0407baSopenharmony_cistatic void hidinput_cleanup_battery(struct hid_device *dev) 5303d0407baSopenharmony_ci{ 5313d0407baSopenharmony_ci} 5323d0407baSopenharmony_ci 5333d0407baSopenharmony_cistatic void hidinput_update_battery(struct hid_device *dev, int value) 5343d0407baSopenharmony_ci{ 5353d0407baSopenharmony_ci} 5363d0407baSopenharmony_ci#endif /* CONFIG_HID_BATTERY_STRENGTH */ 5373d0407baSopenharmony_ci 5383d0407baSopenharmony_cistatic void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage) 5393d0407baSopenharmony_ci{ 5403d0407baSopenharmony_ci struct input_dev *input = hidinput->input; 5413d0407baSopenharmony_ci struct hid_device *device = input_get_drvdata(input); 5423d0407baSopenharmony_ci int max = 0, code; 5433d0407baSopenharmony_ci unsigned long *bit = NULL; 5443d0407baSopenharmony_ci 5453d0407baSopenharmony_ci field->hidinput = hidinput; 5463d0407baSopenharmony_ci 5473d0407baSopenharmony_ci if (field->flags & HID_MAIN_ITEM_CONSTANT) { 5483d0407baSopenharmony_ci goto ignore; 5493d0407baSopenharmony_ci } 5503d0407baSopenharmony_ci 5513d0407baSopenharmony_ci /* Ignore if report count is out of bounds. */ 5523d0407baSopenharmony_ci if (field->report_count < 1) { 5533d0407baSopenharmony_ci goto ignore; 5543d0407baSopenharmony_ci } 5553d0407baSopenharmony_ci 5563d0407baSopenharmony_ci /* only LED usages are supported in output fields */ 5573d0407baSopenharmony_ci if (field->report_type == HID_OUTPUT_REPORT && (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { 5583d0407baSopenharmony_ci goto ignore; 5593d0407baSopenharmony_ci } 5603d0407baSopenharmony_ci 5613d0407baSopenharmony_ci if (device->driver->input_mapping) { 5623d0407baSopenharmony_ci int ret = device->driver->input_mapping(device, hidinput, field, usage, &bit, &max); 5633d0407baSopenharmony_ci if (ret > 0) { 5643d0407baSopenharmony_ci goto mapped; 5653d0407baSopenharmony_ci } 5663d0407baSopenharmony_ci if (ret < 0) { 5673d0407baSopenharmony_ci goto ignore; 5683d0407baSopenharmony_ci } 5693d0407baSopenharmony_ci } 5703d0407baSopenharmony_ci 5713d0407baSopenharmony_ci switch (usage->hid & HID_USAGE_PAGE) { 5723d0407baSopenharmony_ci case HID_UP_UNDEFINED: 5733d0407baSopenharmony_ci goto ignore; 5743d0407baSopenharmony_ci 5753d0407baSopenharmony_ci case HID_UP_KEYBOARD: 5763d0407baSopenharmony_ci set_bit(EV_REP, input->evbit); 5773d0407baSopenharmony_ci 5783d0407baSopenharmony_ci if ((usage->hid & HID_USAGE) < 0x100) { 5793d0407baSopenharmony_ci if (!hid_keyboard[usage->hid & HID_USAGE]) { 5803d0407baSopenharmony_ci goto ignore; 5813d0407baSopenharmony_ci } 5823d0407baSopenharmony_ci map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); 5833d0407baSopenharmony_ci } else { 5843d0407baSopenharmony_ci map_key(KEY_UNKNOWN); 5853d0407baSopenharmony_ci } 5863d0407baSopenharmony_ci 5873d0407baSopenharmony_ci break; 5883d0407baSopenharmony_ci 5893d0407baSopenharmony_ci case HID_UP_BUTTON: 5903d0407baSopenharmony_ci code = ((usage->hid - 1) & HID_USAGE); 5913d0407baSopenharmony_ci 5923d0407baSopenharmony_ci switch (field->application) { 5933d0407baSopenharmony_ci case HID_GD_MOUSE: 5943d0407baSopenharmony_ci case HID_GD_POINTER: 5953d0407baSopenharmony_ci code += BTN_MOUSE; 5963d0407baSopenharmony_ci break; 5973d0407baSopenharmony_ci case HID_GD_JOYSTICK: 5983d0407baSopenharmony_ci if (code <= 0xf) { 5993d0407baSopenharmony_ci code += BTN_JOYSTICK; 6003d0407baSopenharmony_ci } else { 6013d0407baSopenharmony_ci code += BTN_TRIGGER_HAPPY - 0x10; 6023d0407baSopenharmony_ci } 6033d0407baSopenharmony_ci break; 6043d0407baSopenharmony_ci case HID_GD_GAMEPAD: 6053d0407baSopenharmony_ci if (code <= 0xf) { 6063d0407baSopenharmony_ci code += BTN_GAMEPAD; 6073d0407baSopenharmony_ci } else { 6083d0407baSopenharmony_ci code += BTN_TRIGGER_HAPPY - 0x10; 6093d0407baSopenharmony_ci } 6103d0407baSopenharmony_ci break; 6113d0407baSopenharmony_ci default: 6123d0407baSopenharmony_ci switch (field->physical) { 6133d0407baSopenharmony_ci case HID_GD_MOUSE: 6143d0407baSopenharmony_ci case HID_GD_POINTER: 6153d0407baSopenharmony_ci code += BTN_MOUSE; 6163d0407baSopenharmony_ci break; 6173d0407baSopenharmony_ci case HID_GD_JOYSTICK: 6183d0407baSopenharmony_ci code += BTN_JOYSTICK; 6193d0407baSopenharmony_ci break; 6203d0407baSopenharmony_ci case HID_GD_GAMEPAD: 6213d0407baSopenharmony_ci code += BTN_GAMEPAD; 6223d0407baSopenharmony_ci break; 6233d0407baSopenharmony_ci default: 6243d0407baSopenharmony_ci code += BTN_MISC; 6253d0407baSopenharmony_ci } 6263d0407baSopenharmony_ci } 6273d0407baSopenharmony_ci 6283d0407baSopenharmony_ci map_key(code); 6293d0407baSopenharmony_ci break; 6303d0407baSopenharmony_ci 6313d0407baSopenharmony_ci case HID_UP_SIMULATION: 6323d0407baSopenharmony_ci switch (usage->hid & 0xffff) { 6333d0407baSopenharmony_ci case 0xba: 6343d0407baSopenharmony_ci map_abs(ABS_RUDDER); 6353d0407baSopenharmony_ci break; 6363d0407baSopenharmony_ci case 0xbb: 6373d0407baSopenharmony_ci map_abs(ABS_THROTTLE); 6383d0407baSopenharmony_ci break; 6393d0407baSopenharmony_ci case 0xc4: 6403d0407baSopenharmony_ci map_abs(ABS_GAS); 6413d0407baSopenharmony_ci break; 6423d0407baSopenharmony_ci case 0xc5: 6433d0407baSopenharmony_ci map_abs(ABS_BRAKE); 6443d0407baSopenharmony_ci break; 6453d0407baSopenharmony_ci case 0xc8: 6463d0407baSopenharmony_ci map_abs(ABS_WHEEL); 6473d0407baSopenharmony_ci break; 6483d0407baSopenharmony_ci default: 6493d0407baSopenharmony_ci goto ignore; 6503d0407baSopenharmony_ci } 6513d0407baSopenharmony_ci break; 6523d0407baSopenharmony_ci 6533d0407baSopenharmony_ci case HID_UP_GENDESK: 6543d0407baSopenharmony_ci if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ 6553d0407baSopenharmony_ci switch (usage->hid & 0xf) { 6563d0407baSopenharmony_ci case 0x1: 6573d0407baSopenharmony_ci map_key_clear(KEY_POWER); 6583d0407baSopenharmony_ci break; 6593d0407baSopenharmony_ci case 0x2: 6603d0407baSopenharmony_ci map_key_clear(KEY_SLEEP); 6613d0407baSopenharmony_ci break; 6623d0407baSopenharmony_ci case 0x3: 6633d0407baSopenharmony_ci map_key_clear(KEY_WAKEUP); 6643d0407baSopenharmony_ci break; 6653d0407baSopenharmony_ci case 0x4: 6663d0407baSopenharmony_ci map_key_clear(KEY_CONTEXT_MENU); 6673d0407baSopenharmony_ci break; 6683d0407baSopenharmony_ci case 0x5: 6693d0407baSopenharmony_ci map_key_clear(KEY_MENU); 6703d0407baSopenharmony_ci break; 6713d0407baSopenharmony_ci case 0x6: 6723d0407baSopenharmony_ci map_key_clear(KEY_PROG1); 6733d0407baSopenharmony_ci break; 6743d0407baSopenharmony_ci case 0x7: 6753d0407baSopenharmony_ci map_key_clear(KEY_HELP); 6763d0407baSopenharmony_ci break; 6773d0407baSopenharmony_ci case 0x8: 6783d0407baSopenharmony_ci map_key_clear(KEY_EXIT); 6793d0407baSopenharmony_ci break; 6803d0407baSopenharmony_ci case 0x9: 6813d0407baSopenharmony_ci map_key_clear(KEY_SELECT); 6823d0407baSopenharmony_ci break; 6833d0407baSopenharmony_ci case 0xa: 6843d0407baSopenharmony_ci map_key_clear(KEY_RIGHT); 6853d0407baSopenharmony_ci break; 6863d0407baSopenharmony_ci case 0xb: 6873d0407baSopenharmony_ci map_key_clear(KEY_LEFT); 6883d0407baSopenharmony_ci break; 6893d0407baSopenharmony_ci case 0xc: 6903d0407baSopenharmony_ci map_key_clear(KEY_UP); 6913d0407baSopenharmony_ci break; 6923d0407baSopenharmony_ci case 0xd: 6933d0407baSopenharmony_ci map_key_clear(KEY_DOWN); 6943d0407baSopenharmony_ci break; 6953d0407baSopenharmony_ci case 0xe: 6963d0407baSopenharmony_ci map_key_clear(KEY_POWER2); 6973d0407baSopenharmony_ci break; 6983d0407baSopenharmony_ci case 0xf: 6993d0407baSopenharmony_ci map_key_clear(KEY_RESTART); 7003d0407baSopenharmony_ci break; 7013d0407baSopenharmony_ci default: 7023d0407baSopenharmony_ci goto unknown; 7033d0407baSopenharmony_ci } 7043d0407baSopenharmony_ci break; 7053d0407baSopenharmony_ci } 7063d0407baSopenharmony_ci 7073d0407baSopenharmony_ci if ((usage->hid & 0xf0) == 0xb0) { /* SC - Display */ 7083d0407baSopenharmony_ci switch (usage->hid & 0xf) { 7093d0407baSopenharmony_ci case 0x05: 7103d0407baSopenharmony_ci map_key_clear(KEY_SWITCHVIDEOMODE); 7113d0407baSopenharmony_ci break; 7123d0407baSopenharmony_ci default: 7133d0407baSopenharmony_ci goto ignore; 7143d0407baSopenharmony_ci } 7153d0407baSopenharmony_ci break; 7163d0407baSopenharmony_ci } 7173d0407baSopenharmony_ci 7183d0407baSopenharmony_ci /* 7193d0407baSopenharmony_ci * Some lazy vendors declare 255 usages for System Control, 7203d0407baSopenharmony_ci * leading to the creation of ABS_X|Y axis and too many others. 7213d0407baSopenharmony_ci * It wouldn't be a problem if joydev doesn't consider the 7223d0407baSopenharmony_ci * device as a joystick then. 7233d0407baSopenharmony_ci */ 7243d0407baSopenharmony_ci if (field->application == HID_GD_SYSTEM_CONTROL) { 7253d0407baSopenharmony_ci goto ignore; 7263d0407baSopenharmony_ci } 7273d0407baSopenharmony_ci 7283d0407baSopenharmony_ci if ((usage->hid & 0xf0) == 0x90) { /* D-pad */ 7293d0407baSopenharmony_ci switch (usage->hid) { 7303d0407baSopenharmony_ci case HID_GD_UP: 7313d0407baSopenharmony_ci usage->hat_dir = 1; 7323d0407baSopenharmony_ci break; 7333d0407baSopenharmony_ci case HID_GD_DOWN: 7343d0407baSopenharmony_ci usage->hat_dir = 0x5; 7353d0407baSopenharmony_ci break; 7363d0407baSopenharmony_ci case HID_GD_RIGHT: 7373d0407baSopenharmony_ci usage->hat_dir = 0x3; 7383d0407baSopenharmony_ci break; 7393d0407baSopenharmony_ci case HID_GD_LEFT: 7403d0407baSopenharmony_ci usage->hat_dir = 0x7; 7413d0407baSopenharmony_ci break; 7423d0407baSopenharmony_ci default: 7433d0407baSopenharmony_ci goto unknown; 7443d0407baSopenharmony_ci } 7453d0407baSopenharmony_ci if (field->dpad) { 7463d0407baSopenharmony_ci map_abs(field->dpad); 7473d0407baSopenharmony_ci goto ignore; 7483d0407baSopenharmony_ci } 7493d0407baSopenharmony_ci map_abs(ABS_HAT0X); 7503d0407baSopenharmony_ci break; 7513d0407baSopenharmony_ci } 7523d0407baSopenharmony_ci 7533d0407baSopenharmony_ci switch (usage->hid) { 7543d0407baSopenharmony_ci /* These usage IDs map directly to the usage codes. */ 7553d0407baSopenharmony_ci case HID_GD_X: 7563d0407baSopenharmony_ci case HID_GD_Y: 7573d0407baSopenharmony_ci case HID_GD_Z: 7583d0407baSopenharmony_ci case HID_GD_RX: 7593d0407baSopenharmony_ci case HID_GD_RY: 7603d0407baSopenharmony_ci case HID_GD_RZ: 7613d0407baSopenharmony_ci if (field->flags & HID_MAIN_ITEM_RELATIVE) { 7623d0407baSopenharmony_ci map_rel(usage->hid & 0xf); 7633d0407baSopenharmony_ci } else { 7643d0407baSopenharmony_ci map_abs_clear(usage->hid & 0xf); 7653d0407baSopenharmony_ci } 7663d0407baSopenharmony_ci break; 7673d0407baSopenharmony_ci 7683d0407baSopenharmony_ci case HID_GD_WHEEL: 7693d0407baSopenharmony_ci if (field->flags & HID_MAIN_ITEM_RELATIVE) { 7703d0407baSopenharmony_ci set_bit(REL_WHEEL, input->relbit); 7713d0407baSopenharmony_ci map_rel(REL_WHEEL_HI_RES); 7723d0407baSopenharmony_ci } else { 7733d0407baSopenharmony_ci map_abs(usage->hid & 0xf); 7743d0407baSopenharmony_ci } 7753d0407baSopenharmony_ci break; 7763d0407baSopenharmony_ci case HID_GD_SLIDER: 7773d0407baSopenharmony_ci case HID_GD_DIAL: 7783d0407baSopenharmony_ci if (field->flags & HID_MAIN_ITEM_RELATIVE) { 7793d0407baSopenharmony_ci map_rel(usage->hid & 0xf); 7803d0407baSopenharmony_ci } else { 7813d0407baSopenharmony_ci map_abs(usage->hid & 0xf); 7823d0407baSopenharmony_ci } 7833d0407baSopenharmony_ci break; 7843d0407baSopenharmony_ci 7853d0407baSopenharmony_ci case HID_GD_HATSWITCH: 7863d0407baSopenharmony_ci usage->hat_min = field->logical_minimum; 7873d0407baSopenharmony_ci usage->hat_max = field->logical_maximum; 7883d0407baSopenharmony_ci map_abs(ABS_HAT0X); 7893d0407baSopenharmony_ci break; 7903d0407baSopenharmony_ci 7913d0407baSopenharmony_ci case HID_GD_START: 7923d0407baSopenharmony_ci map_key_clear(BTN_START); 7933d0407baSopenharmony_ci break; 7943d0407baSopenharmony_ci case HID_GD_SELECT: 7953d0407baSopenharmony_ci map_key_clear(BTN_SELECT); 7963d0407baSopenharmony_ci break; 7973d0407baSopenharmony_ci 7983d0407baSopenharmony_ci case HID_GD_RFKILL_BTN: 7993d0407baSopenharmony_ci /* MS wireless radio ctl extension, also check CA */ 8003d0407baSopenharmony_ci if (field->application == HID_GD_WIRELESS_RADIO_CTLS) { 8013d0407baSopenharmony_ci map_key_clear(KEY_RFKILL); 8023d0407baSopenharmony_ci /* We need to simulate the btn release */ 8033d0407baSopenharmony_ci field->flags |= HID_MAIN_ITEM_RELATIVE; 8043d0407baSopenharmony_ci break; 8053d0407baSopenharmony_ci } 8063d0407baSopenharmony_ci 8073d0407baSopenharmony_ci default: 8083d0407baSopenharmony_ci goto unknown; 8093d0407baSopenharmony_ci } 8103d0407baSopenharmony_ci 8113d0407baSopenharmony_ci break; 8123d0407baSopenharmony_ci 8133d0407baSopenharmony_ci case HID_UP_LED: 8143d0407baSopenharmony_ci switch (usage->hid & 0xffff) { /* HID-Value: */ 8153d0407baSopenharmony_ci case 0x01: 8163d0407baSopenharmony_ci map_led(LED_NUML); 8173d0407baSopenharmony_ci break; /* "Num Lock" */ 8183d0407baSopenharmony_ci case 0x02: 8193d0407baSopenharmony_ci map_led(LED_CAPSL); 8203d0407baSopenharmony_ci break; /* "Caps Lock" */ 8213d0407baSopenharmony_ci case 0x03: 8223d0407baSopenharmony_ci map_led(LED_SCROLLL); 8233d0407baSopenharmony_ci break; /* "Scroll Lock" */ 8243d0407baSopenharmony_ci case 0x04: 8253d0407baSopenharmony_ci map_led(LED_COMPOSE); 8263d0407baSopenharmony_ci break; /* "Compose" */ 8273d0407baSopenharmony_ci case 0x05: 8283d0407baSopenharmony_ci map_led(LED_KANA); 8293d0407baSopenharmony_ci break; /* "Kana" */ 8303d0407baSopenharmony_ci case 0x27: 8313d0407baSopenharmony_ci map_led(LED_SLEEP); 8323d0407baSopenharmony_ci break; /* "Stand-By" */ 8333d0407baSopenharmony_ci case 0x4c: 8343d0407baSopenharmony_ci map_led(LED_SUSPEND); 8353d0407baSopenharmony_ci break; /* "System Suspend" */ 8363d0407baSopenharmony_ci case 0x09: 8373d0407baSopenharmony_ci map_led(LED_MUTE); 8383d0407baSopenharmony_ci break; /* "Mute" */ 8393d0407baSopenharmony_ci case 0x4b: 8403d0407baSopenharmony_ci map_led(LED_MISC); 8413d0407baSopenharmony_ci break; /* "Generic Indicator" */ 8423d0407baSopenharmony_ci case 0x19: 8433d0407baSopenharmony_ci map_led(LED_MAIL); 8443d0407baSopenharmony_ci break; /* "Message Waiting" */ 8453d0407baSopenharmony_ci case 0x4d: 8463d0407baSopenharmony_ci map_led(LED_CHARGING); 8473d0407baSopenharmony_ci break; /* "External Power Connected" */ 8483d0407baSopenharmony_ci 8493d0407baSopenharmony_ci default: 8503d0407baSopenharmony_ci goto ignore; 8513d0407baSopenharmony_ci } 8523d0407baSopenharmony_ci break; 8533d0407baSopenharmony_ci 8543d0407baSopenharmony_ci case HID_UP_DIGITIZER: 8553d0407baSopenharmony_ci if ((field->application & 0xff) == 0x01) { /* Digitizer */ 8563d0407baSopenharmony_ci __set_bit(INPUT_PROP_POINTER, input->propbit); 8573d0407baSopenharmony_ci } else if ((field->application & 0xff) == 0x02) { /* Pen */ 8583d0407baSopenharmony_ci __set_bit(INPUT_PROP_DIRECT, input->propbit); 8593d0407baSopenharmony_ci } 8603d0407baSopenharmony_ci 8613d0407baSopenharmony_ci switch (usage->hid & 0xff) { 8623d0407baSopenharmony_ci case 0x00: /* Undefined */ 8633d0407baSopenharmony_ci goto ignore; 8643d0407baSopenharmony_ci 8653d0407baSopenharmony_ci case 0x30: /* TipPressure */ 8663d0407baSopenharmony_ci if (!test_bit(BTN_TOUCH, input->keybit)) { 8673d0407baSopenharmony_ci device->quirks |= HID_QUIRK_NOTOUCH; 8683d0407baSopenharmony_ci set_bit(EV_KEY, input->evbit); 8693d0407baSopenharmony_ci set_bit(BTN_TOUCH, input->keybit); 8703d0407baSopenharmony_ci } 8713d0407baSopenharmony_ci map_abs_clear(ABS_PRESSURE); 8723d0407baSopenharmony_ci break; 8733d0407baSopenharmony_ci 8743d0407baSopenharmony_ci case 0x32: /* InRange */ 8753d0407baSopenharmony_ci switch (field->physical & 0xff) { 8763d0407baSopenharmony_ci case 0x21: 8773d0407baSopenharmony_ci map_key(BTN_TOOL_MOUSE); 8783d0407baSopenharmony_ci break; 8793d0407baSopenharmony_ci case 0x22: 8803d0407baSopenharmony_ci map_key(BTN_TOOL_FINGER); 8813d0407baSopenharmony_ci break; 8823d0407baSopenharmony_ci default: 8833d0407baSopenharmony_ci map_key(BTN_TOOL_PEN); 8843d0407baSopenharmony_ci break; 8853d0407baSopenharmony_ci } 8863d0407baSopenharmony_ci break; 8873d0407baSopenharmony_ci 8883d0407baSopenharmony_ci case 0x3b: /* Battery Strength */ 8893d0407baSopenharmony_ci hidinput_setup_battery(device, HID_INPUT_REPORT, field); 8903d0407baSopenharmony_ci usage->type = EV_PWR; 8913d0407baSopenharmony_ci return; 8923d0407baSopenharmony_ci 8933d0407baSopenharmony_ci case 0x3c: /* Invert */ 8943d0407baSopenharmony_ci map_key_clear(BTN_TOOL_RUBBER); 8953d0407baSopenharmony_ci break; 8963d0407baSopenharmony_ci 8973d0407baSopenharmony_ci case 0x3d: /* X Tilt */ 8983d0407baSopenharmony_ci map_abs_clear(ABS_TILT_X); 8993d0407baSopenharmony_ci break; 9003d0407baSopenharmony_ci 9013d0407baSopenharmony_ci case 0x3e: /* Y Tilt */ 9023d0407baSopenharmony_ci map_abs_clear(ABS_TILT_Y); 9033d0407baSopenharmony_ci break; 9043d0407baSopenharmony_ci 9053d0407baSopenharmony_ci case 0x33: /* Touch */ 9063d0407baSopenharmony_ci case 0x42: /* TipSwitch */ 9073d0407baSopenharmony_ci case 0x43: /* TipSwitch2 */ 9083d0407baSopenharmony_ci device->quirks &= ~HID_QUIRK_NOTOUCH; 9093d0407baSopenharmony_ci map_key_clear(BTN_TOUCH); 9103d0407baSopenharmony_ci break; 9113d0407baSopenharmony_ci 9123d0407baSopenharmony_ci case 0x44: /* BarrelSwitch */ 9133d0407baSopenharmony_ci map_key_clear(BTN_STYLUS); 9143d0407baSopenharmony_ci break; 9153d0407baSopenharmony_ci 9163d0407baSopenharmony_ci case 0x45: /* ERASER */ 9173d0407baSopenharmony_ci /* 9183d0407baSopenharmony_ci * This event is reported when eraser tip touches the surface. 9193d0407baSopenharmony_ci * Actual eraser (BTN_TOOL_RUBBER) is set by Invert usage when 9203d0407baSopenharmony_ci * tool gets in proximity. 9213d0407baSopenharmony_ci */ 9223d0407baSopenharmony_ci map_key_clear(BTN_TOUCH); 9233d0407baSopenharmony_ci break; 9243d0407baSopenharmony_ci 9253d0407baSopenharmony_ci case 0x46: /* TabletPick */ 9263d0407baSopenharmony_ci case 0x5a: /* SecondaryBarrelSwitch */ 9273d0407baSopenharmony_ci map_key_clear(BTN_STYLUS2); 9283d0407baSopenharmony_ci break; 9293d0407baSopenharmony_ci 9303d0407baSopenharmony_ci case 0x5b: /* TransducerSerialNumber */ 9313d0407baSopenharmony_ci usage->type = EV_MSC; 9323d0407baSopenharmony_ci usage->code = MSC_SERIAL; 9333d0407baSopenharmony_ci bit = input->mscbit; 9343d0407baSopenharmony_ci max = MSC_MAX; 9353d0407baSopenharmony_ci break; 9363d0407baSopenharmony_ci 9373d0407baSopenharmony_ci default: 9383d0407baSopenharmony_ci goto unknown; 9393d0407baSopenharmony_ci } 9403d0407baSopenharmony_ci break; 9413d0407baSopenharmony_ci 9423d0407baSopenharmony_ci case HID_UP_TELEPHONY: 9433d0407baSopenharmony_ci switch (usage->hid & HID_USAGE) { 9443d0407baSopenharmony_ci case 0x2f: 9453d0407baSopenharmony_ci map_key_clear(KEY_MICMUTE); 9463d0407baSopenharmony_ci break; 9473d0407baSopenharmony_ci case 0xb0: 9483d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_0); 9493d0407baSopenharmony_ci break; 9503d0407baSopenharmony_ci case 0xb1: 9513d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_1); 9523d0407baSopenharmony_ci break; 9533d0407baSopenharmony_ci case 0xb2: 9543d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_2); 9553d0407baSopenharmony_ci break; 9563d0407baSopenharmony_ci case 0xb3: 9573d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_3); 9583d0407baSopenharmony_ci break; 9593d0407baSopenharmony_ci case 0xb4: 9603d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_4); 9613d0407baSopenharmony_ci break; 9623d0407baSopenharmony_ci case 0xb5: 9633d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_5); 9643d0407baSopenharmony_ci break; 9653d0407baSopenharmony_ci case 0xb6: 9663d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_6); 9673d0407baSopenharmony_ci break; 9683d0407baSopenharmony_ci case 0xb7: 9693d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_7); 9703d0407baSopenharmony_ci break; 9713d0407baSopenharmony_ci case 0xb8: 9723d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_8); 9733d0407baSopenharmony_ci break; 9743d0407baSopenharmony_ci case 0xb9: 9753d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_9); 9763d0407baSopenharmony_ci break; 9773d0407baSopenharmony_ci case 0xba: 9783d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_STAR); 9793d0407baSopenharmony_ci break; 9803d0407baSopenharmony_ci case 0xbb: 9813d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_POUND); 9823d0407baSopenharmony_ci break; 9833d0407baSopenharmony_ci case 0xbc: 9843d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_A); 9853d0407baSopenharmony_ci break; 9863d0407baSopenharmony_ci case 0xbd: 9873d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_B); 9883d0407baSopenharmony_ci break; 9893d0407baSopenharmony_ci case 0xbe: 9903d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_C); 9913d0407baSopenharmony_ci break; 9923d0407baSopenharmony_ci case 0xbf: 9933d0407baSopenharmony_ci map_key_clear(KEY_NUMERIC_D); 9943d0407baSopenharmony_ci break; 9953d0407baSopenharmony_ci default: 9963d0407baSopenharmony_ci goto ignore; 9973d0407baSopenharmony_ci } 9983d0407baSopenharmony_ci break; 9993d0407baSopenharmony_ci 10003d0407baSopenharmony_ci case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */ 10013d0407baSopenharmony_ci switch (usage->hid & HID_USAGE) { 10023d0407baSopenharmony_ci case 0x000: 10033d0407baSopenharmony_ci goto ignore; 10043d0407baSopenharmony_ci case 0x030: 10053d0407baSopenharmony_ci map_key_clear(KEY_POWER); 10063d0407baSopenharmony_ci break; 10073d0407baSopenharmony_ci case 0x031: 10083d0407baSopenharmony_ci map_key_clear(KEY_RESTART); 10093d0407baSopenharmony_ci break; 10103d0407baSopenharmony_ci case 0x032: 10113d0407baSopenharmony_ci map_key_clear(KEY_SLEEP); 10123d0407baSopenharmony_ci break; 10133d0407baSopenharmony_ci case 0x034: 10143d0407baSopenharmony_ci map_key_clear(KEY_SLEEP); 10153d0407baSopenharmony_ci break; 10163d0407baSopenharmony_ci case 0x035: 10173d0407baSopenharmony_ci map_key_clear(KEY_KBDILLUMTOGGLE); 10183d0407baSopenharmony_ci break; 10193d0407baSopenharmony_ci case 0x036: 10203d0407baSopenharmony_ci map_key_clear(BTN_MISC); 10213d0407baSopenharmony_ci break; 10223d0407baSopenharmony_ci 10233d0407baSopenharmony_ci case 0x040: 10243d0407baSopenharmony_ci map_key_clear(KEY_MENU); 10253d0407baSopenharmony_ci break; /* Menu */ 10263d0407baSopenharmony_ci case 0x041: 10273d0407baSopenharmony_ci map_key_clear(KEY_SELECT); 10283d0407baSopenharmony_ci break; /* Menu Pick */ 10293d0407baSopenharmony_ci case 0x042: 10303d0407baSopenharmony_ci map_key_clear(KEY_UP); 10313d0407baSopenharmony_ci break; /* Menu Up */ 10323d0407baSopenharmony_ci case 0x043: 10333d0407baSopenharmony_ci map_key_clear(KEY_DOWN); 10343d0407baSopenharmony_ci break; /* Menu Down */ 10353d0407baSopenharmony_ci case 0x044: 10363d0407baSopenharmony_ci map_key_clear(KEY_LEFT); 10373d0407baSopenharmony_ci break; /* Menu Left */ 10383d0407baSopenharmony_ci case 0x045: 10393d0407baSopenharmony_ci map_key_clear(KEY_RIGHT); 10403d0407baSopenharmony_ci break; /* Menu Right */ 10413d0407baSopenharmony_ci case 0x046: 10423d0407baSopenharmony_ci map_key_clear(KEY_ESC); 10433d0407baSopenharmony_ci break; /* Menu Escape */ 10443d0407baSopenharmony_ci case 0x047: 10453d0407baSopenharmony_ci map_key_clear(KEY_KPPLUS); 10463d0407baSopenharmony_ci break; /* Menu Value Increase */ 10473d0407baSopenharmony_ci case 0x048: 10483d0407baSopenharmony_ci map_key_clear(KEY_KPMINUS); 10493d0407baSopenharmony_ci break; /* Menu Value Decrease */ 10503d0407baSopenharmony_ci 10513d0407baSopenharmony_ci case 0x060: 10523d0407baSopenharmony_ci map_key_clear(KEY_INFO); 10533d0407baSopenharmony_ci break; /* Data On Screen */ 10543d0407baSopenharmony_ci case 0x061: 10553d0407baSopenharmony_ci map_key_clear(KEY_SUBTITLE); 10563d0407baSopenharmony_ci break; /* Closed Caption */ 10573d0407baSopenharmony_ci case 0x063: 10583d0407baSopenharmony_ci map_key_clear(KEY_VCR); 10593d0407baSopenharmony_ci break; /* VCR/TV */ 10603d0407baSopenharmony_ci case 0x065: 10613d0407baSopenharmony_ci map_key_clear(KEY_CAMERA); 10623d0407baSopenharmony_ci break; /* Snapshot */ 10633d0407baSopenharmony_ci case 0x069: 10643d0407baSopenharmony_ci map_key_clear(KEY_RED); 10653d0407baSopenharmony_ci break; 10663d0407baSopenharmony_ci case 0x06a: 10673d0407baSopenharmony_ci map_key_clear(KEY_GREEN); 10683d0407baSopenharmony_ci break; 10693d0407baSopenharmony_ci case 0x06b: 10703d0407baSopenharmony_ci map_key_clear(KEY_BLUE); 10713d0407baSopenharmony_ci break; 10723d0407baSopenharmony_ci case 0x06c: 10733d0407baSopenharmony_ci map_key_clear(KEY_YELLOW); 10743d0407baSopenharmony_ci break; 10753d0407baSopenharmony_ci case 0x06d: 10763d0407baSopenharmony_ci map_key_clear(KEY_ASPECT_RATIO); 10773d0407baSopenharmony_ci break; 10783d0407baSopenharmony_ci 10793d0407baSopenharmony_ci case 0x06f: 10803d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESSUP); 10813d0407baSopenharmony_ci break; 10823d0407baSopenharmony_ci case 0x070: 10833d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESSDOWN); 10843d0407baSopenharmony_ci break; 10853d0407baSopenharmony_ci case 0x072: 10863d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESS_TOGGLE); 10873d0407baSopenharmony_ci break; 10883d0407baSopenharmony_ci case 0x073: 10893d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESS_MIN); 10903d0407baSopenharmony_ci break; 10913d0407baSopenharmony_ci case 0x074: 10923d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESS_MAX); 10933d0407baSopenharmony_ci break; 10943d0407baSopenharmony_ci case 0x075: 10953d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESS_AUTO); 10963d0407baSopenharmony_ci break; 10973d0407baSopenharmony_ci 10983d0407baSopenharmony_ci case 0x079: 10993d0407baSopenharmony_ci map_key_clear(KEY_KBDILLUMUP); 11003d0407baSopenharmony_ci break; 11013d0407baSopenharmony_ci case 0x07a: 11023d0407baSopenharmony_ci map_key_clear(KEY_KBDILLUMDOWN); 11033d0407baSopenharmony_ci break; 11043d0407baSopenharmony_ci case 0x07c: 11053d0407baSopenharmony_ci map_key_clear(KEY_KBDILLUMTOGGLE); 11063d0407baSopenharmony_ci break; 11073d0407baSopenharmony_ci 11083d0407baSopenharmony_ci case 0x082: 11093d0407baSopenharmony_ci map_key_clear(KEY_VIDEO_NEXT); 11103d0407baSopenharmony_ci break; 11113d0407baSopenharmony_ci case 0x083: 11123d0407baSopenharmony_ci map_key_clear(KEY_LAST); 11133d0407baSopenharmony_ci break; 11143d0407baSopenharmony_ci case 0x084: 11153d0407baSopenharmony_ci map_key_clear(KEY_ENTER); 11163d0407baSopenharmony_ci break; 11173d0407baSopenharmony_ci case 0x088: 11183d0407baSopenharmony_ci map_key_clear(KEY_PC); 11193d0407baSopenharmony_ci break; 11203d0407baSopenharmony_ci case 0x089: 11213d0407baSopenharmony_ci map_key_clear(KEY_TV); 11223d0407baSopenharmony_ci break; 11233d0407baSopenharmony_ci case 0x08a: 11243d0407baSopenharmony_ci map_key_clear(KEY_WWW); 11253d0407baSopenharmony_ci break; 11263d0407baSopenharmony_ci case 0x08b: 11273d0407baSopenharmony_ci map_key_clear(KEY_DVD); 11283d0407baSopenharmony_ci break; 11293d0407baSopenharmony_ci case 0x08c: 11303d0407baSopenharmony_ci map_key_clear(KEY_PHONE); 11313d0407baSopenharmony_ci break; 11323d0407baSopenharmony_ci case 0x08d: 11333d0407baSopenharmony_ci map_key_clear(KEY_PROGRAM); 11343d0407baSopenharmony_ci break; 11353d0407baSopenharmony_ci case 0x08e: 11363d0407baSopenharmony_ci map_key_clear(KEY_VIDEOPHONE); 11373d0407baSopenharmony_ci break; 11383d0407baSopenharmony_ci case 0x08f: 11393d0407baSopenharmony_ci map_key_clear(KEY_GAMES); 11403d0407baSopenharmony_ci break; 11413d0407baSopenharmony_ci case 0x090: 11423d0407baSopenharmony_ci map_key_clear(KEY_MEMO); 11433d0407baSopenharmony_ci break; 11443d0407baSopenharmony_ci case 0x091: 11453d0407baSopenharmony_ci map_key_clear(KEY_CD); 11463d0407baSopenharmony_ci break; 11473d0407baSopenharmony_ci case 0x092: 11483d0407baSopenharmony_ci map_key_clear(KEY_VCR); 11493d0407baSopenharmony_ci break; 11503d0407baSopenharmony_ci case 0x093: 11513d0407baSopenharmony_ci map_key_clear(KEY_TUNER); 11523d0407baSopenharmony_ci break; 11533d0407baSopenharmony_ci case 0x094: 11543d0407baSopenharmony_ci map_key_clear(KEY_EXIT); 11553d0407baSopenharmony_ci break; 11563d0407baSopenharmony_ci case 0x095: 11573d0407baSopenharmony_ci map_key_clear(KEY_HELP); 11583d0407baSopenharmony_ci break; 11593d0407baSopenharmony_ci case 0x096: 11603d0407baSopenharmony_ci map_key_clear(KEY_TAPE); 11613d0407baSopenharmony_ci break; 11623d0407baSopenharmony_ci case 0x097: 11633d0407baSopenharmony_ci map_key_clear(KEY_TV2); 11643d0407baSopenharmony_ci break; 11653d0407baSopenharmony_ci case 0x098: 11663d0407baSopenharmony_ci map_key_clear(KEY_SAT); 11673d0407baSopenharmony_ci break; 11683d0407baSopenharmony_ci case 0x09a: 11693d0407baSopenharmony_ci map_key_clear(KEY_PVR); 11703d0407baSopenharmony_ci break; 11713d0407baSopenharmony_ci 11723d0407baSopenharmony_ci case 0x09c: 11733d0407baSopenharmony_ci map_key_clear(KEY_CHANNELUP); 11743d0407baSopenharmony_ci break; 11753d0407baSopenharmony_ci case 0x09d: 11763d0407baSopenharmony_ci map_key_clear(KEY_CHANNELDOWN); 11773d0407baSopenharmony_ci break; 11783d0407baSopenharmony_ci case 0x0a0: 11793d0407baSopenharmony_ci map_key_clear(KEY_VCR2); 11803d0407baSopenharmony_ci break; 11813d0407baSopenharmony_ci 11823d0407baSopenharmony_ci case 0x0b0: 11833d0407baSopenharmony_ci map_key_clear(KEY_PLAY); 11843d0407baSopenharmony_ci break; 11853d0407baSopenharmony_ci case 0x0b1: 11863d0407baSopenharmony_ci map_key_clear(KEY_PAUSE); 11873d0407baSopenharmony_ci break; 11883d0407baSopenharmony_ci case 0x0b2: 11893d0407baSopenharmony_ci map_key_clear(KEY_RECORD); 11903d0407baSopenharmony_ci break; 11913d0407baSopenharmony_ci case 0x0b3: 11923d0407baSopenharmony_ci map_key_clear(KEY_FASTFORWARD); 11933d0407baSopenharmony_ci break; 11943d0407baSopenharmony_ci case 0x0b4: 11953d0407baSopenharmony_ci map_key_clear(KEY_REWIND); 11963d0407baSopenharmony_ci break; 11973d0407baSopenharmony_ci case 0x0b5: 11983d0407baSopenharmony_ci map_key_clear(KEY_NEXTSONG); 11993d0407baSopenharmony_ci break; 12003d0407baSopenharmony_ci case 0x0b6: 12013d0407baSopenharmony_ci map_key_clear(KEY_PREVIOUSSONG); 12023d0407baSopenharmony_ci break; 12033d0407baSopenharmony_ci case 0x0b7: 12043d0407baSopenharmony_ci map_key_clear(KEY_STOPCD); 12053d0407baSopenharmony_ci break; 12063d0407baSopenharmony_ci case 0x0b8: 12073d0407baSopenharmony_ci map_key_clear(KEY_EJECTCD); 12083d0407baSopenharmony_ci break; 12093d0407baSopenharmony_ci case 0x0bc: 12103d0407baSopenharmony_ci map_key_clear(KEY_MEDIA_REPEAT); 12113d0407baSopenharmony_ci break; 12123d0407baSopenharmony_ci case 0x0b9: 12133d0407baSopenharmony_ci map_key_clear(KEY_SHUFFLE); 12143d0407baSopenharmony_ci break; 12153d0407baSopenharmony_ci case 0x0bf: 12163d0407baSopenharmony_ci map_key_clear(KEY_SLOW); 12173d0407baSopenharmony_ci break; 12183d0407baSopenharmony_ci 12193d0407baSopenharmony_ci case 0x0cd: 12203d0407baSopenharmony_ci map_key_clear(KEY_PLAYPAUSE); 12213d0407baSopenharmony_ci break; 12223d0407baSopenharmony_ci case 0x0cf: 12233d0407baSopenharmony_ci map_key_clear(KEY_VOICECOMMAND); 12243d0407baSopenharmony_ci break; 12253d0407baSopenharmony_ci case 0x0d8: 12263d0407baSopenharmony_ci map_key_clear(KEY_DICTATE); 12273d0407baSopenharmony_ci break; 12283d0407baSopenharmony_ci 12293d0407baSopenharmony_ci case 0x0d9: 12303d0407baSopenharmony_ci map_key_clear(KEY_EMOJI_PICKER); 12313d0407baSopenharmony_ci break; 12323d0407baSopenharmony_ci 12333d0407baSopenharmony_ci case 0x0e0: 12343d0407baSopenharmony_ci map_abs_clear(ABS_VOLUME); 12353d0407baSopenharmony_ci break; 12363d0407baSopenharmony_ci case 0x0e2: 12373d0407baSopenharmony_ci map_key_clear(KEY_MUTE); 12383d0407baSopenharmony_ci break; 12393d0407baSopenharmony_ci case 0x0e5: 12403d0407baSopenharmony_ci map_key_clear(KEY_BASSBOOST); 12413d0407baSopenharmony_ci break; 12423d0407baSopenharmony_ci case 0x0e9: 12433d0407baSopenharmony_ci map_key_clear(KEY_VOLUMEUP); 12443d0407baSopenharmony_ci break; 12453d0407baSopenharmony_ci case 0x0ea: 12463d0407baSopenharmony_ci map_key_clear(KEY_VOLUMEDOWN); 12473d0407baSopenharmony_ci break; 12483d0407baSopenharmony_ci case 0x0f5: 12493d0407baSopenharmony_ci map_key_clear(KEY_SLOW); 12503d0407baSopenharmony_ci break; 12513d0407baSopenharmony_ci 12523d0407baSopenharmony_ci case 0x181: 12533d0407baSopenharmony_ci map_key_clear(KEY_BUTTONCONFIG); 12543d0407baSopenharmony_ci break; 12553d0407baSopenharmony_ci case 0x182: 12563d0407baSopenharmony_ci map_key_clear(KEY_BOOKMARKS); 12573d0407baSopenharmony_ci break; 12583d0407baSopenharmony_ci case 0x183: 12593d0407baSopenharmony_ci map_key_clear(KEY_CONFIG); 12603d0407baSopenharmony_ci break; 12613d0407baSopenharmony_ci case 0x184: 12623d0407baSopenharmony_ci map_key_clear(KEY_WORDPROCESSOR); 12633d0407baSopenharmony_ci break; 12643d0407baSopenharmony_ci case 0x185: 12653d0407baSopenharmony_ci map_key_clear(KEY_EDITOR); 12663d0407baSopenharmony_ci break; 12673d0407baSopenharmony_ci case 0x186: 12683d0407baSopenharmony_ci map_key_clear(KEY_SPREADSHEET); 12693d0407baSopenharmony_ci break; 12703d0407baSopenharmony_ci case 0x187: 12713d0407baSopenharmony_ci map_key_clear(KEY_GRAPHICSEDITOR); 12723d0407baSopenharmony_ci break; 12733d0407baSopenharmony_ci case 0x188: 12743d0407baSopenharmony_ci map_key_clear(KEY_PRESENTATION); 12753d0407baSopenharmony_ci break; 12763d0407baSopenharmony_ci case 0x189: 12773d0407baSopenharmony_ci map_key_clear(KEY_DATABASE); 12783d0407baSopenharmony_ci break; 12793d0407baSopenharmony_ci case 0x18a: 12803d0407baSopenharmony_ci map_key_clear(KEY_MAIL); 12813d0407baSopenharmony_ci break; 12823d0407baSopenharmony_ci case 0x18b: 12833d0407baSopenharmony_ci map_key_clear(KEY_NEWS); 12843d0407baSopenharmony_ci break; 12853d0407baSopenharmony_ci case 0x18c: 12863d0407baSopenharmony_ci map_key_clear(KEY_VOICEMAIL); 12873d0407baSopenharmony_ci break; 12883d0407baSopenharmony_ci case 0x18d: 12893d0407baSopenharmony_ci map_key_clear(KEY_ADDRESSBOOK); 12903d0407baSopenharmony_ci break; 12913d0407baSopenharmony_ci case 0x18e: 12923d0407baSopenharmony_ci map_key_clear(KEY_CALENDAR); 12933d0407baSopenharmony_ci break; 12943d0407baSopenharmony_ci case 0x18f: 12953d0407baSopenharmony_ci map_key_clear(KEY_TASKMANAGER); 12963d0407baSopenharmony_ci break; 12973d0407baSopenharmony_ci case 0x190: 12983d0407baSopenharmony_ci map_key_clear(KEY_JOURNAL); 12993d0407baSopenharmony_ci break; 13003d0407baSopenharmony_ci case 0x191: 13013d0407baSopenharmony_ci map_key_clear(KEY_FINANCE); 13023d0407baSopenharmony_ci break; 13033d0407baSopenharmony_ci case 0x192: 13043d0407baSopenharmony_ci map_key_clear(KEY_CALC); 13053d0407baSopenharmony_ci break; 13063d0407baSopenharmony_ci case 0x193: 13073d0407baSopenharmony_ci map_key_clear(KEY_PLAYER); 13083d0407baSopenharmony_ci break; 13093d0407baSopenharmony_ci case 0x194: 13103d0407baSopenharmony_ci map_key_clear(KEY_FILE); 13113d0407baSopenharmony_ci break; 13123d0407baSopenharmony_ci case 0x196: 13133d0407baSopenharmony_ci map_key_clear(KEY_WWW); 13143d0407baSopenharmony_ci break; 13153d0407baSopenharmony_ci case 0x199: 13163d0407baSopenharmony_ci map_key_clear(KEY_CHAT); 13173d0407baSopenharmony_ci break; 13183d0407baSopenharmony_ci case 0x19c: 13193d0407baSopenharmony_ci map_key_clear(KEY_LOGOFF); 13203d0407baSopenharmony_ci break; 13213d0407baSopenharmony_ci case 0x19e: 13223d0407baSopenharmony_ci map_key_clear(KEY_COFFEE); 13233d0407baSopenharmony_ci break; 13243d0407baSopenharmony_ci case 0x19f: 13253d0407baSopenharmony_ci map_key_clear(KEY_CONTROLPANEL); 13263d0407baSopenharmony_ci break; 13273d0407baSopenharmony_ci case 0x1a2: 13283d0407baSopenharmony_ci map_key_clear(KEY_APPSELECT); 13293d0407baSopenharmony_ci break; 13303d0407baSopenharmony_ci case 0x1a3: 13313d0407baSopenharmony_ci map_key_clear(KEY_NEXT); 13323d0407baSopenharmony_ci break; 13333d0407baSopenharmony_ci case 0x1a4: 13343d0407baSopenharmony_ci map_key_clear(KEY_PREVIOUS); 13353d0407baSopenharmony_ci break; 13363d0407baSopenharmony_ci case 0x1a6: 13373d0407baSopenharmony_ci map_key_clear(KEY_HELP); 13383d0407baSopenharmony_ci break; 13393d0407baSopenharmony_ci case 0x1a7: 13403d0407baSopenharmony_ci map_key_clear(KEY_DOCUMENTS); 13413d0407baSopenharmony_ci break; 13423d0407baSopenharmony_ci case 0x1ab: 13433d0407baSopenharmony_ci map_key_clear(KEY_SPELLCHECK); 13443d0407baSopenharmony_ci break; 13453d0407baSopenharmony_ci case 0x1ae: 13463d0407baSopenharmony_ci map_key_clear(KEY_KEYBOARD); 13473d0407baSopenharmony_ci break; 13483d0407baSopenharmony_ci case 0x1b1: 13493d0407baSopenharmony_ci map_key_clear(KEY_SCREENSAVER); 13503d0407baSopenharmony_ci break; 13513d0407baSopenharmony_ci case 0x1b4: 13523d0407baSopenharmony_ci map_key_clear(KEY_FILE); 13533d0407baSopenharmony_ci break; 13543d0407baSopenharmony_ci case 0x1b6: 13553d0407baSopenharmony_ci map_key_clear(KEY_IMAGES); 13563d0407baSopenharmony_ci break; 13573d0407baSopenharmony_ci case 0x1b7: 13583d0407baSopenharmony_ci map_key_clear(KEY_AUDIO); 13593d0407baSopenharmony_ci break; 13603d0407baSopenharmony_ci case 0x1b8: 13613d0407baSopenharmony_ci map_key_clear(KEY_VIDEO); 13623d0407baSopenharmony_ci break; 13633d0407baSopenharmony_ci case 0x1bc: 13643d0407baSopenharmony_ci map_key_clear(KEY_MESSENGER); 13653d0407baSopenharmony_ci break; 13663d0407baSopenharmony_ci case 0x1bd: 13673d0407baSopenharmony_ci map_key_clear(KEY_INFO); 13683d0407baSopenharmony_ci break; 13693d0407baSopenharmony_ci case 0x1cb: 13703d0407baSopenharmony_ci map_key_clear(KEY_ASSISTANT); 13713d0407baSopenharmony_ci break; 13723d0407baSopenharmony_ci case 0x201: 13733d0407baSopenharmony_ci map_key_clear(KEY_NEW); 13743d0407baSopenharmony_ci break; 13753d0407baSopenharmony_ci case 0x202: 13763d0407baSopenharmony_ci map_key_clear(KEY_OPEN); 13773d0407baSopenharmony_ci break; 13783d0407baSopenharmony_ci case 0x203: 13793d0407baSopenharmony_ci map_key_clear(KEY_CLOSE); 13803d0407baSopenharmony_ci break; 13813d0407baSopenharmony_ci case 0x204: 13823d0407baSopenharmony_ci map_key_clear(KEY_EXIT); 13833d0407baSopenharmony_ci break; 13843d0407baSopenharmony_ci case 0x207: 13853d0407baSopenharmony_ci map_key_clear(KEY_SAVE); 13863d0407baSopenharmony_ci break; 13873d0407baSopenharmony_ci case 0x208: 13883d0407baSopenharmony_ci map_key_clear(KEY_PRINT); 13893d0407baSopenharmony_ci break; 13903d0407baSopenharmony_ci case 0x209: 13913d0407baSopenharmony_ci map_key_clear(KEY_PROPS); 13923d0407baSopenharmony_ci break; 13933d0407baSopenharmony_ci case 0x21a: 13943d0407baSopenharmony_ci map_key_clear(KEY_UNDO); 13953d0407baSopenharmony_ci break; 13963d0407baSopenharmony_ci case 0x21b: 13973d0407baSopenharmony_ci map_key_clear(KEY_COPY); 13983d0407baSopenharmony_ci break; 13993d0407baSopenharmony_ci case 0x21c: 14003d0407baSopenharmony_ci map_key_clear(KEY_CUT); 14013d0407baSopenharmony_ci break; 14023d0407baSopenharmony_ci case 0x21d: 14033d0407baSopenharmony_ci map_key_clear(KEY_PASTE); 14043d0407baSopenharmony_ci break; 14053d0407baSopenharmony_ci case 0x21f: 14063d0407baSopenharmony_ci map_key_clear(KEY_FIND); 14073d0407baSopenharmony_ci break; 14083d0407baSopenharmony_ci case 0x221: 14093d0407baSopenharmony_ci map_key_clear(KEY_SEARCH); 14103d0407baSopenharmony_ci break; 14113d0407baSopenharmony_ci case 0x222: 14123d0407baSopenharmony_ci map_key_clear(KEY_GOTO); 14133d0407baSopenharmony_ci break; 14143d0407baSopenharmony_ci case 0x223: 14153d0407baSopenharmony_ci map_key_clear(KEY_HOMEPAGE); 14163d0407baSopenharmony_ci break; 14173d0407baSopenharmony_ci case 0x224: 14183d0407baSopenharmony_ci map_key_clear(KEY_BACK); 14193d0407baSopenharmony_ci break; 14203d0407baSopenharmony_ci case 0x225: 14213d0407baSopenharmony_ci map_key_clear(KEY_FORWARD); 14223d0407baSopenharmony_ci break; 14233d0407baSopenharmony_ci case 0x226: 14243d0407baSopenharmony_ci map_key_clear(KEY_STOP); 14253d0407baSopenharmony_ci break; 14263d0407baSopenharmony_ci case 0x227: 14273d0407baSopenharmony_ci map_key_clear(KEY_REFRESH); 14283d0407baSopenharmony_ci break; 14293d0407baSopenharmony_ci case 0x22a: 14303d0407baSopenharmony_ci map_key_clear(KEY_BOOKMARKS); 14313d0407baSopenharmony_ci break; 14323d0407baSopenharmony_ci case 0x22d: 14333d0407baSopenharmony_ci map_key_clear(KEY_ZOOMIN); 14343d0407baSopenharmony_ci break; 14353d0407baSopenharmony_ci case 0x22e: 14363d0407baSopenharmony_ci map_key_clear(KEY_ZOOMOUT); 14373d0407baSopenharmony_ci break; 14383d0407baSopenharmony_ci case 0x22f: 14393d0407baSopenharmony_ci map_key_clear(KEY_ZOOMRESET); 14403d0407baSopenharmony_ci break; 14413d0407baSopenharmony_ci case 0x232: 14423d0407baSopenharmony_ci map_key_clear(KEY_FULL_SCREEN); 14433d0407baSopenharmony_ci break; 14443d0407baSopenharmony_ci case 0x233: 14453d0407baSopenharmony_ci map_key_clear(KEY_SCROLLUP); 14463d0407baSopenharmony_ci break; 14473d0407baSopenharmony_ci case 0x234: 14483d0407baSopenharmony_ci map_key_clear(KEY_SCROLLDOWN); 14493d0407baSopenharmony_ci break; 14503d0407baSopenharmony_ci case 0x238: /* AC Pan */ 14513d0407baSopenharmony_ci set_bit(REL_HWHEEL, input->relbit); 14523d0407baSopenharmony_ci map_rel(REL_HWHEEL_HI_RES); 14533d0407baSopenharmony_ci break; 14543d0407baSopenharmony_ci case 0x23d: 14553d0407baSopenharmony_ci map_key_clear(KEY_EDIT); 14563d0407baSopenharmony_ci break; 14573d0407baSopenharmony_ci case 0x25f: 14583d0407baSopenharmony_ci map_key_clear(KEY_CANCEL); 14593d0407baSopenharmony_ci break; 14603d0407baSopenharmony_ci case 0x269: 14613d0407baSopenharmony_ci map_key_clear(KEY_INSERT); 14623d0407baSopenharmony_ci break; 14633d0407baSopenharmony_ci case 0x26a: 14643d0407baSopenharmony_ci map_key_clear(KEY_DELETE); 14653d0407baSopenharmony_ci break; 14663d0407baSopenharmony_ci case 0x279: 14673d0407baSopenharmony_ci map_key_clear(KEY_REDO); 14683d0407baSopenharmony_ci break; 14693d0407baSopenharmony_ci 14703d0407baSopenharmony_ci case 0x289: 14713d0407baSopenharmony_ci map_key_clear(KEY_REPLY); 14723d0407baSopenharmony_ci break; 14733d0407baSopenharmony_ci case 0x28b: 14743d0407baSopenharmony_ci map_key_clear(KEY_FORWARDMAIL); 14753d0407baSopenharmony_ci break; 14763d0407baSopenharmony_ci case 0x28c: 14773d0407baSopenharmony_ci map_key_clear(KEY_SEND); 14783d0407baSopenharmony_ci break; 14793d0407baSopenharmony_ci case 0x29d: 14803d0407baSopenharmony_ci map_key_clear(KEY_KBD_LAYOUT_NEXT); 14813d0407baSopenharmony_ci break; 14823d0407baSopenharmony_ci case 0x2a2: map_key_clear(KEY_ALL_APPLICATIONS); 14833d0407baSopenharmony_ci break; 14843d0407baSopenharmony_ci case 0x2c7: 14853d0407baSopenharmony_ci map_key_clear(KEY_KBDINPUTASSIST_PREV); 14863d0407baSopenharmony_ci break; 14873d0407baSopenharmony_ci case 0x2c8: 14883d0407baSopenharmony_ci map_key_clear(KEY_KBDINPUTASSIST_NEXT); 14893d0407baSopenharmony_ci break; 14903d0407baSopenharmony_ci case 0x2c9: 14913d0407baSopenharmony_ci map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); 14923d0407baSopenharmony_ci break; 14933d0407baSopenharmony_ci case 0x2ca: 14943d0407baSopenharmony_ci map_key_clear(KEY_KBDINPUTASSIST_NEXTGROUP); 14953d0407baSopenharmony_ci break; 14963d0407baSopenharmony_ci case 0x2cb: 14973d0407baSopenharmony_ci map_key_clear(KEY_KBDINPUTASSIST_ACCEPT); 14983d0407baSopenharmony_ci break; 14993d0407baSopenharmony_ci case 0x2cc: 15003d0407baSopenharmony_ci map_key_clear(KEY_KBDINPUTASSIST_CANCEL); 15013d0407baSopenharmony_ci break; 15023d0407baSopenharmony_ci case 0x29f: 15033d0407baSopenharmony_ci map_key_clear(KEY_SCALE); 15043d0407baSopenharmony_ci break; 15053d0407baSopenharmony_ci default: 15063d0407baSopenharmony_ci map_key_clear(KEY_UNKNOWN); 15073d0407baSopenharmony_ci } 15083d0407baSopenharmony_ci break; 15093d0407baSopenharmony_ci 15103d0407baSopenharmony_ci case HID_UP_GENDEVCTRLS: 15113d0407baSopenharmony_ci switch (usage->hid) { 15123d0407baSopenharmony_ci case HID_DC_BATTERYSTRENGTH: 15133d0407baSopenharmony_ci hidinput_setup_battery(device, HID_INPUT_REPORT, field); 15143d0407baSopenharmony_ci usage->type = EV_PWR; 15153d0407baSopenharmony_ci return; 15163d0407baSopenharmony_ci default: 15173d0407baSopenharmony_ci break; 15183d0407baSopenharmony_ci } 15193d0407baSopenharmony_ci goto unknown; 15203d0407baSopenharmony_ci 15213d0407baSopenharmony_ci case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ 15223d0407baSopenharmony_ci set_bit(EV_REP, input->evbit); 15233d0407baSopenharmony_ci switch (usage->hid & HID_USAGE) { 15243d0407baSopenharmony_ci case 0x021: 15253d0407baSopenharmony_ci map_key_clear(KEY_PRINT); 15263d0407baSopenharmony_ci break; 15273d0407baSopenharmony_ci case 0x070: 15283d0407baSopenharmony_ci map_key_clear(KEY_HP); 15293d0407baSopenharmony_ci break; 15303d0407baSopenharmony_ci case 0x071: 15313d0407baSopenharmony_ci map_key_clear(KEY_CAMERA); 15323d0407baSopenharmony_ci break; 15333d0407baSopenharmony_ci case 0x072: 15343d0407baSopenharmony_ci map_key_clear(KEY_SOUND); 15353d0407baSopenharmony_ci break; 15363d0407baSopenharmony_ci case 0x073: 15373d0407baSopenharmony_ci map_key_clear(KEY_QUESTION); 15383d0407baSopenharmony_ci break; 15393d0407baSopenharmony_ci case 0x080: 15403d0407baSopenharmony_ci map_key_clear(KEY_EMAIL); 15413d0407baSopenharmony_ci break; 15423d0407baSopenharmony_ci case 0x081: 15433d0407baSopenharmony_ci map_key_clear(KEY_CHAT); 15443d0407baSopenharmony_ci break; 15453d0407baSopenharmony_ci case 0x082: 15463d0407baSopenharmony_ci map_key_clear(KEY_SEARCH); 15473d0407baSopenharmony_ci break; 15483d0407baSopenharmony_ci case 0x083: 15493d0407baSopenharmony_ci map_key_clear(KEY_CONNECT); 15503d0407baSopenharmony_ci break; 15513d0407baSopenharmony_ci case 0x084: 15523d0407baSopenharmony_ci map_key_clear(KEY_FINANCE); 15533d0407baSopenharmony_ci break; 15543d0407baSopenharmony_ci case 0x085: 15553d0407baSopenharmony_ci map_key_clear(KEY_SPORT); 15563d0407baSopenharmony_ci break; 15573d0407baSopenharmony_ci case 0x086: 15583d0407baSopenharmony_ci map_key_clear(KEY_SHOP); 15593d0407baSopenharmony_ci break; 15603d0407baSopenharmony_ci default: 15613d0407baSopenharmony_ci goto ignore; 15623d0407baSopenharmony_ci } 15633d0407baSopenharmony_ci break; 15643d0407baSopenharmony_ci 15653d0407baSopenharmony_ci case HID_UP_HPVENDOR2: 15663d0407baSopenharmony_ci set_bit(EV_REP, input->evbit); 15673d0407baSopenharmony_ci switch (usage->hid & HID_USAGE) { 15683d0407baSopenharmony_ci case 0x001: 15693d0407baSopenharmony_ci map_key_clear(KEY_MICMUTE); 15703d0407baSopenharmony_ci break; 15713d0407baSopenharmony_ci case 0x003: 15723d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESSDOWN); 15733d0407baSopenharmony_ci break; 15743d0407baSopenharmony_ci case 0x004: 15753d0407baSopenharmony_ci map_key_clear(KEY_BRIGHTNESSUP); 15763d0407baSopenharmony_ci break; 15773d0407baSopenharmony_ci default: 15783d0407baSopenharmony_ci goto ignore; 15793d0407baSopenharmony_ci } 15803d0407baSopenharmony_ci break; 15813d0407baSopenharmony_ci 15823d0407baSopenharmony_ci case HID_UP_MSVENDOR: 15833d0407baSopenharmony_ci goto ignore; 15843d0407baSopenharmony_ci 15853d0407baSopenharmony_ci case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */ 15863d0407baSopenharmony_ci set_bit(EV_REP, input->evbit); 15873d0407baSopenharmony_ci goto ignore; 15883d0407baSopenharmony_ci 15893d0407baSopenharmony_ci case HID_UP_LOGIVENDOR: 15903d0407baSopenharmony_ci /* intentional fallback */ 15913d0407baSopenharmony_ci case HID_UP_LOGIVENDOR2: 15923d0407baSopenharmony_ci /* intentional fallback */ 15933d0407baSopenharmony_ci case HID_UP_LOGIVENDOR3: 15943d0407baSopenharmony_ci goto ignore; 15953d0407baSopenharmony_ci 15963d0407baSopenharmony_ci case HID_UP_PID: 15973d0407baSopenharmony_ci switch (usage->hid & HID_USAGE) { 15983d0407baSopenharmony_ci case 0xa4: 15993d0407baSopenharmony_ci map_key_clear(BTN_DEAD); 16003d0407baSopenharmony_ci break; 16013d0407baSopenharmony_ci default: 16023d0407baSopenharmony_ci goto ignore; 16033d0407baSopenharmony_ci } 16043d0407baSopenharmony_ci break; 16053d0407baSopenharmony_ci 16063d0407baSopenharmony_ci default: 16073d0407baSopenharmony_ci unknown: 16083d0407baSopenharmony_ci if (field->report_size == 1) { 16093d0407baSopenharmony_ci if (field->report->type == HID_OUTPUT_REPORT) { 16103d0407baSopenharmony_ci map_led(LED_MISC); 16113d0407baSopenharmony_ci break; 16123d0407baSopenharmony_ci } 16133d0407baSopenharmony_ci map_key(BTN_MISC); 16143d0407baSopenharmony_ci break; 16153d0407baSopenharmony_ci } 16163d0407baSopenharmony_ci if (field->flags & HID_MAIN_ITEM_RELATIVE) { 16173d0407baSopenharmony_ci map_rel(REL_MISC); 16183d0407baSopenharmony_ci break; 16193d0407baSopenharmony_ci } 16203d0407baSopenharmony_ci map_abs(ABS_MISC); 16213d0407baSopenharmony_ci break; 16223d0407baSopenharmony_ci } 16233d0407baSopenharmony_ci 16243d0407baSopenharmony_cimapped: 16253d0407baSopenharmony_ci /* Mapping failed, bail out */ 16263d0407baSopenharmony_ci if (!bit) { 16273d0407baSopenharmony_ci return; 16283d0407baSopenharmony_ci } 16293d0407baSopenharmony_ci 16303d0407baSopenharmony_ci if (device->driver->input_mapped && device->driver->input_mapped(device, hidinput, field, usage, &bit, &max) < 0) { 16313d0407baSopenharmony_ci /* 16323d0407baSopenharmony_ci * The driver indicated that no further generic handling 16333d0407baSopenharmony_ci * of the usage is desired. 16343d0407baSopenharmony_ci */ 16353d0407baSopenharmony_ci return; 16363d0407baSopenharmony_ci } 16373d0407baSopenharmony_ci 16383d0407baSopenharmony_ci set_bit(usage->type, input->evbit); 16393d0407baSopenharmony_ci 16403d0407baSopenharmony_ci /* 16413d0407baSopenharmony_ci * This part is *really* controversial: 16423d0407baSopenharmony_ci * - HID aims at being generic so we should do our best to export 16433d0407baSopenharmony_ci * all incoming events 16443d0407baSopenharmony_ci * - HID describes what events are, so there is no reason for ABS_X 16453d0407baSopenharmony_ci * to be mapped to ABS_Y 16463d0407baSopenharmony_ci * - HID is using *_MISC+N as a default value, but nothing prevents 16473d0407baSopenharmony_ci * *_MISC+N to overwrite a legitimate even, which confuses userspace 16483d0407baSopenharmony_ci * (for instance ABS_MISC + 7 is ABS_MT_SLOT, which has a different 16493d0407baSopenharmony_ci * processing) 16503d0407baSopenharmony_ci * 16513d0407baSopenharmony_ci * If devices still want to use this (at their own risk), they will 16523d0407baSopenharmony_ci * have to use the quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE, but 16533d0407baSopenharmony_ci * the default should be a reliable mapping. 16543d0407baSopenharmony_ci */ 16553d0407baSopenharmony_ci while (usage->code <= max && test_and_set_bit(usage->code, bit)) { 16563d0407baSopenharmony_ci if (device->quirks & HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE) { 16573d0407baSopenharmony_ci usage->code = find_next_zero_bit(bit, max + 1, usage->code); 16583d0407baSopenharmony_ci } else { 16593d0407baSopenharmony_ci device->status |= HID_STAT_DUP_DETECTED; 16603d0407baSopenharmony_ci goto ignore; 16613d0407baSopenharmony_ci } 16623d0407baSopenharmony_ci } 16633d0407baSopenharmony_ci 16643d0407baSopenharmony_ci if (usage->code > max) { 16653d0407baSopenharmony_ci goto ignore; 16663d0407baSopenharmony_ci } 16673d0407baSopenharmony_ci 16683d0407baSopenharmony_ci if (usage->type == EV_ABS) { 16693d0407baSopenharmony_ci int a = field->logical_minimum; 16703d0407baSopenharmony_ci int b = field->logical_maximum; 16713d0407baSopenharmony_ci 16723d0407baSopenharmony_ci if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { 16733d0407baSopenharmony_ci a = field->logical_minimum = 0; 16743d0407baSopenharmony_ci b = field->logical_maximum = 0xFF; 16753d0407baSopenharmony_ci } 16763d0407baSopenharmony_ci 16773d0407baSopenharmony_ci if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) { 16783d0407baSopenharmony_ci input_set_abs_params(input, usage->code, a, b, (b - a) >> 0x8, (b - a) >> 0x4); 16793d0407baSopenharmony_ci } else { 16803d0407baSopenharmony_ci input_set_abs_params(input, usage->code, a, b, 0, 0); 16813d0407baSopenharmony_ci } 16823d0407baSopenharmony_ci 16833d0407baSopenharmony_ci input_abs_set_res(input, usage->code, hidinput_calc_abs_res(field, usage->code)); 16843d0407baSopenharmony_ci 16853d0407baSopenharmony_ci /* use a larger default input buffer for MT devices */ 16863d0407baSopenharmony_ci if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0) { 16873d0407baSopenharmony_ci input_set_events_per_packet(input, 0x3C); 16883d0407baSopenharmony_ci } 16893d0407baSopenharmony_ci } 16903d0407baSopenharmony_ci 16913d0407baSopenharmony_ci if (usage->type == EV_ABS && (usage->hat_min < usage->hat_max || usage->hat_dir)) { 16923d0407baSopenharmony_ci int i; 16933d0407baSopenharmony_ci for (i = usage->code; i < usage->code + 0x2 && i <= max; i++) { 16943d0407baSopenharmony_ci input_set_abs_params(input, i, -1, 1, 0, 0); 16953d0407baSopenharmony_ci set_bit(i, input->absbit); 16963d0407baSopenharmony_ci } 16973d0407baSopenharmony_ci if (usage->hat_dir && !field->dpad) { 16983d0407baSopenharmony_ci field->dpad = usage->code; 16993d0407baSopenharmony_ci } 17003d0407baSopenharmony_ci } 17013d0407baSopenharmony_ci 17023d0407baSopenharmony_ci /* for those devices which produce Consumer volume usage as relative, 17033d0407baSopenharmony_ci * we emulate pressing volumeup/volumedown appropriate number of times 17043d0407baSopenharmony_ci * in hidinput_hid_event() 17053d0407baSopenharmony_ci */ 17063d0407baSopenharmony_ci if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->code == ABS_VOLUME)) { 17073d0407baSopenharmony_ci set_bit(KEY_VOLUMEUP, input->keybit); 17083d0407baSopenharmony_ci set_bit(KEY_VOLUMEDOWN, input->keybit); 17093d0407baSopenharmony_ci } 17103d0407baSopenharmony_ci 17113d0407baSopenharmony_ci if (usage->type == EV_KEY) { 17123d0407baSopenharmony_ci set_bit(EV_MSC, input->evbit); 17133d0407baSopenharmony_ci set_bit(MSC_SCAN, input->mscbit); 17143d0407baSopenharmony_ci } 17153d0407baSopenharmony_ci 17163d0407baSopenharmony_ci return; 17173d0407baSopenharmony_ci 17183d0407baSopenharmony_ciignore: 17193d0407baSopenharmony_ci usage->type = 0; 17203d0407baSopenharmony_ci usage->code = 0; 17213d0407baSopenharmony_ci} 17223d0407baSopenharmony_ci 17233d0407baSopenharmony_cistatic void hidinput_handle_scroll(struct hid_usage *usage, struct input_dev *input, __s32 value) 17243d0407baSopenharmony_ci{ 17253d0407baSopenharmony_ci int code; 17263d0407baSopenharmony_ci int hi_res, lo_res; 17273d0407baSopenharmony_ci 17283d0407baSopenharmony_ci if (value == 0) { 17293d0407baSopenharmony_ci return; 17303d0407baSopenharmony_ci } 17313d0407baSopenharmony_ci 17323d0407baSopenharmony_ci if (usage->code == REL_WHEEL_HI_RES) { 17333d0407baSopenharmony_ci code = REL_WHEEL; 17343d0407baSopenharmony_ci } else { 17353d0407baSopenharmony_ci code = REL_HWHEEL; 17363d0407baSopenharmony_ci } 17373d0407baSopenharmony_ci 17383d0407baSopenharmony_ci /* 17393d0407baSopenharmony_ci * Windows reports one wheel click as value 120. Where a high-res 17403d0407baSopenharmony_ci * scroll wheel is present, a fraction of 120 is reported instead. 17413d0407baSopenharmony_ci * Our REL_WHEEL_HI_RES axis does the same because all HW must 17423d0407baSopenharmony_ci * adhere to the 120 expectation. 17433d0407baSopenharmony_ci */ 17443d0407baSopenharmony_ci hi_res = value * 0x78 / usage->resolution_multiplier; 17453d0407baSopenharmony_ci 17463d0407baSopenharmony_ci usage->wheel_accumulated += hi_res; 17473d0407baSopenharmony_ci lo_res = usage->wheel_accumulated / 0x78; 17483d0407baSopenharmony_ci if (lo_res) { 17493d0407baSopenharmony_ci usage->wheel_accumulated -= lo_res * 0x78; 17503d0407baSopenharmony_ci } 17513d0407baSopenharmony_ci 17523d0407baSopenharmony_ci input_event(input, EV_REL, code, lo_res); 17533d0407baSopenharmony_ci input_event(input, EV_REL, usage->code, hi_res); 17543d0407baSopenharmony_ci} 17553d0407baSopenharmony_ci 17563d0407baSopenharmony_civoid hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) 17573d0407baSopenharmony_ci{ 17583d0407baSopenharmony_ci struct input_dev *input; 17593d0407baSopenharmony_ci unsigned *quirks = &hid->quirks; 17603d0407baSopenharmony_ci 17613d0407baSopenharmony_ci if (!usage->type) { 17623d0407baSopenharmony_ci return; 17633d0407baSopenharmony_ci } 17643d0407baSopenharmony_ci 17653d0407baSopenharmony_ci if (usage->type == EV_PWR) { 17663d0407baSopenharmony_ci hidinput_update_battery(hid, value); 17673d0407baSopenharmony_ci return; 17683d0407baSopenharmony_ci } 17693d0407baSopenharmony_ci 17703d0407baSopenharmony_ci if (!field->hidinput) { 17713d0407baSopenharmony_ci return; 17723d0407baSopenharmony_ci } 17733d0407baSopenharmony_ci 17743d0407baSopenharmony_ci input = field->hidinput->input; 17753d0407baSopenharmony_ci 17763d0407baSopenharmony_ci if (usage->type == EV_ABS && 17773d0407baSopenharmony_ci (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) || 17783d0407baSopenharmony_ci ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) { 17793d0407baSopenharmony_ci value = field->logical_maximum - value; 17803d0407baSopenharmony_ci } 17813d0407baSopenharmony_ci 17823d0407baSopenharmony_ci if (usage->hat_min < usage->hat_max || usage->hat_dir) { 17833d0407baSopenharmony_ci int hat_dir = usage->hat_dir; 17843d0407baSopenharmony_ci if (!hat_dir) { 17853d0407baSopenharmony_ci hat_dir = (value - usage->hat_min) * 0x8 / (usage->hat_max - usage->hat_min + 1) + 1; 17863d0407baSopenharmony_ci } 17873d0407baSopenharmony_ci if (hat_dir < 0 || hat_dir > 0x8) { 17883d0407baSopenharmony_ci hat_dir = 0; 17893d0407baSopenharmony_ci } 17903d0407baSopenharmony_ci input_event(input, usage->type, usage->code, hid_hat_to_axis[hat_dir].x); 17913d0407baSopenharmony_ci input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); 17923d0407baSopenharmony_ci return; 17933d0407baSopenharmony_ci } 17943d0407baSopenharmony_ci 17953d0407baSopenharmony_ci if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ 17963d0407baSopenharmony_ci *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); 17973d0407baSopenharmony_ci return; 17983d0407baSopenharmony_ci } 17993d0407baSopenharmony_ci 18003d0407baSopenharmony_ci if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ 18013d0407baSopenharmony_ci if (value) { 18023d0407baSopenharmony_ci input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); 18033d0407baSopenharmony_ci return; 18043d0407baSopenharmony_ci } 18053d0407baSopenharmony_ci input_event(input, usage->type, usage->code, 0); 18063d0407baSopenharmony_ci input_event(input, usage->type, BTN_TOOL_RUBBER, 0); 18073d0407baSopenharmony_ci return; 18083d0407baSopenharmony_ci } 18093d0407baSopenharmony_ci 18103d0407baSopenharmony_ci if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ 18113d0407baSopenharmony_ci int a = field->logical_minimum; 18123d0407baSopenharmony_ci int b = field->logical_maximum; 18133d0407baSopenharmony_ci input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 0x3)); 18143d0407baSopenharmony_ci } 18153d0407baSopenharmony_ci 18163d0407baSopenharmony_ci if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ 18173d0407baSopenharmony_ci dbg_hid("Maximum Effects - %d\n", value); 18183d0407baSopenharmony_ci return; 18193d0407baSopenharmony_ci } 18203d0407baSopenharmony_ci 18213d0407baSopenharmony_ci if (usage->hid == (HID_UP_PID | 0x7fUL)) { 18223d0407baSopenharmony_ci dbg_hid("PID Pool Report\n"); 18233d0407baSopenharmony_ci return; 18243d0407baSopenharmony_ci } 18253d0407baSopenharmony_ci 18263d0407baSopenharmony_ci if ((usage->type == EV_KEY) && (usage->code == 0)) { /* Key 0 is "unassigned", not KEY_UNKNOWN */ 18273d0407baSopenharmony_ci return; 18283d0407baSopenharmony_ci } 18293d0407baSopenharmony_ci 18303d0407baSopenharmony_ci if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES || usage->code == REL_HWHEEL_HI_RES)) { 18313d0407baSopenharmony_ci hidinput_handle_scroll(usage, input, value); 18323d0407baSopenharmony_ci return; 18333d0407baSopenharmony_ci } 18343d0407baSopenharmony_ci 18353d0407baSopenharmony_ci if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->code == ABS_VOLUME)) { 18363d0407baSopenharmony_ci int count = abs(value); 18373d0407baSopenharmony_ci int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN; 18383d0407baSopenharmony_ci int i; 18393d0407baSopenharmony_ci 18403d0407baSopenharmony_ci for (i = 0; i < count; i++) { 18413d0407baSopenharmony_ci input_event(input, EV_KEY, direction, 1); 18423d0407baSopenharmony_ci input_sync(input); 18433d0407baSopenharmony_ci input_event(input, EV_KEY, direction, 0); 18443d0407baSopenharmony_ci input_sync(input); 18453d0407baSopenharmony_ci } 18463d0407baSopenharmony_ci return; 18473d0407baSopenharmony_ci } 18483d0407baSopenharmony_ci 18493d0407baSopenharmony_ci /* 18503d0407baSopenharmony_ci * Ignore out-of-range values as per HID specification, 18513d0407baSopenharmony_ci * section 5.10 and 6.2.25, when NULL state bit is present. 18523d0407baSopenharmony_ci * When it's not, clamp the value to match Microsoft's input 18533d0407baSopenharmony_ci * driver as mentioned in "Required HID usages for digitizers": 18543d0407baSopenharmony_ci * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp 18553d0407baSopenharmony_ci * 18563d0407baSopenharmony_ci * The logical_minimum < logical_maximum check is done so that we 18573d0407baSopenharmony_ci * don't unintentionally discard values sent by devices which 18583d0407baSopenharmony_ci * don't specify logical min and max. 18593d0407baSopenharmony_ci */ 18603d0407baSopenharmony_ci if ((field->flags & HID_MAIN_ITEM_VARIABLE) && (field->logical_minimum < field->logical_maximum)) { 18613d0407baSopenharmony_ci if (field->flags & HID_MAIN_ITEM_NULL_STATE && 18623d0407baSopenharmony_ci (value < field->logical_minimum || value > field->logical_maximum)) { 18633d0407baSopenharmony_ci dbg_hid("Ignoring out-of-range value %x\n", value); 18643d0407baSopenharmony_ci return; 18653d0407baSopenharmony_ci } 18663d0407baSopenharmony_ci value = clamp(value, field->logical_minimum, field->logical_maximum); 18673d0407baSopenharmony_ci } 18683d0407baSopenharmony_ci 18693d0407baSopenharmony_ci /* 18703d0407baSopenharmony_ci * Ignore reports for absolute data if the data didn't change. This is 18713d0407baSopenharmony_ci * not only an optimization but also fixes 'dead' key reports. Some 18723d0407baSopenharmony_ci * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID 18733d0407baSopenharmony_ci * 0x31 and 0x32) report multiple keys, even though a localized keyboard 18743d0407baSopenharmony_ci * can only have one of them physically available. The 'dead' keys 18753d0407baSopenharmony_ci * report constant 0. As all map to the same keycode, they'd confuse 18763d0407baSopenharmony_ci * the input layer. If we filter the 'dead' keys on the HID level, we 18773d0407baSopenharmony_ci * skip the keycode translation and only forward real events. 18783d0407baSopenharmony_ci */ 18793d0407baSopenharmony_ci if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_BUFFERED_BYTE)) && 18803d0407baSopenharmony_ci (field->flags & HID_MAIN_ITEM_VARIABLE) && usage->usage_index < field->maxusage && 18813d0407baSopenharmony_ci value == field->value[usage->usage_index]) { 18823d0407baSopenharmony_ci return; 18833d0407baSopenharmony_ci } 18843d0407baSopenharmony_ci 18853d0407baSopenharmony_ci /* report the usage code as scancode if the key status has changed */ 18863d0407baSopenharmony_ci if (usage->type == EV_KEY && (!test_bit(usage->code, input->key)) == value) { 18873d0407baSopenharmony_ci input_event(input, EV_MSC, MSC_SCAN, usage->hid); 18883d0407baSopenharmony_ci } 18893d0407baSopenharmony_ci 18903d0407baSopenharmony_ci input_event(input, usage->type, usage->code, value); 18913d0407baSopenharmony_ci 18923d0407baSopenharmony_ci if ((field->flags & HID_MAIN_ITEM_RELATIVE) && usage->type == EV_KEY && value) { 18933d0407baSopenharmony_ci input_sync(input); 18943d0407baSopenharmony_ci input_event(input, usage->type, usage->code, 0); 18953d0407baSopenharmony_ci } 18963d0407baSopenharmony_ci} 18973d0407baSopenharmony_ci 18983d0407baSopenharmony_civoid hidinput_report_event(struct hid_device *hid, struct hid_report *report) 18993d0407baSopenharmony_ci{ 19003d0407baSopenharmony_ci struct hid_input *hidinput; 19013d0407baSopenharmony_ci 19023d0407baSopenharmony_ci if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC) { 19033d0407baSopenharmony_ci return; 19043d0407baSopenharmony_ci } 19053d0407baSopenharmony_ci 19063d0407baSopenharmony_ci list_for_each_entry(hidinput, &hid->inputs, list) input_sync(hidinput->input); 19073d0407baSopenharmony_ci} 19083d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_report_event); 19093d0407baSopenharmony_ci 19103d0407baSopenharmony_ciint hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) 19113d0407baSopenharmony_ci{ 19123d0407baSopenharmony_ci struct hid_report *report; 19133d0407baSopenharmony_ci int i, j; 19143d0407baSopenharmony_ci 19153d0407baSopenharmony_ci list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) 19163d0407baSopenharmony_ci { 19173d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 19183d0407baSopenharmony_ci *field = report->field[i]; 19193d0407baSopenharmony_ci for (j = 0; j < (*field)->maxusage; j++) { 19203d0407baSopenharmony_ci if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) { 19213d0407baSopenharmony_ci return j; 19223d0407baSopenharmony_ci } 19233d0407baSopenharmony_ci } 19243d0407baSopenharmony_ci } 19253d0407baSopenharmony_ci } 19263d0407baSopenharmony_ci return -1; 19273d0407baSopenharmony_ci} 19283d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_find_field); 19293d0407baSopenharmony_ci 19303d0407baSopenharmony_cistruct hid_field *hidinput_get_led_field(struct hid_device *hid) 19313d0407baSopenharmony_ci{ 19323d0407baSopenharmony_ci struct hid_report *report; 19333d0407baSopenharmony_ci struct hid_field *field; 19343d0407baSopenharmony_ci int i, j; 19353d0407baSopenharmony_ci 19363d0407baSopenharmony_ci list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) 19373d0407baSopenharmony_ci { 19383d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 19393d0407baSopenharmony_ci field = report->field[i]; 19403d0407baSopenharmony_ci for (j = 0; j < field->maxusage; j++) { 19413d0407baSopenharmony_ci if (field->usage[j].type == EV_LED) { 19423d0407baSopenharmony_ci return field; 19433d0407baSopenharmony_ci } 19443d0407baSopenharmony_ci } 19453d0407baSopenharmony_ci } 19463d0407baSopenharmony_ci } 19473d0407baSopenharmony_ci return NULL; 19483d0407baSopenharmony_ci} 19493d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_get_led_field); 19503d0407baSopenharmony_ci 19513d0407baSopenharmony_ciunsigned int hidinput_count_leds(struct hid_device *hid) 19523d0407baSopenharmony_ci{ 19533d0407baSopenharmony_ci struct hid_report *report; 19543d0407baSopenharmony_ci struct hid_field *field; 19553d0407baSopenharmony_ci int i, j; 19563d0407baSopenharmony_ci unsigned int count = 0; 19573d0407baSopenharmony_ci 19583d0407baSopenharmony_ci list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) 19593d0407baSopenharmony_ci { 19603d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 19613d0407baSopenharmony_ci field = report->field[i]; 19623d0407baSopenharmony_ci for (j = 0; j < field->maxusage; j++) { 19633d0407baSopenharmony_ci if (field->usage[j].type == EV_LED && field->value[j]) { 19643d0407baSopenharmony_ci count += 1; 19653d0407baSopenharmony_ci } 19663d0407baSopenharmony_ci } 19673d0407baSopenharmony_ci } 19683d0407baSopenharmony_ci } 19693d0407baSopenharmony_ci return count; 19703d0407baSopenharmony_ci} 19713d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_count_leds); 19723d0407baSopenharmony_ci 19733d0407baSopenharmony_cistatic void hidinput_led_worker(struct work_struct *work) 19743d0407baSopenharmony_ci{ 19753d0407baSopenharmony_ci struct hid_device *hid = container_of(work, struct hid_device, led_work); 19763d0407baSopenharmony_ci struct hid_field *field; 19773d0407baSopenharmony_ci struct hid_report *report; 19783d0407baSopenharmony_ci int ret; 19793d0407baSopenharmony_ci u32 len; 19803d0407baSopenharmony_ci __u8 *buf; 19813d0407baSopenharmony_ci 19823d0407baSopenharmony_ci field = hidinput_get_led_field(hid); 19833d0407baSopenharmony_ci if (!field) { 19843d0407baSopenharmony_ci return; 19853d0407baSopenharmony_ci } 19863d0407baSopenharmony_ci 19873d0407baSopenharmony_ci /* 19883d0407baSopenharmony_ci * field->report is accessed unlocked regarding HID core. So there might 19893d0407baSopenharmony_ci * be another incoming SET-LED request from user-space, which changes 19903d0407baSopenharmony_ci * the LED state while we assemble our outgoing buffer. However, this 19913d0407baSopenharmony_ci * doesn't matter as hid_output_report() correctly converts it into a 19923d0407baSopenharmony_ci * boolean value no matter what information is currently set on the LED 19933d0407baSopenharmony_ci * field (even garbage). So the remote device will always get a valid 19943d0407baSopenharmony_ci * request. 19953d0407baSopenharmony_ci * And in case we send a wrong value, a next led worker is spawned 19963d0407baSopenharmony_ci * for every SET-LED request so the following worker will send the 19973d0407baSopenharmony_ci * correct value, guaranteed! 19983d0407baSopenharmony_ci */ 19993d0407baSopenharmony_ci 20003d0407baSopenharmony_ci report = field->report; 20013d0407baSopenharmony_ci 20023d0407baSopenharmony_ci /* use custom SET_REPORT request if possible (asynchronous) */ 20033d0407baSopenharmony_ci if (hid->ll_driver->request) { 20043d0407baSopenharmony_ci return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT); 20053d0407baSopenharmony_ci } 20063d0407baSopenharmony_ci 20073d0407baSopenharmony_ci /* fall back to generic raw-output-report */ 20083d0407baSopenharmony_ci len = hid_report_len(report); 20093d0407baSopenharmony_ci buf = hid_alloc_report_buf(report, GFP_KERNEL); 20103d0407baSopenharmony_ci if (!buf) { 20113d0407baSopenharmony_ci return; 20123d0407baSopenharmony_ci } 20133d0407baSopenharmony_ci 20143d0407baSopenharmony_ci hid_output_report(report, buf); 20153d0407baSopenharmony_ci /* synchronous output report */ 20163d0407baSopenharmony_ci ret = hid_hw_output_report(hid, buf, len); 20173d0407baSopenharmony_ci if (ret == -ENOSYS) { 20183d0407baSopenharmony_ci hid_hw_raw_request(hid, report->id, buf, len, HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 20193d0407baSopenharmony_ci } 20203d0407baSopenharmony_ci kfree(buf); 20213d0407baSopenharmony_ci} 20223d0407baSopenharmony_ci 20233d0407baSopenharmony_cistatic int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 20243d0407baSopenharmony_ci{ 20253d0407baSopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 20263d0407baSopenharmony_ci struct hid_field *field; 20273d0407baSopenharmony_ci int offset; 20283d0407baSopenharmony_ci 20293d0407baSopenharmony_ci if (type == EV_FF) { 20303d0407baSopenharmony_ci return input_ff_event(dev, type, code, value); 20313d0407baSopenharmony_ci } 20323d0407baSopenharmony_ci 20333d0407baSopenharmony_ci if (type != EV_LED) { 20343d0407baSopenharmony_ci return -1; 20353d0407baSopenharmony_ci } 20363d0407baSopenharmony_ci 20373d0407baSopenharmony_ci if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { 20383d0407baSopenharmony_ci hid_warn(dev, "event field not found\n"); 20393d0407baSopenharmony_ci return -1; 20403d0407baSopenharmony_ci } 20413d0407baSopenharmony_ci 20423d0407baSopenharmony_ci hid_set_field(field, offset, value); 20433d0407baSopenharmony_ci 20443d0407baSopenharmony_ci schedule_work(&hid->led_work); 20453d0407baSopenharmony_ci return 0; 20463d0407baSopenharmony_ci} 20473d0407baSopenharmony_ci 20483d0407baSopenharmony_cistatic int hidinput_open(struct input_dev *dev) 20493d0407baSopenharmony_ci{ 20503d0407baSopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 20513d0407baSopenharmony_ci 20523d0407baSopenharmony_ci return hid_hw_open(hid); 20533d0407baSopenharmony_ci} 20543d0407baSopenharmony_ci 20553d0407baSopenharmony_cistatic void hidinput_close(struct input_dev *dev) 20563d0407baSopenharmony_ci{ 20573d0407baSopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 20583d0407baSopenharmony_ci 20593d0407baSopenharmony_ci hid_hw_close(hid); 20603d0407baSopenharmony_ci} 20613d0407baSopenharmony_ci 20623d0407baSopenharmony_cistatic bool __hidinput_change_resolution_multipliers(struct hid_device *hid, struct hid_report *report, 20633d0407baSopenharmony_ci bool use_logical_max) 20643d0407baSopenharmony_ci{ 20653d0407baSopenharmony_ci struct hid_usage *usage; 20663d0407baSopenharmony_ci bool update_needed = false; 20673d0407baSopenharmony_ci bool get_report_completed = false; 20683d0407baSopenharmony_ci int i, j; 20693d0407baSopenharmony_ci 20703d0407baSopenharmony_ci if (report->maxfield == 0) { 20713d0407baSopenharmony_ci return false; 20723d0407baSopenharmony_ci } 20733d0407baSopenharmony_ci 20743d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 20753d0407baSopenharmony_ci __s32 value = use_logical_max ? report->field[i]->logical_maximum : report->field[i]->logical_minimum; 20763d0407baSopenharmony_ci 20773d0407baSopenharmony_ci /* There is no good reason for a Resolution 20783d0407baSopenharmony_ci * Multiplier to have a count other than 1. 20793d0407baSopenharmony_ci * Ignore that case. 20803d0407baSopenharmony_ci */ 20813d0407baSopenharmony_ci if (report->field[i]->report_count != 1) { 20823d0407baSopenharmony_ci continue; 20833d0407baSopenharmony_ci } 20843d0407baSopenharmony_ci 20853d0407baSopenharmony_ci for (j = 0; j < report->field[i]->maxusage; j++) { 20863d0407baSopenharmony_ci usage = &report->field[i]->usage[j]; 20873d0407baSopenharmony_ci 20883d0407baSopenharmony_ci if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER) { 20893d0407baSopenharmony_ci continue; 20903d0407baSopenharmony_ci } 20913d0407baSopenharmony_ci 20923d0407baSopenharmony_ci /* 20933d0407baSopenharmony_ci * If we have more than one feature within this 20943d0407baSopenharmony_ci * report we need to fill in the bits from the 20953d0407baSopenharmony_ci * others before we can overwrite the ones for the 20963d0407baSopenharmony_ci * Resolution Multiplier. 20973d0407baSopenharmony_ci * 20983d0407baSopenharmony_ci * But if we're not allowed to read from the device, 20993d0407baSopenharmony_ci * we just bail. Such a device should not exist 21003d0407baSopenharmony_ci * anyway. 21013d0407baSopenharmony_ci */ 21023d0407baSopenharmony_ci if (!get_report_completed && report->maxfield > 1) { 21033d0407baSopenharmony_ci if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS) { 21043d0407baSopenharmony_ci return update_needed; 21053d0407baSopenharmony_ci } 21063d0407baSopenharmony_ci 21073d0407baSopenharmony_ci hid_hw_request(hid, report, HID_REQ_GET_REPORT); 21083d0407baSopenharmony_ci hid_hw_wait(hid); 21093d0407baSopenharmony_ci get_report_completed = true; 21103d0407baSopenharmony_ci } 21113d0407baSopenharmony_ci 21123d0407baSopenharmony_ci report->field[i]->value[j] = value; 21133d0407baSopenharmony_ci update_needed = true; 21143d0407baSopenharmony_ci } 21153d0407baSopenharmony_ci } 21163d0407baSopenharmony_ci 21173d0407baSopenharmony_ci return update_needed; 21183d0407baSopenharmony_ci} 21193d0407baSopenharmony_ci 21203d0407baSopenharmony_cistatic void hidinput_change_resolution_multipliers(struct hid_device *hid) 21213d0407baSopenharmony_ci{ 21223d0407baSopenharmony_ci struct hid_report_enum *rep_enum; 21233d0407baSopenharmony_ci struct hid_report *rep; 21243d0407baSopenharmony_ci int ret; 21253d0407baSopenharmony_ci 21263d0407baSopenharmony_ci rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; 21273d0407baSopenharmony_ci list_for_each_entry(rep, &rep_enum->report_list, list) 21283d0407baSopenharmony_ci { 21293d0407baSopenharmony_ci bool update_needed = __hidinput_change_resolution_multipliers(hid, rep, true); 21303d0407baSopenharmony_ci if (update_needed) { 21313d0407baSopenharmony_ci ret = __hid_request(hid, rep, HID_REQ_SET_REPORT); 21323d0407baSopenharmony_ci if (ret) { 21333d0407baSopenharmony_ci __hidinput_change_resolution_multipliers(hid, rep, false); 21343d0407baSopenharmony_ci return; 21353d0407baSopenharmony_ci } 21363d0407baSopenharmony_ci } 21373d0407baSopenharmony_ci } 21383d0407baSopenharmony_ci /* refresh our structs */ 21393d0407baSopenharmony_ci hid_setup_resolution_multiplier(hid); 21403d0407baSopenharmony_ci} 21413d0407baSopenharmony_ci 21423d0407baSopenharmony_cistatic void report_features(struct hid_device *hid) 21433d0407baSopenharmony_ci{ 21443d0407baSopenharmony_ci struct hid_driver *drv = hid->driver; 21453d0407baSopenharmony_ci struct hid_report_enum *rep_enum; 21463d0407baSopenharmony_ci struct hid_report *rep; 21473d0407baSopenharmony_ci struct hid_usage *usage; 21483d0407baSopenharmony_ci int i, j; 21493d0407baSopenharmony_ci 21503d0407baSopenharmony_ci rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; 21513d0407baSopenharmony_ci list_for_each_entry(rep, &rep_enum->report_list, list) { 21523d0407baSopenharmony_ci for (i = 0; i < rep->maxfield; i++) { 21533d0407baSopenharmony_ci /* Ignore if report count is out of bounds. */ 21543d0407baSopenharmony_ci if (rep->field[i]->report_count < 1) { 21553d0407baSopenharmony_ci continue; 21563d0407baSopenharmony_ci } 21573d0407baSopenharmony_ci 21583d0407baSopenharmony_ci for (j = 0; j < rep->field[i]->maxusage; j++) { 21593d0407baSopenharmony_ci usage = &rep->field[i]->usage[j]; 21603d0407baSopenharmony_ci 21613d0407baSopenharmony_ci /* Verify if Battery Strength feature is available */ 21623d0407baSopenharmony_ci if (usage->hid == HID_DC_BATTERYSTRENGTH) { 21633d0407baSopenharmony_ci hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); 21643d0407baSopenharmony_ci } 21653d0407baSopenharmony_ci 21663d0407baSopenharmony_ci if (drv->feature_mapping) { 21673d0407baSopenharmony_ci drv->feature_mapping(hid, rep->field[i], usage); 21683d0407baSopenharmony_ci } 21693d0407baSopenharmony_ci } 21703d0407baSopenharmony_ci } 21713d0407baSopenharmony_ci } 21723d0407baSopenharmony_ci} 21733d0407baSopenharmony_ci 21743d0407baSopenharmony_cistatic struct hid_input *hidinput_allocate(struct hid_device *hid, unsigned int application) 21753d0407baSopenharmony_ci{ 21763d0407baSopenharmony_ci struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); 21773d0407baSopenharmony_ci struct input_dev *input_dev = input_allocate_device(); 21783d0407baSopenharmony_ci const char *suffix = NULL; 21793d0407baSopenharmony_ci size_t suffix_len, name_len; 21803d0407baSopenharmony_ci 21813d0407baSopenharmony_ci if (!hidinput || !input_dev) { 21823d0407baSopenharmony_ci goto fail; 21833d0407baSopenharmony_ci } 21843d0407baSopenharmony_ci 21853d0407baSopenharmony_ci if ((hid->quirks & HID_QUIRK_INPUT_PER_APP) && hid->maxapplication > 1) { 21863d0407baSopenharmony_ci switch (application) { 21873d0407baSopenharmony_ci case HID_GD_KEYBOARD: 21883d0407baSopenharmony_ci suffix = "Keyboard"; 21893d0407baSopenharmony_ci break; 21903d0407baSopenharmony_ci case HID_GD_KEYPAD: 21913d0407baSopenharmony_ci suffix = "Keypad"; 21923d0407baSopenharmony_ci break; 21933d0407baSopenharmony_ci case HID_GD_MOUSE: 21943d0407baSopenharmony_ci suffix = "Mouse"; 21953d0407baSopenharmony_ci break; 21963d0407baSopenharmony_ci case HID_DG_STYLUS: 21973d0407baSopenharmony_ci suffix = "Pen"; 21983d0407baSopenharmony_ci break; 21993d0407baSopenharmony_ci case HID_DG_TOUCHSCREEN: 22003d0407baSopenharmony_ci suffix = "Touchscreen"; 22013d0407baSopenharmony_ci break; 22023d0407baSopenharmony_ci case HID_DG_TOUCHPAD: 22033d0407baSopenharmony_ci suffix = "Touchpad"; 22043d0407baSopenharmony_ci break; 22053d0407baSopenharmony_ci case HID_GD_SYSTEM_CONTROL: 22063d0407baSopenharmony_ci suffix = "System Control"; 22073d0407baSopenharmony_ci break; 22083d0407baSopenharmony_ci case HID_CP_CONSUMER_CONTROL: 22093d0407baSopenharmony_ci suffix = "Consumer Control"; 22103d0407baSopenharmony_ci break; 22113d0407baSopenharmony_ci case HID_GD_WIRELESS_RADIO_CTLS: 22123d0407baSopenharmony_ci suffix = "Wireless Radio Control"; 22133d0407baSopenharmony_ci break; 22143d0407baSopenharmony_ci case HID_GD_SYSTEM_MULTIAXIS: 22153d0407baSopenharmony_ci suffix = "System Multi Axis"; 22163d0407baSopenharmony_ci break; 22173d0407baSopenharmony_ci default: 22183d0407baSopenharmony_ci break; 22193d0407baSopenharmony_ci } 22203d0407baSopenharmony_ci } 22213d0407baSopenharmony_ci 22223d0407baSopenharmony_ci if (suffix) { 22233d0407baSopenharmony_ci name_len = strlen(hid->name); 22243d0407baSopenharmony_ci suffix_len = strlen(suffix); 22253d0407baSopenharmony_ci if ((name_len < suffix_len) || strcmp(hid->name + name_len - suffix_len, suffix)) { 22263d0407baSopenharmony_ci hidinput->name = kasprintf(GFP_KERNEL, "%s %s", hid->name, suffix); 22273d0407baSopenharmony_ci if (!hidinput->name) { 22283d0407baSopenharmony_ci goto fail; 22293d0407baSopenharmony_ci } 22303d0407baSopenharmony_ci } 22313d0407baSopenharmony_ci } 22323d0407baSopenharmony_ci 22333d0407baSopenharmony_ci input_set_drvdata(input_dev, hid); 22343d0407baSopenharmony_ci input_dev->event = hidinput_input_event; 22353d0407baSopenharmony_ci input_dev->open = hidinput_open; 22363d0407baSopenharmony_ci input_dev->close = hidinput_close; 22373d0407baSopenharmony_ci input_dev->setkeycode = hidinput_setkeycode; 22383d0407baSopenharmony_ci input_dev->getkeycode = hidinput_getkeycode; 22393d0407baSopenharmony_ci 22403d0407baSopenharmony_ci input_dev->name = hidinput->name ? hidinput->name : hid->name; 22413d0407baSopenharmony_ci input_dev->phys = hid->phys; 22423d0407baSopenharmony_ci input_dev->uniq = hid->uniq; 22433d0407baSopenharmony_ci input_dev->id.bustype = hid->bus; 22443d0407baSopenharmony_ci input_dev->id.vendor = hid->vendor; 22453d0407baSopenharmony_ci input_dev->id.product = hid->product; 22463d0407baSopenharmony_ci input_dev->id.version = hid->version; 22473d0407baSopenharmony_ci input_dev->dev.parent = &hid->dev; 22483d0407baSopenharmony_ci 22493d0407baSopenharmony_ci hidinput->input = input_dev; 22503d0407baSopenharmony_ci hidinput->application = application; 22513d0407baSopenharmony_ci list_add_tail(&hidinput->list, &hid->inputs); 22523d0407baSopenharmony_ci 22533d0407baSopenharmony_ci INIT_LIST_HEAD(&hidinput->reports); 22543d0407baSopenharmony_ci 22553d0407baSopenharmony_ci return hidinput; 22563d0407baSopenharmony_ci 22573d0407baSopenharmony_cifail: 22583d0407baSopenharmony_ci kfree(hidinput); 22593d0407baSopenharmony_ci input_free_device(input_dev); 22603d0407baSopenharmony_ci hid_err(hid, "Out of memory during hid input probe\n"); 22613d0407baSopenharmony_ci return NULL; 22623d0407baSopenharmony_ci} 22633d0407baSopenharmony_ci 22643d0407baSopenharmony_cistatic bool hidinput_has_been_populated(struct hid_input *hidinput) 22653d0407baSopenharmony_ci{ 22663d0407baSopenharmony_ci int i; 22673d0407baSopenharmony_ci unsigned long r = 0; 22683d0407baSopenharmony_ci 22693d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++) { 22703d0407baSopenharmony_ci r |= hidinput->input->evbit[i]; 22713d0407baSopenharmony_ci } 22723d0407baSopenharmony_ci 22733d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++) { 22743d0407baSopenharmony_ci r |= hidinput->input->keybit[i]; 22753d0407baSopenharmony_ci } 22763d0407baSopenharmony_ci 22773d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++) { 22783d0407baSopenharmony_ci r |= hidinput->input->relbit[i]; 22793d0407baSopenharmony_ci } 22803d0407baSopenharmony_ci 22813d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++) { 22823d0407baSopenharmony_ci r |= hidinput->input->absbit[i]; 22833d0407baSopenharmony_ci } 22843d0407baSopenharmony_ci 22853d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++) { 22863d0407baSopenharmony_ci r |= hidinput->input->mscbit[i]; 22873d0407baSopenharmony_ci } 22883d0407baSopenharmony_ci 22893d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++) { 22903d0407baSopenharmony_ci r |= hidinput->input->ledbit[i]; 22913d0407baSopenharmony_ci } 22923d0407baSopenharmony_ci 22933d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++) { 22943d0407baSopenharmony_ci r |= hidinput->input->sndbit[i]; 22953d0407baSopenharmony_ci } 22963d0407baSopenharmony_ci 22973d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++) { 22983d0407baSopenharmony_ci r |= hidinput->input->ffbit[i]; 22993d0407baSopenharmony_ci } 23003d0407baSopenharmony_ci 23013d0407baSopenharmony_ci for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++) { 23023d0407baSopenharmony_ci r |= hidinput->input->swbit[i]; 23033d0407baSopenharmony_ci } 23043d0407baSopenharmony_ci 23053d0407baSopenharmony_ci return !!r; 23063d0407baSopenharmony_ci} 23073d0407baSopenharmony_ci 23083d0407baSopenharmony_cistatic void hidinput_cleanup_hidinput(struct hid_device *hid, struct hid_input *hidinput) 23093d0407baSopenharmony_ci{ 23103d0407baSopenharmony_ci struct hid_report *report; 23113d0407baSopenharmony_ci int i, k; 23123d0407baSopenharmony_ci 23133d0407baSopenharmony_ci list_del(&hidinput->list); 23143d0407baSopenharmony_ci input_free_device(hidinput->input); 23153d0407baSopenharmony_ci kfree(hidinput->name); 23163d0407baSopenharmony_ci 23173d0407baSopenharmony_ci for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { 23183d0407baSopenharmony_ci if ((k == HID_OUTPUT_REPORT) && (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)) { 23193d0407baSopenharmony_ci continue; 23203d0407baSopenharmony_ci } 23213d0407baSopenharmony_ci 23223d0407baSopenharmony_ci list_for_each_entry(report, &hid->report_enum[k].report_list, list) 23233d0407baSopenharmony_ci { 23243d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 23253d0407baSopenharmony_ci if (report->field[i]->hidinput == hidinput) { 23263d0407baSopenharmony_ci report->field[i]->hidinput = NULL; 23273d0407baSopenharmony_ci } 23283d0407baSopenharmony_ci } 23293d0407baSopenharmony_ci } 23303d0407baSopenharmony_ci } 23313d0407baSopenharmony_ci 23323d0407baSopenharmony_ci kfree(hidinput); 23333d0407baSopenharmony_ci} 23343d0407baSopenharmony_ci 23353d0407baSopenharmony_cistatic struct hid_input *hidinput_match(struct hid_report *report) 23363d0407baSopenharmony_ci{ 23373d0407baSopenharmony_ci struct hid_device *hid = report->device; 23383d0407baSopenharmony_ci struct hid_input *hidinput; 23393d0407baSopenharmony_ci 23403d0407baSopenharmony_ci list_for_each_entry(hidinput, &hid->inputs, list) 23413d0407baSopenharmony_ci { 23423d0407baSopenharmony_ci if (hidinput->report && hidinput->report->id == report->id) { 23433d0407baSopenharmony_ci return hidinput; 23443d0407baSopenharmony_ci } 23453d0407baSopenharmony_ci } 23463d0407baSopenharmony_ci 23473d0407baSopenharmony_ci return NULL; 23483d0407baSopenharmony_ci} 23493d0407baSopenharmony_ci 23503d0407baSopenharmony_cistatic struct hid_input *hidinput_match_application(struct hid_report *report) 23513d0407baSopenharmony_ci{ 23523d0407baSopenharmony_ci struct hid_device *hid = report->device; 23533d0407baSopenharmony_ci struct hid_input *hidinput; 23543d0407baSopenharmony_ci 23553d0407baSopenharmony_ci list_for_each_entry(hidinput, &hid->inputs, list) 23563d0407baSopenharmony_ci { 23573d0407baSopenharmony_ci if (hidinput->application == report->application) { 23583d0407baSopenharmony_ci return hidinput; 23593d0407baSopenharmony_ci } 23603d0407baSopenharmony_ci } 23613d0407baSopenharmony_ci 23623d0407baSopenharmony_ci return NULL; 23633d0407baSopenharmony_ci} 23643d0407baSopenharmony_ci 23653d0407baSopenharmony_cistatic inline void hidinput_configure_usages(struct hid_input *hidinput, struct hid_report *report) 23663d0407baSopenharmony_ci{ 23673d0407baSopenharmony_ci int i, j; 23683d0407baSopenharmony_ci 23693d0407baSopenharmony_ci for (i = 0; i < report->maxfield; i++) { 23703d0407baSopenharmony_ci for (j = 0; j < report->field[i]->maxusage; j++) { 23713d0407baSopenharmony_ci hidinput_configure_usage(hidinput, report->field[i], report->field[i]->usage + j); 23723d0407baSopenharmony_ci } 23733d0407baSopenharmony_ci } 23743d0407baSopenharmony_ci} 23753d0407baSopenharmony_ci 23763d0407baSopenharmony_ci/* 23773d0407baSopenharmony_ci * Register the input device; print a message. 23783d0407baSopenharmony_ci * Configure the input layer interface 23793d0407baSopenharmony_ci * Read all reports and initialize the absolute field values. 23803d0407baSopenharmony_ci */ 23813d0407baSopenharmony_ci 23823d0407baSopenharmony_ciint hidinput_connect(struct hid_device *hid, unsigned int force) 23833d0407baSopenharmony_ci{ 23843d0407baSopenharmony_ci struct hid_driver *drv = hid->driver; 23853d0407baSopenharmony_ci struct hid_report *report; 23863d0407baSopenharmony_ci struct hid_input *next, *hidinput = NULL; 23873d0407baSopenharmony_ci unsigned int application; 23883d0407baSopenharmony_ci int i, k; 23893d0407baSopenharmony_ci 23903d0407baSopenharmony_ci INIT_LIST_HEAD(&hid->inputs); 23913d0407baSopenharmony_ci INIT_WORK(&hid->led_work, hidinput_led_worker); 23923d0407baSopenharmony_ci 23933d0407baSopenharmony_ci hid->status &= ~HID_STAT_DUP_DETECTED; 23943d0407baSopenharmony_ci 23953d0407baSopenharmony_ci if (!force) { 23963d0407baSopenharmony_ci for (i = 0; i < hid->maxcollection; i++) { 23973d0407baSopenharmony_ci struct hid_collection *col = &hid->collection[i]; 23983d0407baSopenharmony_ci if (col->type == HID_COLLECTION_APPLICATION || col->type == HID_COLLECTION_PHYSICAL) { 23993d0407baSopenharmony_ci if (IS_INPUT_APPLICATION(col->usage)) { 24003d0407baSopenharmony_ci break; 24013d0407baSopenharmony_ci } 24023d0407baSopenharmony_ci } 24033d0407baSopenharmony_ci } 24043d0407baSopenharmony_ci 24053d0407baSopenharmony_ci if (i == hid->maxcollection) { 24063d0407baSopenharmony_ci return -1; 24073d0407baSopenharmony_ci } 24083d0407baSopenharmony_ci } 24093d0407baSopenharmony_ci 24103d0407baSopenharmony_ci report_features(hid); 24113d0407baSopenharmony_ci 24123d0407baSopenharmony_ci for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { 24133d0407baSopenharmony_ci if ((k == HID_OUTPUT_REPORT) && (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)) { 24143d0407baSopenharmony_ci continue; 24153d0407baSopenharmony_ci } 24163d0407baSopenharmony_ci 24173d0407baSopenharmony_ci list_for_each_entry(report, &hid->report_enum[k].report_list, list) 24183d0407baSopenharmony_ci { 24193d0407baSopenharmony_ci if (!report->maxfield) { 24203d0407baSopenharmony_ci continue; 24213d0407baSopenharmony_ci } 24223d0407baSopenharmony_ci 24233d0407baSopenharmony_ci application = report->application; 24243d0407baSopenharmony_ci 24253d0407baSopenharmony_ci /* 24263d0407baSopenharmony_ci * Find the previous hidinput report attached 24273d0407baSopenharmony_ci * to this report id. 24283d0407baSopenharmony_ci */ 24293d0407baSopenharmony_ci if (hid->quirks & HID_QUIRK_MULTI_INPUT) { 24303d0407baSopenharmony_ci hidinput = hidinput_match(report); 24313d0407baSopenharmony_ci } else if (hid->maxapplication > 1 && (hid->quirks & HID_QUIRK_INPUT_PER_APP)) { 24323d0407baSopenharmony_ci hidinput = hidinput_match_application(report); 24333d0407baSopenharmony_ci } 24343d0407baSopenharmony_ci 24353d0407baSopenharmony_ci if (!hidinput) { 24363d0407baSopenharmony_ci hidinput = hidinput_allocate(hid, application); 24373d0407baSopenharmony_ci if (!hidinput) { 24383d0407baSopenharmony_ci goto out_unwind; 24393d0407baSopenharmony_ci } 24403d0407baSopenharmony_ci } 24413d0407baSopenharmony_ci 24423d0407baSopenharmony_ci hidinput_configure_usages(hidinput, report); 24433d0407baSopenharmony_ci 24443d0407baSopenharmony_ci if (hid->quirks & HID_QUIRK_MULTI_INPUT) { 24453d0407baSopenharmony_ci hidinput->report = report; 24463d0407baSopenharmony_ci } 24473d0407baSopenharmony_ci 24483d0407baSopenharmony_ci list_add_tail(&report->hidinput_list, &hidinput->reports); 24493d0407baSopenharmony_ci } 24503d0407baSopenharmony_ci } 24513d0407baSopenharmony_ci 24523d0407baSopenharmony_ci hidinput_change_resolution_multipliers(hid); 24533d0407baSopenharmony_ci 24543d0407baSopenharmony_ci list_for_each_entry_safe(hidinput, next, &hid->inputs, list) 24553d0407baSopenharmony_ci { 24563d0407baSopenharmony_ci if (drv->input_configured && drv->input_configured(hid, hidinput)) { 24573d0407baSopenharmony_ci goto out_unwind; 24583d0407baSopenharmony_ci } 24593d0407baSopenharmony_ci 24603d0407baSopenharmony_ci if (!hidinput_has_been_populated(hidinput)) { 24613d0407baSopenharmony_ci /* no need to register an input device not populated */ 24623d0407baSopenharmony_ci hidinput_cleanup_hidinput(hid, hidinput); 24633d0407baSopenharmony_ci continue; 24643d0407baSopenharmony_ci } 24653d0407baSopenharmony_ci 24663d0407baSopenharmony_ci if (input_register_device(hidinput->input)) { 24673d0407baSopenharmony_ci goto out_unwind; 24683d0407baSopenharmony_ci } 24693d0407baSopenharmony_ci hidinput->registered = true; 24703d0407baSopenharmony_ci } 24713d0407baSopenharmony_ci 24723d0407baSopenharmony_ci if (list_empty(&hid->inputs)) { 24733d0407baSopenharmony_ci hid_err(hid, "No inputs registered, leaving\n"); 24743d0407baSopenharmony_ci goto out_unwind; 24753d0407baSopenharmony_ci } 24763d0407baSopenharmony_ci 24773d0407baSopenharmony_ci if (hid->status & HID_STAT_DUP_DETECTED) { 24783d0407baSopenharmony_ci hid_dbg(hid, "Some usages could not be mapped, please use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE if this is " 24793d0407baSopenharmony_ci "legitimate.\n"); 24803d0407baSopenharmony_ci } 24813d0407baSopenharmony_ci 24823d0407baSopenharmony_ci return 0; 24833d0407baSopenharmony_ci 24843d0407baSopenharmony_ciout_unwind: 24853d0407baSopenharmony_ci /* unwind the ones we already registered */ 24863d0407baSopenharmony_ci hidinput_disconnect(hid); 24873d0407baSopenharmony_ci 24883d0407baSopenharmony_ci return -1; 24893d0407baSopenharmony_ci} 24903d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_connect); 24913d0407baSopenharmony_ci 24923d0407baSopenharmony_civoid hidinput_disconnect(struct hid_device *hid) 24933d0407baSopenharmony_ci{ 24943d0407baSopenharmony_ci struct hid_input *hidinput, *next; 24953d0407baSopenharmony_ci 24963d0407baSopenharmony_ci hidinput_cleanup_battery(hid); 24973d0407baSopenharmony_ci 24983d0407baSopenharmony_ci list_for_each_entry_safe(hidinput, next, &hid->inputs, list) 24993d0407baSopenharmony_ci { 25003d0407baSopenharmony_ci list_del(&hidinput->list); 25013d0407baSopenharmony_ci if (hidinput->registered) { 25023d0407baSopenharmony_ci input_unregister_device(hidinput->input); 25033d0407baSopenharmony_ci } else { 25043d0407baSopenharmony_ci input_free_device(hidinput->input); 25053d0407baSopenharmony_ci } 25063d0407baSopenharmony_ci kfree(hidinput->name); 25073d0407baSopenharmony_ci kfree(hidinput); 25083d0407baSopenharmony_ci } 25093d0407baSopenharmony_ci 25103d0407baSopenharmony_ci /* led_work is spawned by input_dev callbacks, but doesn't access the 25113d0407baSopenharmony_ci * parent input_dev at all. Once all input devices are removed, we 25123d0407baSopenharmony_ci * know that led_work will never get restarted, so we can cancel it 25133d0407baSopenharmony_ci * synchronously and are safe. */ 25143d0407baSopenharmony_ci cancel_work_sync(&hid->led_work); 25153d0407baSopenharmony_ci} 25163d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(hidinput_disconnect); 2517