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