11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2dde5845aSJiri Kosina /*
3dde5845aSJiri Kosina * Copyright (c) 2000-2001 Vojtech Pavlik
47d39e849SJiri Kosina * Copyright (c) 2006-2010 Jiri Kosina
5dde5845aSJiri Kosina *
6dde5845aSJiri Kosina * HID to Linux Input mapping
7dde5845aSJiri Kosina */
8dde5845aSJiri Kosina
9dde5845aSJiri Kosina /*
10dde5845aSJiri Kosina *
11dde5845aSJiri Kosina * Should you need to contact me, the author, you can do so either by
12dde5845aSJiri Kosina * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
13dde5845aSJiri Kosina * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
14dde5845aSJiri Kosina */
15dde5845aSJiri Kosina
16dde5845aSJiri Kosina #include <linux/module.h>
17dde5845aSJiri Kosina #include <linux/slab.h>
18dde5845aSJiri Kosina #include <linux/kernel.h>
19dde5845aSJiri Kosina
20dde5845aSJiri Kosina #include <linux/hid.h>
21c080d89aSJiri Kosina #include <linux/hid-debug.h>
22dde5845aSJiri Kosina
23bbc21cfdSJeremy Fitzhardinge #include "hid-ids.h"
24bbc21cfdSJeremy Fitzhardinge
25dde5845aSJiri Kosina #define unk KEY_UNKNOWN
26dde5845aSJiri Kosina
27dde5845aSJiri Kosina static const unsigned char hid_keyboard[256] = {
28dde5845aSJiri Kosina 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
29dde5845aSJiri Kosina 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
30dde5845aSJiri Kosina 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
31dde5845aSJiri Kosina 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
32dde5845aSJiri Kosina 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
33dde5845aSJiri Kosina 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
34dde5845aSJiri Kosina 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
35dde5845aSJiri Kosina 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
36dde5845aSJiri Kosina 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
37437f3b19SJarod Wilson 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,
38dde5845aSJiri Kosina unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
391fe8736dSJiri Kosina unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
40dde5845aSJiri Kosina unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
41437f3b19SJarod Wilson unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,
42dde5845aSJiri Kosina 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
43dde5845aSJiri Kosina 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
44dde5845aSJiri Kosina };
45dde5845aSJiri Kosina
46dde5845aSJiri Kosina static const struct {
47dde5845aSJiri Kosina __s32 x;
48dde5845aSJiri Kosina __s32 y;
49dde5845aSJiri Kosina } hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
50dde5845aSJiri Kosina
515c20000aSBenjamin Tissoires struct usage_priority {
525c20000aSBenjamin Tissoires __u32 usage; /* the HID usage associated */
535c20000aSBenjamin Tissoires bool global; /* we assume all usages to be slotted,
545c20000aSBenjamin Tissoires * unless global
555c20000aSBenjamin Tissoires */
565c20000aSBenjamin Tissoires unsigned int slot_overwrite; /* for globals: allows to set the usage
575c20000aSBenjamin Tissoires * before or after the slots
585c20000aSBenjamin Tissoires */
595c20000aSBenjamin Tissoires };
605c20000aSBenjamin Tissoires
61048cddfdSBenjamin Tissoires /*
62048cddfdSBenjamin Tissoires * hid-input will convert this list into priorities:
63048cddfdSBenjamin Tissoires * the first element will have the highest priority
64048cddfdSBenjamin Tissoires * (the length of the following array) and the last
65048cddfdSBenjamin Tissoires * element the lowest (1).
66048cddfdSBenjamin Tissoires *
67048cddfdSBenjamin Tissoires * hid-input will then shift the priority by 8 bits to leave some space
68048cddfdSBenjamin Tissoires * in case drivers want to interleave other fields.
69048cddfdSBenjamin Tissoires *
705c20000aSBenjamin Tissoires * To accommodate slotted devices, the slot priority is
715c20000aSBenjamin Tissoires * defined in the next 8 bits (defined by 0xff - slot).
725c20000aSBenjamin Tissoires *
73048cddfdSBenjamin Tissoires * If drivers want to add fields before those, hid-input will
74048cddfdSBenjamin Tissoires * leave out the first 8 bits of the priority value.
75048cddfdSBenjamin Tissoires *
76048cddfdSBenjamin Tissoires * This still leaves us 65535 individual priority values.
77048cddfdSBenjamin Tissoires */
785c20000aSBenjamin Tissoires static const struct usage_priority hidinput_usages_priorities[] = {
795c20000aSBenjamin Tissoires { /* Eraser (eraser touching) must always come before tipswitch */
805c20000aSBenjamin Tissoires .usage = HID_DG_ERASER,
815c20000aSBenjamin Tissoires },
825c20000aSBenjamin Tissoires { /* Invert must always come before In Range */
835c20000aSBenjamin Tissoires .usage = HID_DG_INVERT,
845c20000aSBenjamin Tissoires },
855c20000aSBenjamin Tissoires { /* Is the tip of the tool touching? */
865c20000aSBenjamin Tissoires .usage = HID_DG_TIPSWITCH,
875c20000aSBenjamin Tissoires },
885c20000aSBenjamin Tissoires { /* Tip Pressure might emulate tip switch */
895c20000aSBenjamin Tissoires .usage = HID_DG_TIPPRESSURE,
905c20000aSBenjamin Tissoires },
915c20000aSBenjamin Tissoires { /* In Range needs to come after the other tool states */
925c20000aSBenjamin Tissoires .usage = HID_DG_INRANGE,
935c20000aSBenjamin Tissoires },
94048cddfdSBenjamin Tissoires };
95048cddfdSBenjamin Tissoires
96022e8c4dSJiri Slaby #define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
97022e8c4dSJiri Slaby #define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
98022e8c4dSJiri Slaby #define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
99022e8c4dSJiri Slaby #define map_led(c) hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c))
1008aa45b54SMika Westerberg #define map_msc(c) hid_map_usage(hidinput, usage, &bit, &max, EV_MSC, (c))
101dde5845aSJiri Kosina
102022e8c4dSJiri Slaby #define map_abs_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
103022e8c4dSJiri Slaby &max, EV_ABS, (c))
104022e8c4dSJiri Slaby #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
105022e8c4dSJiri Slaby &max, EV_KEY, (c))
106dde5845aSJiri Kosina
match_scancode(struct hid_usage * usage,unsigned int cur_idx,unsigned int scancode)107a0bf0ea8SDmitry Torokhov static bool match_scancode(struct hid_usage *usage,
108a0bf0ea8SDmitry Torokhov unsigned int cur_idx, unsigned int scancode)
109fe7ba31fSMarvin Raaijmakers {
110a0bf0ea8SDmitry Torokhov return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
111fe7ba31fSMarvin Raaijmakers }
112fe7ba31fSMarvin Raaijmakers
match_keycode(struct hid_usage * usage,unsigned int cur_idx,unsigned int keycode)113a0bf0ea8SDmitry Torokhov static bool match_keycode(struct hid_usage *usage,
114a0bf0ea8SDmitry Torokhov unsigned int cur_idx, unsigned int keycode)
115fe7ba31fSMarvin Raaijmakers {
116f5854fadSDmitry Torokhov /*
117f5854fadSDmitry Torokhov * We should exclude unmapped usages when doing lookup by keycode.
118f5854fadSDmitry Torokhov */
119f5854fadSDmitry Torokhov return (usage->type == EV_KEY && usage->code == keycode);
120fe7ba31fSMarvin Raaijmakers }
121fe7ba31fSMarvin Raaijmakers
match_index(struct hid_usage * usage,unsigned int cur_idx,unsigned int idx)122a0bf0ea8SDmitry Torokhov static bool match_index(struct hid_usage *usage,
123a0bf0ea8SDmitry Torokhov unsigned int cur_idx, unsigned int idx)
124a0bf0ea8SDmitry Torokhov {
125a0bf0ea8SDmitry Torokhov return cur_idx == idx;
126a0bf0ea8SDmitry Torokhov }
127a0bf0ea8SDmitry Torokhov
128a0bf0ea8SDmitry Torokhov typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
129a0bf0ea8SDmitry Torokhov unsigned int cur_idx, unsigned int val);
130a0bf0ea8SDmitry Torokhov
hidinput_find_key(struct hid_device * hid,hid_usage_cmp_t match,unsigned int value,unsigned int * usage_idx)131fe7ba31fSMarvin Raaijmakers static struct hid_usage *hidinput_find_key(struct hid_device *hid,
132a0bf0ea8SDmitry Torokhov hid_usage_cmp_t match,
133a0bf0ea8SDmitry Torokhov unsigned int value,
134a0bf0ea8SDmitry Torokhov unsigned int *usage_idx)
135fe7ba31fSMarvin Raaijmakers {
136a0bf0ea8SDmitry Torokhov unsigned int i, j, k, cur_idx = 0;
137fe7ba31fSMarvin Raaijmakers struct hid_report *report;
138fe7ba31fSMarvin Raaijmakers struct hid_usage *usage;
139fe7ba31fSMarvin Raaijmakers
140fe7ba31fSMarvin Raaijmakers for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
141fe7ba31fSMarvin Raaijmakers list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
142fe7ba31fSMarvin Raaijmakers for (i = 0; i < report->maxfield; i++) {
143fe7ba31fSMarvin Raaijmakers for (j = 0; j < report->field[i]->maxusage; j++) {
144fe7ba31fSMarvin Raaijmakers usage = report->field[i]->usage + j;
145f5854fadSDmitry Torokhov if (usage->type == EV_KEY || usage->type == 0) {
146a0bf0ea8SDmitry Torokhov if (match(usage, cur_idx, value)) {
147a0bf0ea8SDmitry Torokhov if (usage_idx)
148a0bf0ea8SDmitry Torokhov *usage_idx = cur_idx;
149fe7ba31fSMarvin Raaijmakers return usage;
150fe7ba31fSMarvin Raaijmakers }
151a0bf0ea8SDmitry Torokhov cur_idx++;
152a0bf0ea8SDmitry Torokhov }
153a0bf0ea8SDmitry Torokhov }
154fe7ba31fSMarvin Raaijmakers }
155fe7ba31fSMarvin Raaijmakers }
156fe7ba31fSMarvin Raaijmakers }
157fe7ba31fSMarvin Raaijmakers return NULL;
158fe7ba31fSMarvin Raaijmakers }
159fe7ba31fSMarvin Raaijmakers
hidinput_locate_usage(struct hid_device * hid,const struct input_keymap_entry * ke,unsigned int * index)160a0bf0ea8SDmitry Torokhov static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
161a0bf0ea8SDmitry Torokhov const struct input_keymap_entry *ke,
162a0bf0ea8SDmitry Torokhov unsigned int *index)
163a0bf0ea8SDmitry Torokhov {
164a0bf0ea8SDmitry Torokhov struct hid_usage *usage;
165a0bf0ea8SDmitry Torokhov unsigned int scancode;
166a0bf0ea8SDmitry Torokhov
167a0bf0ea8SDmitry Torokhov if (ke->flags & INPUT_KEYMAP_BY_INDEX)
168a0bf0ea8SDmitry Torokhov usage = hidinput_find_key(hid, match_index, ke->index, index);
169a0bf0ea8SDmitry Torokhov else if (input_scancode_to_scalar(ke, &scancode) == 0)
170a0bf0ea8SDmitry Torokhov usage = hidinput_find_key(hid, match_scancode, scancode, index);
171a0bf0ea8SDmitry Torokhov else
172a0bf0ea8SDmitry Torokhov usage = NULL;
173a0bf0ea8SDmitry Torokhov
174a0bf0ea8SDmitry Torokhov return usage;
175a0bf0ea8SDmitry Torokhov }
176a0bf0ea8SDmitry Torokhov
hidinput_getkeycode(struct input_dev * dev,struct input_keymap_entry * ke)17758b93995SDmitry Torokhov static int hidinput_getkeycode(struct input_dev *dev,
178a0bf0ea8SDmitry Torokhov struct input_keymap_entry *ke)
179fe7ba31fSMarvin Raaijmakers {
180f202df60SDmitry Torokhov struct hid_device *hid = input_get_drvdata(dev);
181fe7ba31fSMarvin Raaijmakers struct hid_usage *usage;
182a0bf0ea8SDmitry Torokhov unsigned int scancode, index;
183fe7ba31fSMarvin Raaijmakers
184a0bf0ea8SDmitry Torokhov usage = hidinput_locate_usage(hid, ke, &index);
185fe7ba31fSMarvin Raaijmakers if (usage) {
186f5854fadSDmitry Torokhov ke->keycode = usage->type == EV_KEY ?
187f5854fadSDmitry Torokhov usage->code : KEY_RESERVED;
188a0bf0ea8SDmitry Torokhov ke->index = index;
189a0bf0ea8SDmitry Torokhov scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
190a0bf0ea8SDmitry Torokhov ke->len = sizeof(scancode);
191a0bf0ea8SDmitry Torokhov memcpy(ke->scancode, &scancode, sizeof(scancode));
192fe7ba31fSMarvin Raaijmakers return 0;
193fe7ba31fSMarvin Raaijmakers }
194a0bf0ea8SDmitry Torokhov
195fe7ba31fSMarvin Raaijmakers return -EINVAL;
196fe7ba31fSMarvin Raaijmakers }
197fe7ba31fSMarvin Raaijmakers
hidinput_setkeycode(struct input_dev * dev,const struct input_keymap_entry * ke,unsigned int * old_keycode)19858b93995SDmitry Torokhov static int hidinput_setkeycode(struct input_dev *dev,
199a0bf0ea8SDmitry Torokhov const struct input_keymap_entry *ke,
200a0bf0ea8SDmitry Torokhov unsigned int *old_keycode)
201fe7ba31fSMarvin Raaijmakers {
202f202df60SDmitry Torokhov struct hid_device *hid = input_get_drvdata(dev);
203fe7ba31fSMarvin Raaijmakers struct hid_usage *usage;
204fe7ba31fSMarvin Raaijmakers
205a0bf0ea8SDmitry Torokhov usage = hidinput_locate_usage(hid, ke, NULL);
206fe7ba31fSMarvin Raaijmakers if (usage) {
207f5854fadSDmitry Torokhov *old_keycode = usage->type == EV_KEY ?
208f5854fadSDmitry Torokhov usage->code : KEY_RESERVED;
2093e6a950dSThomas Weißschuh usage->type = EV_KEY;
210a0bf0ea8SDmitry Torokhov usage->code = ke->keycode;
211fe7ba31fSMarvin Raaijmakers
212a0bf0ea8SDmitry Torokhov clear_bit(*old_keycode, dev->keybit);
213fe7ba31fSMarvin Raaijmakers set_bit(usage->code, dev->keybit);
214587d1452SJoe Perches dbg_hid("Assigned keycode %d to HID usage code %x\n",
215a0bf0ea8SDmitry Torokhov usage->code, usage->hid);
216a0bf0ea8SDmitry Torokhov
217a0bf0ea8SDmitry Torokhov /*
218a0bf0ea8SDmitry Torokhov * Set the keybit for the old keycode if the old keycode is used
219a0bf0ea8SDmitry Torokhov * by another key
220a0bf0ea8SDmitry Torokhov */
221a0bf0ea8SDmitry Torokhov if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
222a0bf0ea8SDmitry Torokhov set_bit(*old_keycode, dev->keybit);
223fe7ba31fSMarvin Raaijmakers
224fe7ba31fSMarvin Raaijmakers return 0;
225fe7ba31fSMarvin Raaijmakers }
226fe7ba31fSMarvin Raaijmakers
227fe7ba31fSMarvin Raaijmakers return -EINVAL;
228fe7ba31fSMarvin Raaijmakers }
229fe7ba31fSMarvin Raaijmakers
230ad0e669bSNikolai Kondrashov
2314ea6e4ffSNikolai Kondrashov /**
2324ea6e4ffSNikolai Kondrashov * hidinput_calc_abs_res - calculate an absolute axis resolution
2334ea6e4ffSNikolai Kondrashov * @field: the HID report field to calculate resolution for
2344ea6e4ffSNikolai Kondrashov * @code: axis code
2354ea6e4ffSNikolai Kondrashov *
2364ea6e4ffSNikolai Kondrashov * The formula is:
2374ea6e4ffSNikolai Kondrashov * (logical_maximum - logical_minimum)
2384ea6e4ffSNikolai Kondrashov * resolution = ----------------------------------------------------------
2394ea6e4ffSNikolai Kondrashov * (physical_maximum - physical_minimum) * 10 ^ unit_exponent
2404ea6e4ffSNikolai Kondrashov *
2414ea6e4ffSNikolai Kondrashov * as seen in the HID specification v1.11 6.2.2.7 Global Items.
2424ea6e4ffSNikolai Kondrashov *
24383ed79c5SDmitry Torokhov * Only exponent 1 length units are processed. Centimeters and inches are
24483ed79c5SDmitry Torokhov * converted to millimeters. Degrees are converted to radians.
2454ea6e4ffSNikolai Kondrashov */
hidinput_calc_abs_res(const struct hid_field * field,__u16 code)24637cf6e6fSBenjamin Tissoires __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
2474ea6e4ffSNikolai Kondrashov {
2484ea6e4ffSNikolai Kondrashov __s32 unit_exponent = field->unit_exponent;
2494ea6e4ffSNikolai Kondrashov __s32 logical_extents = field->logical_maximum -
2504ea6e4ffSNikolai Kondrashov field->logical_minimum;
2514ea6e4ffSNikolai Kondrashov __s32 physical_extents = field->physical_maximum -
2524ea6e4ffSNikolai Kondrashov field->physical_minimum;
2534ea6e4ffSNikolai Kondrashov __s32 prev;
2544ea6e4ffSNikolai Kondrashov
2554ea6e4ffSNikolai Kondrashov /* Check if the extents are sane */
2564ea6e4ffSNikolai Kondrashov if (logical_extents <= 0 || physical_extents <= 0)
2574ea6e4ffSNikolai Kondrashov return 0;
2584ea6e4ffSNikolai Kondrashov
2594ea6e4ffSNikolai Kondrashov /*
2604ea6e4ffSNikolai Kondrashov * Verify and convert units.
2614ea6e4ffSNikolai Kondrashov * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
2624ea6e4ffSNikolai Kondrashov */
263b73b2da0SNikolai Kondrashov switch (code) {
264b73b2da0SNikolai Kondrashov case ABS_X:
265b73b2da0SNikolai Kondrashov case ABS_Y:
266b73b2da0SNikolai Kondrashov case ABS_Z:
26737cf6e6fSBenjamin Tissoires case ABS_MT_POSITION_X:
26837cf6e6fSBenjamin Tissoires case ABS_MT_POSITION_Y:
26937cf6e6fSBenjamin Tissoires case ABS_MT_TOOL_X:
27037cf6e6fSBenjamin Tissoires case ABS_MT_TOOL_Y:
27137cf6e6fSBenjamin Tissoires case ABS_MT_TOUCH_MAJOR:
27237cf6e6fSBenjamin Tissoires case ABS_MT_TOUCH_MINOR:
273ad0e669bSNikolai Kondrashov if (field->unit == 0x11) { /* If centimeters */
27483ed79c5SDmitry Torokhov /* Convert to millimeters */
27583ed79c5SDmitry Torokhov unit_exponent += 1;
276ad0e669bSNikolai Kondrashov } else if (field->unit == 0x13) { /* If inches */
27783ed79c5SDmitry Torokhov /* Convert to millimeters */
27883ed79c5SDmitry Torokhov prev = physical_extents;
27983ed79c5SDmitry Torokhov physical_extents *= 254;
28083ed79c5SDmitry Torokhov if (physical_extents < prev)
2814ea6e4ffSNikolai Kondrashov return 0;
28283ed79c5SDmitry Torokhov unit_exponent -= 1;
283ad0e669bSNikolai Kondrashov } else {
2844ea6e4ffSNikolai Kondrashov return 0;
2854ea6e4ffSNikolai Kondrashov }
286b73b2da0SNikolai Kondrashov break;
287b73b2da0SNikolai Kondrashov
288b73b2da0SNikolai Kondrashov case ABS_RX:
289b73b2da0SNikolai Kondrashov case ABS_RY:
290b73b2da0SNikolai Kondrashov case ABS_RZ:
291c0bf5741SJason Gerecke case ABS_WHEEL:
292b73b2da0SNikolai Kondrashov case ABS_TILT_X:
293b73b2da0SNikolai Kondrashov case ABS_TILT_Y:
2944ea6e4ffSNikolai Kondrashov if (field->unit == 0x14) { /* If degrees */
2954ea6e4ffSNikolai Kondrashov /* Convert to radians */
2964ea6e4ffSNikolai Kondrashov prev = logical_extents;
2974ea6e4ffSNikolai Kondrashov logical_extents *= 573;
2984ea6e4ffSNikolai Kondrashov if (logical_extents < prev)
2994ea6e4ffSNikolai Kondrashov return 0;
3004ea6e4ffSNikolai Kondrashov unit_exponent += 1;
3014ea6e4ffSNikolai Kondrashov } else if (field->unit != 0x12) { /* If not radians */
3024ea6e4ffSNikolai Kondrashov return 0;
3034ea6e4ffSNikolai Kondrashov }
304b73b2da0SNikolai Kondrashov break;
305b73b2da0SNikolai Kondrashov
306b73b2da0SNikolai Kondrashov default:
3074ea6e4ffSNikolai Kondrashov return 0;
3084ea6e4ffSNikolai Kondrashov }
3094ea6e4ffSNikolai Kondrashov
3104ea6e4ffSNikolai Kondrashov /* Apply negative unit exponent */
3114ea6e4ffSNikolai Kondrashov for (; unit_exponent < 0; unit_exponent++) {
3124ea6e4ffSNikolai Kondrashov prev = logical_extents;
3134ea6e4ffSNikolai Kondrashov logical_extents *= 10;
3144ea6e4ffSNikolai Kondrashov if (logical_extents < prev)
3154ea6e4ffSNikolai Kondrashov return 0;
3164ea6e4ffSNikolai Kondrashov }
3174ea6e4ffSNikolai Kondrashov /* Apply positive unit exponent */
3184ea6e4ffSNikolai Kondrashov for (; unit_exponent > 0; unit_exponent--) {
3194ea6e4ffSNikolai Kondrashov prev = physical_extents;
3204ea6e4ffSNikolai Kondrashov physical_extents *= 10;
3214ea6e4ffSNikolai Kondrashov if (physical_extents < prev)
3224ea6e4ffSNikolai Kondrashov return 0;
3234ea6e4ffSNikolai Kondrashov }
3244ea6e4ffSNikolai Kondrashov
3254ea6e4ffSNikolai Kondrashov /* Calculate resolution */
326ccdd6994SBenjamin Tissoires return DIV_ROUND_CLOSEST(logical_extents, physical_extents);
3274ea6e4ffSNikolai Kondrashov }
32837cf6e6fSBenjamin Tissoires EXPORT_SYMBOL_GPL(hidinput_calc_abs_res);
3294ea6e4ffSNikolai Kondrashov
3304f5ca836SJeremy Fitzhardinge #ifdef CONFIG_HID_BATTERY_STRENGTH
3314f5ca836SJeremy Fitzhardinge static enum power_supply_property hidinput_battery_props[] = {
3324f5ca836SJeremy Fitzhardinge POWER_SUPPLY_PROP_PRESENT,
3334f5ca836SJeremy Fitzhardinge POWER_SUPPLY_PROP_ONLINE,
3344f5ca836SJeremy Fitzhardinge POWER_SUPPLY_PROP_CAPACITY,
3354f5ca836SJeremy Fitzhardinge POWER_SUPPLY_PROP_MODEL_NAME,
33645d9c273SJeremy Fitzhardinge POWER_SUPPLY_PROP_STATUS,
33745d9c273SJeremy Fitzhardinge POWER_SUPPLY_PROP_SCOPE,
3384f5ca836SJeremy Fitzhardinge };
3394f5ca836SJeremy Fitzhardinge
340bbc21cfdSJeremy Fitzhardinge #define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */
341652aa6a9SJeremy Fitzhardinge #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
3425d9374cfSAlexander E. Patrakov #define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */
343037c1aaeSJosé Expósito #define HID_BATTERY_QUIRK_AVOID_QUERY (1 << 3) /* do not query the battery */
344bbc21cfdSJeremy Fitzhardinge
345bbc21cfdSJeremy Fitzhardinge static const struct hid_device_id hid_battery_quirks[] = {
346652aa6a9SJeremy Fitzhardinge { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
3474cc85417SOrtwin Glück USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
3484cc85417SOrtwin Glück HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
3494cc85417SOrtwin Glück { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
350cbd366beSRoss Skaliotis USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
351cbd366beSRoss Skaliotis HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
352cbd366beSRoss Skaliotis { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
353652aa6a9SJeremy Fitzhardinge USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
354652aa6a9SJeremy Fitzhardinge HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
3550c47935cSDaniel Nicoletti { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
356da940db4SKarl Relton USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
357da940db4SKarl Relton HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
358da940db4SKarl Relton { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
3590c47935cSDaniel Nicoletti USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
3600c47935cSDaniel Nicoletti HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
3619c34660eSNimish Gåtam { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
3629c34660eSNimish Gåtam USB_DEVICE_ID_APPLE_MAGICTRACKPAD),
3639c34660eSNimish Gåtam HID_BATTERY_QUIRK_IGNORE },
3645d9374cfSAlexander E. Patrakov { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
3655d9374cfSAlexander E. Patrakov USB_DEVICE_ID_ELECOM_BM084),
3665d9374cfSAlexander E. Patrakov HID_BATTERY_QUIRK_IGNORE },
3670fd79184SBenson Leung { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL,
3680fd79184SBenson Leung USB_DEVICE_ID_SYMBOL_SCANNER_3),
3690fd79184SBenson Leung HID_BATTERY_QUIRK_IGNORE },
370a767ffeaSNOGUCHI Hiroshi { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
371a767ffeaSNOGUCHI Hiroshi USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD),
372a767ffeaSNOGUCHI Hiroshi HID_BATTERY_QUIRK_IGNORE },
3737940fb03SHans de Goede { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
3747940fb03SHans de Goede USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
3757940fb03SHans de Goede HID_BATTERY_QUIRK_IGNORE },
376cb963b2cSmarco.rodolfi@tuta.io { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN),
377cb963b2cSmarco.rodolfi@tuta.io HID_BATTERY_QUIRK_IGNORE },
37835903009Sweiliang1503 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN),
37935903009Sweiliang1503 HID_BATTERY_QUIRK_IGNORE },
3807c38e769SSeth Miller { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
3817c38e769SSeth Miller HID_BATTERY_QUIRK_IGNORE },
38214902f89SHans de Goede { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
38314902f89SHans de Goede HID_BATTERY_QUIRK_IGNORE },
384037c1aaeSJosé Expósito { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
385037c1aaeSJosé Expósito HID_BATTERY_QUIRK_AVOID_QUERY },
3869266a881SJosé Expósito { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
3879266a881SJosé Expósito HID_BATTERY_QUIRK_AVOID_QUERY },
3887744ca57SJosé Expósito { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
3897744ca57SJosé Expósito HID_BATTERY_QUIRK_AVOID_QUERY },
390b74edf9bSTrevor Davenport { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
391b74edf9bSTrevor Davenport HID_BATTERY_QUIRK_IGNORE },
392f3193ea1SKarl Kurbjun { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),
393f3193ea1SKarl Kurbjun HID_BATTERY_QUIRK_IGNORE },
394cec827d6SJosé Expósito { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV),
395cec827d6SJosé Expósito HID_BATTERY_QUIRK_IGNORE },
396decfe496SElia Devito { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
397decfe496SElia Devito HID_BATTERY_QUIRK_IGNORE },
398ebebf05aSLuka Guzenko { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG),
399ebebf05aSLuka Guzenko HID_BATTERY_QUIRK_IGNORE },
400b5539722SZoltan Tamas Vajda { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
401b5539722SZoltan Tamas Vajda HID_BATTERY_QUIRK_IGNORE },
402db925d80SMaximilian Luz { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN),
403db925d80SMaximilian Luz HID_BATTERY_QUIRK_IGNORE },
4043a47fa7bSSteev Klimaszewski { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN),
4053a47fa7bSSteev Klimaszewski HID_BATTERY_QUIRK_IGNORE },
40650c6b976SPhilippe Troin { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100),
40750c6b976SPhilippe Troin HID_BATTERY_QUIRK_IGNORE },
40850c6b976SPhilippe Troin { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1),
40950c6b976SPhilippe Troin HID_BATTERY_QUIRK_IGNORE },
41050c6b976SPhilippe Troin { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2),
41150c6b976SPhilippe Troin HID_BATTERY_QUIRK_IGNORE },
412b009aa38SFabian Vogt { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG),
413b009aa38SFabian Vogt HID_BATTERY_QUIRK_IGNORE },
4140f09e89eSDmitry Torokhov { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
4150f09e89eSDmitry Torokhov HID_BATTERY_QUIRK_AVOID_QUERY },
416bbc21cfdSJeremy Fitzhardinge {}
417bbc21cfdSJeremy Fitzhardinge };
418bbc21cfdSJeremy Fitzhardinge
find_battery_quirk(struct hid_device * hdev)419bbc21cfdSJeremy Fitzhardinge static unsigned find_battery_quirk(struct hid_device *hdev)
420bbc21cfdSJeremy Fitzhardinge {
421bbc21cfdSJeremy Fitzhardinge unsigned quirks = 0;
422bbc21cfdSJeremy Fitzhardinge const struct hid_device_id *match;
423bbc21cfdSJeremy Fitzhardinge
424bbc21cfdSJeremy Fitzhardinge match = hid_match_id(hdev, hid_battery_quirks);
425bbc21cfdSJeremy Fitzhardinge if (match != NULL)
426bbc21cfdSJeremy Fitzhardinge quirks = match->driver_data;
427bbc21cfdSJeremy Fitzhardinge
428bbc21cfdSJeremy Fitzhardinge return quirks;
429bbc21cfdSJeremy Fitzhardinge }
430bbc21cfdSJeremy Fitzhardinge
hidinput_scale_battery_capacity(struct hid_device * dev,int value)431581c4484SDmitry Torokhov static int hidinput_scale_battery_capacity(struct hid_device *dev,
432581c4484SDmitry Torokhov int value)
433581c4484SDmitry Torokhov {
434581c4484SDmitry Torokhov if (dev->battery_min < dev->battery_max &&
435581c4484SDmitry Torokhov value >= dev->battery_min && value <= dev->battery_max)
436581c4484SDmitry Torokhov value = ((value - dev->battery_min) * 100) /
437581c4484SDmitry Torokhov (dev->battery_max - dev->battery_min);
438581c4484SDmitry Torokhov
439581c4484SDmitry Torokhov return value;
440581c4484SDmitry Torokhov }
441581c4484SDmitry Torokhov
hidinput_query_battery_capacity(struct hid_device * dev)442581c4484SDmitry Torokhov static int hidinput_query_battery_capacity(struct hid_device *dev)
443581c4484SDmitry Torokhov {
444581c4484SDmitry Torokhov u8 *buf;
445581c4484SDmitry Torokhov int ret;
446581c4484SDmitry Torokhov
4474f57caceSGrant Likely buf = kmalloc(4, GFP_KERNEL);
448581c4484SDmitry Torokhov if (!buf)
449581c4484SDmitry Torokhov return -ENOMEM;
450581c4484SDmitry Torokhov
4514f57caceSGrant Likely ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4,
452581c4484SDmitry Torokhov dev->battery_report_type, HID_REQ_GET_REPORT);
4534f57caceSGrant Likely if (ret < 2) {
454581c4484SDmitry Torokhov kfree(buf);
455581c4484SDmitry Torokhov return -ENODATA;
456581c4484SDmitry Torokhov }
457581c4484SDmitry Torokhov
458581c4484SDmitry Torokhov ret = hidinput_scale_battery_capacity(dev, buf[1]);
459581c4484SDmitry Torokhov kfree(buf);
460581c4484SDmitry Torokhov return ret;
461581c4484SDmitry Torokhov }
462581c4484SDmitry Torokhov
hidinput_get_battery_property(struct power_supply * psy,enum power_supply_property prop,union power_supply_propval * val)4634f5ca836SJeremy Fitzhardinge static int hidinput_get_battery_property(struct power_supply *psy,
4644f5ca836SJeremy Fitzhardinge enum power_supply_property prop,
4654f5ca836SJeremy Fitzhardinge union power_supply_propval *val)
4664f5ca836SJeremy Fitzhardinge {
467297d716fSKrzysztof Kozlowski struct hid_device *dev = power_supply_get_drvdata(psy);
468581c4484SDmitry Torokhov int value;
4694f5ca836SJeremy Fitzhardinge int ret = 0;
4704f5ca836SJeremy Fitzhardinge
4714f5ca836SJeremy Fitzhardinge switch (prop) {
4724f5ca836SJeremy Fitzhardinge case POWER_SUPPLY_PROP_PRESENT:
4734f5ca836SJeremy Fitzhardinge case POWER_SUPPLY_PROP_ONLINE:
4744f5ca836SJeremy Fitzhardinge val->intval = 1;
4754f5ca836SJeremy Fitzhardinge break;
4764f5ca836SJeremy Fitzhardinge
4774f5ca836SJeremy Fitzhardinge case POWER_SUPPLY_PROP_CAPACITY:
4782e210bbbSDmitry Torokhov if (dev->battery_status != HID_BATTERY_REPORTED &&
4792e210bbbSDmitry Torokhov !dev->battery_avoid_query) {
480581c4484SDmitry Torokhov value = hidinput_query_battery_capacity(dev);
481581c4484SDmitry Torokhov if (value < 0)
482581c4484SDmitry Torokhov return value;
483581c4484SDmitry Torokhov } else {
484581c4484SDmitry Torokhov value = dev->battery_capacity;
4856c2794a2SJiri Kosina }
486652aa6a9SJeremy Fitzhardinge
487581c4484SDmitry Torokhov val->intval = value;
488c5a92aa3SDaniel Nicoletti break;
4894f5ca836SJeremy Fitzhardinge
4904f5ca836SJeremy Fitzhardinge case POWER_SUPPLY_PROP_MODEL_NAME:
4914f5ca836SJeremy Fitzhardinge val->strval = dev->name;
4924f5ca836SJeremy Fitzhardinge break;
4934f5ca836SJeremy Fitzhardinge
494c5a92aa3SDaniel Nicoletti case POWER_SUPPLY_PROP_STATUS:
4952e210bbbSDmitry Torokhov if (dev->battery_status != HID_BATTERY_REPORTED &&
4962e210bbbSDmitry Torokhov !dev->battery_avoid_query) {
497581c4484SDmitry Torokhov value = hidinput_query_battery_capacity(dev);
498581c4484SDmitry Torokhov if (value < 0)
499581c4484SDmitry Torokhov return value;
500581c4484SDmitry Torokhov
501581c4484SDmitry Torokhov dev->battery_capacity = value;
5022e210bbbSDmitry Torokhov dev->battery_status = HID_BATTERY_QUERIED;
503581c4484SDmitry Torokhov }
504581c4484SDmitry Torokhov
5052e210bbbSDmitry Torokhov if (dev->battery_status == HID_BATTERY_UNKNOWN)
506581c4484SDmitry Torokhov val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
507581c4484SDmitry Torokhov else
508a608dc1cSJosé Expósito val->intval = dev->battery_charge_status;
509c5a92aa3SDaniel Nicoletti break;
510c5a92aa3SDaniel Nicoletti
51145d9c273SJeremy Fitzhardinge case POWER_SUPPLY_PROP_SCOPE:
51245d9c273SJeremy Fitzhardinge val->intval = POWER_SUPPLY_SCOPE_DEVICE;
51345d9c273SJeremy Fitzhardinge break;
51445d9c273SJeremy Fitzhardinge
5154f5ca836SJeremy Fitzhardinge default:
5164f5ca836SJeremy Fitzhardinge ret = -EINVAL;
5174f5ca836SJeremy Fitzhardinge break;
5184f5ca836SJeremy Fitzhardinge }
5194f5ca836SJeremy Fitzhardinge
5204f5ca836SJeremy Fitzhardinge return ret;
5214f5ca836SJeremy Fitzhardinge }
5224f5ca836SJeremy Fitzhardinge
hidinput_setup_battery(struct hid_device * dev,unsigned report_type,struct hid_field * field,bool is_percentage)5239de07a4eSJohn Chen static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
5249de07a4eSJohn Chen struct hid_field *field, bool is_percentage)
5254f5ca836SJeremy Fitzhardinge {
526581c4484SDmitry Torokhov struct power_supply_desc *psy_desc;
527297d716fSKrzysztof Kozlowski struct power_supply_config psy_cfg = { .drv_data = dev, };
528bbc21cfdSJeremy Fitzhardinge unsigned quirks;
5292f2e3f6dSJeremy Fitzhardinge s32 min, max;
530581c4484SDmitry Torokhov int error;
5312f2e3f6dSJeremy Fitzhardinge
532581c4484SDmitry Torokhov if (dev->battery)
533581c4484SDmitry Torokhov return 0; /* already initialized? */
5344f5ca836SJeremy Fitzhardinge
5355d9374cfSAlexander E. Patrakov quirks = find_battery_quirk(dev);
5365d9374cfSAlexander E. Patrakov
5375d9374cfSAlexander E. Patrakov hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
5385d9374cfSAlexander E. Patrakov dev->bus, dev->vendor, dev->product, dev->version, quirks);
5395d9374cfSAlexander E. Patrakov
5405d9374cfSAlexander E. Patrakov if (quirks & HID_BATTERY_QUIRK_IGNORE)
541581c4484SDmitry Torokhov return 0;
5425d9374cfSAlexander E. Patrakov
543297d716fSKrzysztof Kozlowski psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
544581c4484SDmitry Torokhov if (!psy_desc)
545581c4484SDmitry Torokhov return -ENOMEM;
5464f5ca836SJeremy Fitzhardinge
54709223865SDmitry Torokhov psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery",
54809223865SDmitry Torokhov strlen(dev->uniq) ?
54909223865SDmitry Torokhov dev->uniq : dev_name(&dev->dev));
550581c4484SDmitry Torokhov if (!psy_desc->name) {
551581c4484SDmitry Torokhov error = -ENOMEM;
552581c4484SDmitry Torokhov goto err_free_mem;
553297d716fSKrzysztof Kozlowski }
554297d716fSKrzysztof Kozlowski
555297d716fSKrzysztof Kozlowski psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
556297d716fSKrzysztof Kozlowski psy_desc->properties = hidinput_battery_props;
557297d716fSKrzysztof Kozlowski psy_desc->num_properties = ARRAY_SIZE(hidinput_battery_props);
558297d716fSKrzysztof Kozlowski psy_desc->use_for_apm = 0;
559297d716fSKrzysztof Kozlowski psy_desc->get_property = hidinput_get_battery_property;
5604f5ca836SJeremy Fitzhardinge
5612f2e3f6dSJeremy Fitzhardinge min = field->logical_minimum;
5622f2e3f6dSJeremy Fitzhardinge max = field->logical_maximum;
5632f2e3f6dSJeremy Fitzhardinge
5649de07a4eSJohn Chen if (is_percentage || (quirks & HID_BATTERY_QUIRK_PERCENT)) {
565bbc21cfdSJeremy Fitzhardinge min = 0;
566bbc21cfdSJeremy Fitzhardinge max = 100;
567bbc21cfdSJeremy Fitzhardinge }
568bbc21cfdSJeremy Fitzhardinge
569652aa6a9SJeremy Fitzhardinge if (quirks & HID_BATTERY_QUIRK_FEATURE)
570652aa6a9SJeremy Fitzhardinge report_type = HID_FEATURE_REPORT;
571652aa6a9SJeremy Fitzhardinge
5724f5ca836SJeremy Fitzhardinge dev->battery_min = min;
5734f5ca836SJeremy Fitzhardinge dev->battery_max = max;
574fb8ac91bSJeremy Fitzhardinge dev->battery_report_type = report_type;
5752f2e3f6dSJeremy Fitzhardinge dev->battery_report_id = field->report->id;
576a608dc1cSJosé Expósito dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
5774f5ca836SJeremy Fitzhardinge
5782e210bbbSDmitry Torokhov /*
5792e210bbbSDmitry Torokhov * Stylus is normally not connected to the device and thus we
5802e210bbbSDmitry Torokhov * can't query the device and get meaningful battery strength.
5812e210bbbSDmitry Torokhov * We have to wait for the device to report it on its own.
5822e210bbbSDmitry Torokhov */
5832e210bbbSDmitry Torokhov dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
5842e210bbbSDmitry Torokhov field->physical == HID_DG_STYLUS;
5852e210bbbSDmitry Torokhov
586037c1aaeSJosé Expósito if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY)
587037c1aaeSJosé Expósito dev->battery_avoid_query = true;
588037c1aaeSJosé Expósito
589297d716fSKrzysztof Kozlowski dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
590297d716fSKrzysztof Kozlowski if (IS_ERR(dev->battery)) {
591581c4484SDmitry Torokhov error = PTR_ERR(dev->battery);
592581c4484SDmitry Torokhov hid_warn(dev, "can't register power supply: %d\n", error);
593581c4484SDmitry Torokhov goto err_free_name;
594fbea947cSKrzysztof Kozlowski }
59545d9c273SJeremy Fitzhardinge
596581c4484SDmitry Torokhov power_supply_powers(dev->battery, &dev->dev);
597581c4484SDmitry Torokhov return 0;
598581c4484SDmitry Torokhov
599581c4484SDmitry Torokhov err_free_name:
600581c4484SDmitry Torokhov kfree(psy_desc->name);
601581c4484SDmitry Torokhov err_free_mem:
602581c4484SDmitry Torokhov kfree(psy_desc);
603581c4484SDmitry Torokhov dev->battery = NULL;
604581c4484SDmitry Torokhov return error;
6054f5ca836SJeremy Fitzhardinge }
6064f5ca836SJeremy Fitzhardinge
hidinput_cleanup_battery(struct hid_device * dev)6074f5ca836SJeremy Fitzhardinge static void hidinput_cleanup_battery(struct hid_device *dev)
6084f5ca836SJeremy Fitzhardinge {
6090621809eSKrzysztof Kozlowski const struct power_supply_desc *psy_desc;
6100621809eSKrzysztof Kozlowski
611297d716fSKrzysztof Kozlowski if (!dev->battery)
6124f5ca836SJeremy Fitzhardinge return;
6134f5ca836SJeremy Fitzhardinge
6140621809eSKrzysztof Kozlowski psy_desc = dev->battery->desc;
615297d716fSKrzysztof Kozlowski power_supply_unregister(dev->battery);
6160621809eSKrzysztof Kozlowski kfree(psy_desc->name);
6170621809eSKrzysztof Kozlowski kfree(psy_desc);
618297d716fSKrzysztof Kozlowski dev->battery = NULL;
6194f5ca836SJeremy Fitzhardinge }
620581c4484SDmitry Torokhov
hidinput_update_battery(struct hid_device * dev,int value)621581c4484SDmitry Torokhov static void hidinput_update_battery(struct hid_device *dev, int value)
622581c4484SDmitry Torokhov {
6230152b29cSDmitry Torokhov int capacity;
6240152b29cSDmitry Torokhov
625581c4484SDmitry Torokhov if (!dev->battery)
626581c4484SDmitry Torokhov return;
627581c4484SDmitry Torokhov
628581c4484SDmitry Torokhov if (value == 0 || value < dev->battery_min || value > dev->battery_max)
629581c4484SDmitry Torokhov return;
630581c4484SDmitry Torokhov
6310152b29cSDmitry Torokhov capacity = hidinput_scale_battery_capacity(dev, value);
6320152b29cSDmitry Torokhov
6332e210bbbSDmitry Torokhov if (dev->battery_status != HID_BATTERY_REPORTED ||
634c6838eeeSdmitry.torokhov@gmail.com capacity != dev->battery_capacity ||
635c6838eeeSdmitry.torokhov@gmail.com ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) {
6360152b29cSDmitry Torokhov dev->battery_capacity = capacity;
6372e210bbbSDmitry Torokhov dev->battery_status = HID_BATTERY_REPORTED;
638c6838eeeSdmitry.torokhov@gmail.com dev->battery_ratelimit_time =
639c6838eeeSdmitry.torokhov@gmail.com ktime_add_ms(ktime_get_coarse(), 30 * 1000);
640581c4484SDmitry Torokhov power_supply_changed(dev->battery);
641581c4484SDmitry Torokhov }
6420152b29cSDmitry Torokhov }
643a608dc1cSJosé Expósito
hidinput_set_battery_charge_status(struct hid_device * dev,unsigned int usage,int value)644a608dc1cSJosé Expósito static bool hidinput_set_battery_charge_status(struct hid_device *dev,
645a608dc1cSJosé Expósito unsigned int usage, int value)
646a608dc1cSJosé Expósito {
647a608dc1cSJosé Expósito switch (usage) {
648a608dc1cSJosé Expósito case HID_BAT_CHARGING:
649a608dc1cSJosé Expósito dev->battery_charge_status = value ?
650a608dc1cSJosé Expósito POWER_SUPPLY_STATUS_CHARGING :
651a608dc1cSJosé Expósito POWER_SUPPLY_STATUS_DISCHARGING;
652a608dc1cSJosé Expósito return true;
653a608dc1cSJosé Expósito }
654a608dc1cSJosé Expósito
655a608dc1cSJosé Expósito return false;
656a608dc1cSJosé Expósito }
6574f5ca836SJeremy Fitzhardinge #else /* !CONFIG_HID_BATTERY_STRENGTH */
hidinput_setup_battery(struct hid_device * dev,unsigned report_type,struct hid_field * field,bool is_percentage)658581c4484SDmitry Torokhov static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
6599de07a4eSJohn Chen struct hid_field *field, bool is_percentage)
6604f5ca836SJeremy Fitzhardinge {
661581c4484SDmitry Torokhov return 0;
6624f5ca836SJeremy Fitzhardinge }
6634f5ca836SJeremy Fitzhardinge
hidinput_cleanup_battery(struct hid_device * dev)6644f5ca836SJeremy Fitzhardinge static void hidinput_cleanup_battery(struct hid_device *dev)
6654f5ca836SJeremy Fitzhardinge {
6664f5ca836SJeremy Fitzhardinge }
667581c4484SDmitry Torokhov
hidinput_update_battery(struct hid_device * dev,int value)668581c4484SDmitry Torokhov static void hidinput_update_battery(struct hid_device *dev, int value)
669581c4484SDmitry Torokhov {
670581c4484SDmitry Torokhov }
671a608dc1cSJosé Expósito
hidinput_set_battery_charge_status(struct hid_device * dev,unsigned int usage,int value)672a608dc1cSJosé Expósito static bool hidinput_set_battery_charge_status(struct hid_device *dev,
673a608dc1cSJosé Expósito unsigned int usage, int value)
674a608dc1cSJosé Expósito {
675a608dc1cSJosé Expósito return false;
676a608dc1cSJosé Expósito }
6774f5ca836SJeremy Fitzhardinge #endif /* CONFIG_HID_BATTERY_STRENGTH */
6784f5ca836SJeremy Fitzhardinge
hidinput_field_in_collection(struct hid_device * device,struct hid_field * field,unsigned int type,unsigned int usage)679bcfa8d14SThomas Weißschuh static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field,
680bcfa8d14SThomas Weißschuh unsigned int type, unsigned int usage)
681bcfa8d14SThomas Weißschuh {
682bcfa8d14SThomas Weißschuh struct hid_collection *collection;
683bcfa8d14SThomas Weißschuh
684bcfa8d14SThomas Weißschuh collection = &device->collection[field->usage->collection_index];
685bcfa8d14SThomas Weißschuh
686bcfa8d14SThomas Weißschuh return collection->type == type && collection->usage == usage;
687bcfa8d14SThomas Weißschuh }
688bcfa8d14SThomas Weißschuh
hidinput_configure_usage(struct hid_input * hidinput,struct hid_field * field,struct hid_usage * usage,unsigned int usage_index)689dde5845aSJiri Kosina static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
690048cddfdSBenjamin Tissoires struct hid_usage *usage, unsigned int usage_index)
691dde5845aSJiri Kosina {
692dde5845aSJiri Kosina struct input_dev *input = hidinput->input;
693e0712985SDmitry Torokhov struct hid_device *device = input_get_drvdata(input);
6945c20000aSBenjamin Tissoires const struct usage_priority *usage_priority = NULL;
6953715ade9SJiri Slaby int max = 0, code;
696048cddfdSBenjamin Tissoires unsigned int i = 0;
697dde5845aSJiri Kosina unsigned long *bit = NULL;
698dde5845aSJiri Kosina
699dde5845aSJiri Kosina field->hidinput = hidinput;
700dde5845aSJiri Kosina
701dde5845aSJiri Kosina if (field->flags & HID_MAIN_ITEM_CONSTANT)
702dde5845aSJiri Kosina goto ignore;
703dde5845aSJiri Kosina
704cc6b54aaSBenjamin Tissoires /* Ignore if report count is out of bounds. */
705cc6b54aaSBenjamin Tissoires if (field->report_count < 1)
706cc6b54aaSBenjamin Tissoires goto ignore;
707cc6b54aaSBenjamin Tissoires
70882eb1219SJiri Kosina /* only LED usages are supported in output fields */
70982eb1219SJiri Kosina if (field->report_type == HID_OUTPUT_REPORT &&
71082eb1219SJiri Kosina (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
71182eb1219SJiri Kosina goto ignore;
71282eb1219SJiri Kosina }
71382eb1219SJiri Kosina
714048cddfdSBenjamin Tissoires /* assign a priority based on the static list declared here */
715048cddfdSBenjamin Tissoires for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
7165c20000aSBenjamin Tissoires if (usage->hid == hidinput_usages_priorities[i].usage) {
7175c20000aSBenjamin Tissoires usage_priority = &hidinput_usages_priorities[i];
7185c20000aSBenjamin Tissoires
719048cddfdSBenjamin Tissoires field->usages_priorities[usage_index] =
720048cddfdSBenjamin Tissoires (ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
721048cddfdSBenjamin Tissoires break;
722048cddfdSBenjamin Tissoires }
723048cddfdSBenjamin Tissoires }
724048cddfdSBenjamin Tissoires
7255c20000aSBenjamin Tissoires /*
7265c20000aSBenjamin Tissoires * For slotted devices, we need to also add the slot index
7275c20000aSBenjamin Tissoires * in the priority.
7285c20000aSBenjamin Tissoires */
7295c20000aSBenjamin Tissoires if (usage_priority && usage_priority->global)
7305c20000aSBenjamin Tissoires field->usages_priorities[usage_index] |=
7315c20000aSBenjamin Tissoires usage_priority->slot_overwrite;
7325c20000aSBenjamin Tissoires else
7335c20000aSBenjamin Tissoires field->usages_priorities[usage_index] |=
7345c20000aSBenjamin Tissoires (0xff - field->slot_idx) << 16;
7355c20000aSBenjamin Tissoires
736c500c971SJiri Slaby if (device->driver->input_mapping) {
737c500c971SJiri Slaby int ret = device->driver->input_mapping(device, hidinput, field,
738c500c971SJiri Slaby usage, &bit, &max);
739c500c971SJiri Slaby if (ret > 0)
740c500c971SJiri Slaby goto mapped;
741c500c971SJiri Slaby if (ret < 0)
742c500c971SJiri Slaby goto ignore;
743c500c971SJiri Slaby }
744c500c971SJiri Slaby
745dde5845aSJiri Kosina switch (usage->hid & HID_USAGE_PAGE) {
746dde5845aSJiri Kosina case HID_UP_UNDEFINED:
747dde5845aSJiri Kosina goto ignore;
748dde5845aSJiri Kosina
749dde5845aSJiri Kosina case HID_UP_KEYBOARD:
750dde5845aSJiri Kosina set_bit(EV_REP, input->evbit);
751dde5845aSJiri Kosina
752dde5845aSJiri Kosina if ((usage->hid & HID_USAGE) < 256) {
753dde5845aSJiri Kosina if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
754dde5845aSJiri Kosina map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
755dde5845aSJiri Kosina } else
756dde5845aSJiri Kosina map_key(KEY_UNKNOWN);
757dde5845aSJiri Kosina
758dde5845aSJiri Kosina break;
759dde5845aSJiri Kosina
760dde5845aSJiri Kosina case HID_UP_BUTTON:
7617f978b9bSJiri Kosina code = ((usage->hid - 1) & HID_USAGE);
762dde5845aSJiri Kosina
763dde5845aSJiri Kosina switch (field->application) {
764dde5845aSJiri Kosina case HID_GD_MOUSE:
7651874542dSFlorian Fainelli case HID_GD_POINTER: code += BTN_MOUSE; break;
766cf2f765fSJiri Kosina case HID_GD_JOYSTICK:
767cf2f765fSJiri Kosina if (code <= 0xf)
768cf2f765fSJiri Kosina code += BTN_JOYSTICK;
769cf2f765fSJiri Kosina else
770f8e86d05SIngo Ruhnke code += BTN_TRIGGER_HAPPY - 0x10;
771cf2f765fSJiri Kosina break;
772f8e86d05SIngo Ruhnke case HID_GD_GAMEPAD:
773f8e86d05SIngo Ruhnke if (code <= 0xf)
774f8e86d05SIngo Ruhnke code += BTN_GAMEPAD;
775f8e86d05SIngo Ruhnke else
776f8e86d05SIngo Ruhnke code += BTN_TRIGGER_HAPPY - 0x10;
777f8e86d05SIngo Ruhnke break;
778bcfa8d14SThomas Weißschuh case HID_CP_CONSUMER_CONTROL:
779bcfa8d14SThomas Weißschuh if (hidinput_field_in_collection(device, field,
780bcfa8d14SThomas Weißschuh HID_COLLECTION_NAMED_ARRAY,
781bcfa8d14SThomas Weißschuh HID_CP_PROGRAMMABLEBUTTONS)) {
782bcfa8d14SThomas Weißschuh if (code <= 0x1d)
783bcfa8d14SThomas Weißschuh code += KEY_MACRO1;
784bcfa8d14SThomas Weißschuh else
785bcfa8d14SThomas Weißschuh code += BTN_TRIGGER_HAPPY - 0x1e;
786bcfa8d14SThomas Weißschuh break;
7877fc48fd6SHans de Goede }
7887fc48fd6SHans de Goede fallthrough;
789dde5845aSJiri Kosina default:
790dde5845aSJiri Kosina switch (field->physical) {
791dde5845aSJiri Kosina case HID_GD_MOUSE:
7921874542dSFlorian Fainelli case HID_GD_POINTER: code += BTN_MOUSE; break;
7931874542dSFlorian Fainelli case HID_GD_JOYSTICK: code += BTN_JOYSTICK; break;
7941874542dSFlorian Fainelli case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break;
7951874542dSFlorian Fainelli default: code += BTN_MISC;
796dde5845aSJiri Kosina }
797dde5845aSJiri Kosina }
798dde5845aSJiri Kosina
79925914662SJiri Kosina map_key(code);
800dde5845aSJiri Kosina break;
801dde5845aSJiri Kosina
802dde5845aSJiri Kosina case HID_UP_SIMULATION:
803dde5845aSJiri Kosina switch (usage->hid & 0xffff) {
804dde5845aSJiri Kosina case 0xba: map_abs(ABS_RUDDER); break;
805dde5845aSJiri Kosina case 0xbb: map_abs(ABS_THROTTLE); break;
806dde5845aSJiri Kosina case 0xc4: map_abs(ABS_GAS); break;
807dde5845aSJiri Kosina case 0xc5: map_abs(ABS_BRAKE); break;
808dde5845aSJiri Kosina case 0xc8: map_abs(ABS_WHEEL); break;
809dde5845aSJiri Kosina default: goto ignore;
810dde5845aSJiri Kosina }
811dde5845aSJiri Kosina break;
812dde5845aSJiri Kosina
813dde5845aSJiri Kosina case HID_UP_GENDESK:
814dde5845aSJiri Kosina if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
815dde5845aSJiri Kosina switch (usage->hid & 0xf) {
816dde5845aSJiri Kosina case 0x1: map_key_clear(KEY_POWER); break;
817dde5845aSJiri Kosina case 0x2: map_key_clear(KEY_SLEEP); break;
818dde5845aSJiri Kosina case 0x3: map_key_clear(KEY_WAKEUP); break;
819437f3b19SJarod Wilson case 0x4: map_key_clear(KEY_CONTEXT_MENU); break;
820437f3b19SJarod Wilson case 0x5: map_key_clear(KEY_MENU); break;
821437f3b19SJarod Wilson case 0x6: map_key_clear(KEY_PROG1); break;
822437f3b19SJarod Wilson case 0x7: map_key_clear(KEY_HELP); break;
823437f3b19SJarod Wilson case 0x8: map_key_clear(KEY_EXIT); break;
824437f3b19SJarod Wilson case 0x9: map_key_clear(KEY_SELECT); break;
825437f3b19SJarod Wilson case 0xa: map_key_clear(KEY_RIGHT); break;
826437f3b19SJarod Wilson case 0xb: map_key_clear(KEY_LEFT); break;
827437f3b19SJarod Wilson case 0xc: map_key_clear(KEY_UP); break;
828437f3b19SJarod Wilson case 0xd: map_key_clear(KEY_DOWN); break;
829437f3b19SJarod Wilson case 0xe: map_key_clear(KEY_POWER2); break;
830437f3b19SJarod Wilson case 0xf: map_key_clear(KEY_RESTART); break;
831dde5845aSJiri Kosina default: goto unknown;
832dde5845aSJiri Kosina }
833dde5845aSJiri Kosina break;
834dde5845aSJiri Kosina }
835dde5845aSJiri Kosina
8362d60f9f4SJingyuan Liang if ((usage->hid & 0xf0) == 0xa0) { /* SystemControl */
8372d60f9f4SJingyuan Liang switch (usage->hid & 0xf) {
8382d60f9f4SJingyuan Liang case 0x9: map_key_clear(KEY_MICMUTE); break;
8392d60f9f4SJingyuan Liang default: goto ignore;
8402d60f9f4SJingyuan Liang }
8412d60f9f4SJingyuan Liang break;
8422d60f9f4SJingyuan Liang }
8432d60f9f4SJingyuan Liang
844c01908a1SDmitry Torokhov if ((usage->hid & 0xf0) == 0xb0) { /* SC - Display */
845c01908a1SDmitry Torokhov switch (usage->hid & 0xf) {
846c01908a1SDmitry Torokhov case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break;
847c01908a1SDmitry Torokhov default: goto ignore;
848c01908a1SDmitry Torokhov }
849c01908a1SDmitry Torokhov break;
850c01908a1SDmitry Torokhov }
851c01908a1SDmitry Torokhov
8521989dadaSBenjamin Tissoires /*
8531989dadaSBenjamin Tissoires * Some lazy vendors declare 255 usages for System Control,
8541989dadaSBenjamin Tissoires * leading to the creation of ABS_X|Y axis and too many others.
8551989dadaSBenjamin Tissoires * It wouldn't be a problem if joydev doesn't consider the
8561989dadaSBenjamin Tissoires * device as a joystick then.
8571989dadaSBenjamin Tissoires */
8581989dadaSBenjamin Tissoires if (field->application == HID_GD_SYSTEM_CONTROL)
8591989dadaSBenjamin Tissoires goto ignore;
8601989dadaSBenjamin Tissoires
861dde5845aSJiri Kosina if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
862dde5845aSJiri Kosina switch (usage->hid) {
863dde5845aSJiri Kosina case HID_GD_UP: usage->hat_dir = 1; break;
864dde5845aSJiri Kosina case HID_GD_DOWN: usage->hat_dir = 5; break;
865dde5845aSJiri Kosina case HID_GD_RIGHT: usage->hat_dir = 3; break;
866dde5845aSJiri Kosina case HID_GD_LEFT: usage->hat_dir = 7; break;
867dde5845aSJiri Kosina default: goto unknown;
868dde5845aSJiri Kosina }
869dde5845aSJiri Kosina if (field->dpad) {
870dde5845aSJiri Kosina map_abs(field->dpad);
871dde5845aSJiri Kosina goto ignore;
872dde5845aSJiri Kosina }
873dde5845aSJiri Kosina map_abs(ABS_HAT0X);
874dde5845aSJiri Kosina break;
875dde5845aSJiri Kosina }
876dde5845aSJiri Kosina
877dde5845aSJiri Kosina switch (usage->hid) {
878dde5845aSJiri Kosina /* These usage IDs map directly to the usage codes. */
879dde5845aSJiri Kosina case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
880dde5845aSJiri Kosina case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
88179346d62SBenjamin Tissoires if (field->flags & HID_MAIN_ITEM_RELATIVE)
88279346d62SBenjamin Tissoires map_rel(usage->hid & 0xf);
88379346d62SBenjamin Tissoires else
88479346d62SBenjamin Tissoires map_abs_clear(usage->hid & 0xf);
88579346d62SBenjamin Tissoires break;
88679346d62SBenjamin Tissoires
8872dc702c9SPeter Hutterer case HID_GD_WHEEL:
8882dc702c9SPeter Hutterer if (field->flags & HID_MAIN_ITEM_RELATIVE) {
8892dc702c9SPeter Hutterer set_bit(REL_WHEEL, input->relbit);
8902dc702c9SPeter Hutterer map_rel(REL_WHEEL_HI_RES);
8912dc702c9SPeter Hutterer } else {
8922dc702c9SPeter Hutterer map_abs(usage->hid & 0xf);
8932dc702c9SPeter Hutterer }
8942dc702c9SPeter Hutterer break;
8952dc702c9SPeter Hutterer case HID_GD_SLIDER: case HID_GD_DIAL:
896dde5845aSJiri Kosina if (field->flags & HID_MAIN_ITEM_RELATIVE)
89725914662SJiri Kosina map_rel(usage->hid & 0xf);
898dde5845aSJiri Kosina else
89925914662SJiri Kosina map_abs(usage->hid & 0xf);
900dde5845aSJiri Kosina break;
901dde5845aSJiri Kosina
902dde5845aSJiri Kosina case HID_GD_HATSWITCH:
903dde5845aSJiri Kosina usage->hat_min = field->logical_minimum;
904dde5845aSJiri Kosina usage->hat_max = field->logical_maximum;
905dde5845aSJiri Kosina map_abs(ABS_HAT0X);
906dde5845aSJiri Kosina break;
907dde5845aSJiri Kosina
908dde5845aSJiri Kosina case HID_GD_START: map_key_clear(BTN_START); break;
909dde5845aSJiri Kosina case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
910dde5845aSJiri Kosina
91161df56beSHans de Goede case HID_GD_RFKILL_BTN:
91261df56beSHans de Goede /* MS wireless radio ctl extension, also check CA */
9136e7edabfSHans de Goede if (field->application == HID_GD_WIRELESS_RADIO_CTLS) {
91461df56beSHans de Goede map_key_clear(KEY_RFKILL);
91561df56beSHans de Goede /* We need to simulate the btn release */
91661df56beSHans de Goede field->flags |= HID_MAIN_ITEM_RELATIVE;
91761df56beSHans de Goede break;
91861df56beSHans de Goede }
9196b554275SGustavo A. R. Silva goto unknown;
92061df56beSHans de Goede
921dde5845aSJiri Kosina default: goto unknown;
922dde5845aSJiri Kosina }
923dde5845aSJiri Kosina
924dde5845aSJiri Kosina break;
925dde5845aSJiri Kosina
926dde5845aSJiri Kosina case HID_UP_LED:
927d4ae650aSSimon Budig switch (usage->hid & 0xffff) { /* HID-Value: */
928d4ae650aSSimon Budig case 0x01: map_led (LED_NUML); break; /* "Num Lock" */
929d4ae650aSSimon Budig case 0x02: map_led (LED_CAPSL); break; /* "Caps Lock" */
930d4ae650aSSimon Budig case 0x03: map_led (LED_SCROLLL); break; /* "Scroll Lock" */
931d4ae650aSSimon Budig case 0x04: map_led (LED_COMPOSE); break; /* "Compose" */
932d4ae650aSSimon Budig case 0x05: map_led (LED_KANA); break; /* "Kana" */
933d4ae650aSSimon Budig case 0x27: map_led (LED_SLEEP); break; /* "Stand-By" */
934d4ae650aSSimon Budig case 0x4c: map_led (LED_SUSPEND); break; /* "System Suspend" */
935d4ae650aSSimon Budig case 0x09: map_led (LED_MUTE); break; /* "Mute" */
936d4ae650aSSimon Budig case 0x4b: map_led (LED_MISC); break; /* "Generic Indicator" */
937d4ae650aSSimon Budig case 0x19: map_led (LED_MAIL); break; /* "Message Waiting" */
938d4ae650aSSimon Budig case 0x4d: map_led (LED_CHARGING); break; /* "External Power Connected" */
939d4ae650aSSimon Budig
940d4ae650aSSimon Budig default: goto ignore;
941d4ae650aSSimon Budig }
942dde5845aSJiri Kosina break;
943dde5845aSJiri Kosina
944dde5845aSJiri Kosina case HID_UP_DIGITIZER:
9458473a93dSTatsunosuke Tobita if ((field->application & 0xff) == 0x01) /* Digitizer */
9468473a93dSTatsunosuke Tobita __set_bit(INPUT_PROP_POINTER, input->propbit);
9478473a93dSTatsunosuke Tobita else if ((field->application & 0xff) == 0x02) /* Pen */
9488473a93dSTatsunosuke Tobita __set_bit(INPUT_PROP_DIRECT, input->propbit);
9498473a93dSTatsunosuke Tobita
950dde5845aSJiri Kosina switch (usage->hid & 0xff) {
9518c8b01c3SForest Bond case 0x00: /* Undefined */
9528c8b01c3SForest Bond goto ignore;
9538c8b01c3SForest Bond
954dde5845aSJiri Kosina case 0x30: /* TipPressure */
955dde5845aSJiri Kosina if (!test_bit(BTN_TOUCH, input->keybit)) {
956dde5845aSJiri Kosina device->quirks |= HID_QUIRK_NOTOUCH;
957dde5845aSJiri Kosina set_bit(EV_KEY, input->evbit);
958dde5845aSJiri Kosina set_bit(BTN_TOUCH, input->keybit);
959dde5845aSJiri Kosina }
960dde5845aSJiri Kosina map_abs_clear(ABS_PRESSURE);
961dde5845aSJiri Kosina break;
962dde5845aSJiri Kosina
963dde5845aSJiri Kosina case 0x32: /* InRange */
9643c2b0dbdSBenjamin Tissoires switch (field->physical) {
9653c2b0dbdSBenjamin Tissoires case HID_DG_PUCK:
9663c2b0dbdSBenjamin Tissoires map_key(BTN_TOOL_MOUSE);
9673c2b0dbdSBenjamin Tissoires break;
9683c2b0dbdSBenjamin Tissoires case HID_DG_FINGER:
9693c2b0dbdSBenjamin Tissoires map_key(BTN_TOOL_FINGER);
9703c2b0dbdSBenjamin Tissoires break;
9713c2b0dbdSBenjamin Tissoires default:
9723c2b0dbdSBenjamin Tissoires /*
9733c2b0dbdSBenjamin Tissoires * If the physical is not given,
9743c2b0dbdSBenjamin Tissoires * rely on the application.
9753c2b0dbdSBenjamin Tissoires */
9763c2b0dbdSBenjamin Tissoires if (!field->physical) {
9773c2b0dbdSBenjamin Tissoires switch (field->application) {
9783c2b0dbdSBenjamin Tissoires case HID_DG_TOUCHSCREEN:
9793c2b0dbdSBenjamin Tissoires case HID_DG_TOUCHPAD:
9803c2b0dbdSBenjamin Tissoires map_key_clear(BTN_TOOL_FINGER);
9813c2b0dbdSBenjamin Tissoires break;
9823c2b0dbdSBenjamin Tissoires default:
9833c2b0dbdSBenjamin Tissoires map_key_clear(BTN_TOOL_PEN);
9843c2b0dbdSBenjamin Tissoires }
9853c2b0dbdSBenjamin Tissoires } else {
9863c2b0dbdSBenjamin Tissoires map_key(BTN_TOOL_PEN);
9873c2b0dbdSBenjamin Tissoires }
9883c2b0dbdSBenjamin Tissoires break;
989dde5845aSJiri Kosina }
990dde5845aSJiri Kosina break;
991dde5845aSJiri Kosina
992581c4484SDmitry Torokhov case 0x3b: /* Battery Strength */
9939de07a4eSJohn Chen hidinput_setup_battery(device, HID_INPUT_REPORT, field, false);
994581c4484SDmitry Torokhov usage->type = EV_PWR;
995505f394fSDmitry Torokhov return;
996581c4484SDmitry Torokhov
997dde5845aSJiri Kosina case 0x3c: /* Invert */
998276e14e6SIllia Ostapyshyn device->quirks &= ~HID_QUIRK_NOINVERT;
999dde5845aSJiri Kosina map_key_clear(BTN_TOOL_RUBBER);
1000dde5845aSJiri Kosina break;
1001dde5845aSJiri Kosina
1002b73b2da0SNikolai Kondrashov case 0x3d: /* X Tilt */
1003b73b2da0SNikolai Kondrashov map_abs_clear(ABS_TILT_X);
1004b73b2da0SNikolai Kondrashov break;
1005b73b2da0SNikolai Kondrashov
1006b73b2da0SNikolai Kondrashov case 0x3e: /* Y Tilt */
1007b73b2da0SNikolai Kondrashov map_abs_clear(ABS_TILT_Y);
1008b73b2da0SNikolai Kondrashov break;
1009b73b2da0SNikolai Kondrashov
1010dde5845aSJiri Kosina case 0x33: /* Touch */
1011dde5845aSJiri Kosina case 0x42: /* TipSwitch */
1012dde5845aSJiri Kosina case 0x43: /* TipSwitch2 */
1013dde5845aSJiri Kosina device->quirks &= ~HID_QUIRK_NOTOUCH;
1014dde5845aSJiri Kosina map_key_clear(BTN_TOUCH);
1015dde5845aSJiri Kosina break;
1016dde5845aSJiri Kosina
1017dde5845aSJiri Kosina case 0x44: /* BarrelSwitch */
1018dde5845aSJiri Kosina map_key_clear(BTN_STYLUS);
1019dde5845aSJiri Kosina break;
1020dde5845aSJiri Kosina
1021654c192aSPing Cheng case 0x45: /* ERASER */
1022654c192aSPing Cheng /*
1023654c192aSPing Cheng * This event is reported when eraser tip touches the surface.
1024276e14e6SIllia Ostapyshyn * Actual eraser (BTN_TOOL_RUBBER) is set and released either
1025276e14e6SIllia Ostapyshyn * by Invert if tool reports proximity or by Eraser directly.
1026654c192aSPing Cheng */
1027276e14e6SIllia Ostapyshyn if (!test_bit(BTN_TOOL_RUBBER, input->keybit)) {
1028276e14e6SIllia Ostapyshyn device->quirks |= HID_QUIRK_NOINVERT;
1029276e14e6SIllia Ostapyshyn set_bit(BTN_TOOL_RUBBER, input->keybit);
1030276e14e6SIllia Ostapyshyn }
1031654c192aSPing Cheng map_key_clear(BTN_TOUCH);
1032654c192aSPing Cheng break;
1033654c192aSPing Cheng
103450b63697SNikolai Kondrashov case 0x46: /* TabletPick */
1035368c9664SPing Cheng case 0x5a: /* SecondaryBarrelSwitch */
103650b63697SNikolai Kondrashov map_key_clear(BTN_STYLUS2);
103750b63697SNikolai Kondrashov break;
103850b63697SNikolai Kondrashov
1039368c9664SPing Cheng case 0x5b: /* TransducerSerialNumber */
1040f3e82521SFelipe Balbi case 0x6e: /* TransducerSerialNumber2 */
10418aa45b54SMika Westerberg map_msc(MSC_SERIAL);
1042368c9664SPing Cheng break;
1043368c9664SPing Cheng
1044dde5845aSJiri Kosina default: goto unknown;
1045dde5845aSJiri Kosina }
1046dde5845aSJiri Kosina break;
1047dde5845aSJiri Kosina
1048f3dddf24SDmitry Torokhov case HID_UP_TELEPHONY:
1049f3dddf24SDmitry Torokhov switch (usage->hid & HID_USAGE) {
1050f3dddf24SDmitry Torokhov case 0x2f: map_key_clear(KEY_MICMUTE); break;
1051f3dddf24SDmitry Torokhov case 0xb0: map_key_clear(KEY_NUMERIC_0); break;
1052f3dddf24SDmitry Torokhov case 0xb1: map_key_clear(KEY_NUMERIC_1); break;
1053f3dddf24SDmitry Torokhov case 0xb2: map_key_clear(KEY_NUMERIC_2); break;
1054f3dddf24SDmitry Torokhov case 0xb3: map_key_clear(KEY_NUMERIC_3); break;
1055f3dddf24SDmitry Torokhov case 0xb4: map_key_clear(KEY_NUMERIC_4); break;
1056f3dddf24SDmitry Torokhov case 0xb5: map_key_clear(KEY_NUMERIC_5); break;
1057f3dddf24SDmitry Torokhov case 0xb6: map_key_clear(KEY_NUMERIC_6); break;
1058f3dddf24SDmitry Torokhov case 0xb7: map_key_clear(KEY_NUMERIC_7); break;
1059f3dddf24SDmitry Torokhov case 0xb8: map_key_clear(KEY_NUMERIC_8); break;
1060f3dddf24SDmitry Torokhov case 0xb9: map_key_clear(KEY_NUMERIC_9); break;
1061f3dddf24SDmitry Torokhov case 0xba: map_key_clear(KEY_NUMERIC_STAR); break;
1062f3dddf24SDmitry Torokhov case 0xbb: map_key_clear(KEY_NUMERIC_POUND); break;
1063f3dddf24SDmitry Torokhov case 0xbc: map_key_clear(KEY_NUMERIC_A); break;
1064f3dddf24SDmitry Torokhov case 0xbd: map_key_clear(KEY_NUMERIC_B); break;
1065f3dddf24SDmitry Torokhov case 0xbe: map_key_clear(KEY_NUMERIC_C); break;
1066f3dddf24SDmitry Torokhov case 0xbf: map_key_clear(KEY_NUMERIC_D); break;
1067f3dddf24SDmitry Torokhov default: goto ignore;
1068f3dddf24SDmitry Torokhov }
1069f3dddf24SDmitry Torokhov break;
1070f3dddf24SDmitry Torokhov
1071437f3b19SJarod Wilson case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */
1072dde5845aSJiri Kosina switch (usage->hid & HID_USAGE) {
1073dde5845aSJiri Kosina case 0x000: goto ignore;
1074437f3b19SJarod Wilson case 0x030: map_key_clear(KEY_POWER); break;
1075437f3b19SJarod Wilson case 0x031: map_key_clear(KEY_RESTART); break;
1076437f3b19SJarod Wilson case 0x032: map_key_clear(KEY_SLEEP); break;
1077dde5845aSJiri Kosina case 0x034: map_key_clear(KEY_SLEEP); break;
1078437f3b19SJarod Wilson case 0x035: map_key_clear(KEY_KBDILLUMTOGGLE); break;
1079dde5845aSJiri Kosina case 0x036: map_key_clear(BTN_MISC); break;
1080daa0bc90SChris Clayton
1081437f3b19SJarod Wilson case 0x040: map_key_clear(KEY_MENU); break; /* Menu */
1082437f3b19SJarod Wilson case 0x041: map_key_clear(KEY_SELECT); break; /* Menu Pick */
1083437f3b19SJarod Wilson case 0x042: map_key_clear(KEY_UP); break; /* Menu Up */
1084437f3b19SJarod Wilson case 0x043: map_key_clear(KEY_DOWN); break; /* Menu Down */
1085437f3b19SJarod Wilson case 0x044: map_key_clear(KEY_LEFT); break; /* Menu Left */
1086437f3b19SJarod Wilson case 0x045: map_key_clear(KEY_RIGHT); break; /* Menu Right */
1087437f3b19SJarod Wilson case 0x046: map_key_clear(KEY_ESC); break; /* Menu Escape */
1088437f3b19SJarod Wilson case 0x047: map_key_clear(KEY_KPPLUS); break; /* Menu Value Increase */
1089437f3b19SJarod Wilson case 0x048: map_key_clear(KEY_KPMINUS); break; /* Menu Value Decrease */
10901c1e40b5SFlorian Festi
1091437f3b19SJarod Wilson case 0x060: map_key_clear(KEY_INFO); break; /* Data On Screen */
1092437f3b19SJarod Wilson case 0x061: map_key_clear(KEY_SUBTITLE); break; /* Closed Caption */
1093437f3b19SJarod Wilson case 0x063: map_key_clear(KEY_VCR); break; /* VCR/TV */
1094437f3b19SJarod Wilson case 0x065: map_key_clear(KEY_CAMERA); break; /* Snapshot */
1095437f3b19SJarod Wilson case 0x069: map_key_clear(KEY_RED); break;
1096437f3b19SJarod Wilson case 0x06a: map_key_clear(KEY_GREEN); break;
1097437f3b19SJarod Wilson case 0x06b: map_key_clear(KEY_BLUE); break;
1098437f3b19SJarod Wilson case 0x06c: map_key_clear(KEY_YELLOW); break;
1099f7b3d85aSDmitry Torokhov case 0x06d: map_key_clear(KEY_ASPECT_RATIO); break;
1100437f3b19SJarod Wilson
1101f362e690SOlivier Gay case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break;
1102f362e690SOlivier Gay case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break;
1103f362e690SOlivier Gay case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break;
1104f362e690SOlivier Gay case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break;
1105f362e690SOlivier Gay case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break;
1106f362e690SOlivier Gay case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break;
1107f362e690SOlivier Gay
1108e3ea6467SDmitry Torokhov case 0x076: map_key_clear(KEY_CAMERA_ACCESS_ENABLE); break;
1109e3ea6467SDmitry Torokhov case 0x077: map_key_clear(KEY_CAMERA_ACCESS_DISABLE); break;
1110e3ea6467SDmitry Torokhov case 0x078: map_key_clear(KEY_CAMERA_ACCESS_TOGGLE); break;
1111e3ea6467SDmitry Torokhov
11127975a1d6SDmitry Torokhov case 0x079: map_key_clear(KEY_KBDILLUMUP); break;
11137975a1d6SDmitry Torokhov case 0x07a: map_key_clear(KEY_KBDILLUMDOWN); break;
11147975a1d6SDmitry Torokhov case 0x07c: map_key_clear(KEY_KBDILLUMTOGGLE); break;
11157975a1d6SDmitry Torokhov
1116437f3b19SJarod Wilson case 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
11178eda232eSSimon Bennett case 0x083: map_key_clear(KEY_LAST); break;
1118437f3b19SJarod Wilson case 0x084: map_key_clear(KEY_ENTER); break;
11191c1e40b5SFlorian Festi case 0x088: map_key_clear(KEY_PC); break;
11201c1e40b5SFlorian Festi case 0x089: map_key_clear(KEY_TV); break;
1121dde5845aSJiri Kosina case 0x08a: map_key_clear(KEY_WWW); break;
11221c1e40b5SFlorian Festi case 0x08b: map_key_clear(KEY_DVD); break;
11231c1e40b5SFlorian Festi case 0x08c: map_key_clear(KEY_PHONE); break;
1124dde5845aSJiri Kosina case 0x08d: map_key_clear(KEY_PROGRAM); break;
11251c1e40b5SFlorian Festi case 0x08e: map_key_clear(KEY_VIDEOPHONE); break;
11261c1e40b5SFlorian Festi case 0x08f: map_key_clear(KEY_GAMES); break;
11271c1e40b5SFlorian Festi case 0x090: map_key_clear(KEY_MEMO); break;
11281c1e40b5SFlorian Festi case 0x091: map_key_clear(KEY_CD); break;
11291c1e40b5SFlorian Festi case 0x092: map_key_clear(KEY_VCR); break;
11301c1e40b5SFlorian Festi case 0x093: map_key_clear(KEY_TUNER); break;
11311c1e40b5SFlorian Festi case 0x094: map_key_clear(KEY_EXIT); break;
1132dde5845aSJiri Kosina case 0x095: map_key_clear(KEY_HELP); break;
11331c1e40b5SFlorian Festi case 0x096: map_key_clear(KEY_TAPE); break;
11341c1e40b5SFlorian Festi case 0x097: map_key_clear(KEY_TV2); break;
11351c1e40b5SFlorian Festi case 0x098: map_key_clear(KEY_SAT); break;
11368eda232eSSimon Bennett case 0x09a: map_key_clear(KEY_PVR); break;
11371c1e40b5SFlorian Festi
1138dde5845aSJiri Kosina case 0x09c: map_key_clear(KEY_CHANNELUP); break;
1139dde5845aSJiri Kosina case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
11401c1e40b5SFlorian Festi case 0x0a0: map_key_clear(KEY_VCR2); break;
11411c1e40b5SFlorian Festi
1142dde5845aSJiri Kosina case 0x0b0: map_key_clear(KEY_PLAY); break;
1143dde5845aSJiri Kosina case 0x0b1: map_key_clear(KEY_PAUSE); break;
1144dde5845aSJiri Kosina case 0x0b2: map_key_clear(KEY_RECORD); break;
1145dde5845aSJiri Kosina case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
1146dde5845aSJiri Kosina case 0x0b4: map_key_clear(KEY_REWIND); break;
1147dde5845aSJiri Kosina case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
1148dde5845aSJiri Kosina case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
1149dde5845aSJiri Kosina case 0x0b7: map_key_clear(KEY_STOPCD); break;
1150dde5845aSJiri Kosina case 0x0b8: map_key_clear(KEY_EJECTCD); break;
1151094403ceSDmitry Torokhov case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break;
1152437f3b19SJarod Wilson case 0x0b9: map_key_clear(KEY_SHUFFLE); break;
1153437f3b19SJarod Wilson case 0x0bf: map_key_clear(KEY_SLOW); break;
11541c1e40b5SFlorian Festi
1155dde5845aSJiri Kosina case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
1156f362e690SOlivier Gay case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break;
11577b229b13SDmitry Torokhov
1158bfa26ba3SWilliam Mahon case 0x0d8: map_key_clear(KEY_DICTATE); break;
11597b229b13SDmitry Torokhov case 0x0d9: map_key_clear(KEY_EMOJI_PICKER); break;
11607b229b13SDmitry Torokhov
1161dde5845aSJiri Kosina case 0x0e0: map_abs_clear(ABS_VOLUME); break;
1162dde5845aSJiri Kosina case 0x0e2: map_key_clear(KEY_MUTE); break;
1163dde5845aSJiri Kosina case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
1164dde5845aSJiri Kosina case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
1165dde5845aSJiri Kosina case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
1166437f3b19SJarod Wilson case 0x0f5: map_key_clear(KEY_SLOW); break;
116792d9e6e6SJiri Kosina
1168f362e690SOlivier Gay case 0x181: map_key_clear(KEY_BUTTONCONFIG); break;
11693cc5f916SKhelben Blackstaff case 0x182: map_key_clear(KEY_BOOKMARKS); break;
1170dde5845aSJiri Kosina case 0x183: map_key_clear(KEY_CONFIG); break;
11711c1e40b5SFlorian Festi case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
11721c1e40b5SFlorian Festi case 0x185: map_key_clear(KEY_EDITOR); break;
11731c1e40b5SFlorian Festi case 0x186: map_key_clear(KEY_SPREADSHEET); break;
11741c1e40b5SFlorian Festi case 0x187: map_key_clear(KEY_GRAPHICSEDITOR); break;
11751c1e40b5SFlorian Festi case 0x188: map_key_clear(KEY_PRESENTATION); break;
11761c1e40b5SFlorian Festi case 0x189: map_key_clear(KEY_DATABASE); break;
1177dde5845aSJiri Kosina case 0x18a: map_key_clear(KEY_MAIL); break;
11781c1e40b5SFlorian Festi case 0x18b: map_key_clear(KEY_NEWS); break;
11791c1e40b5SFlorian Festi case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
11801c1e40b5SFlorian Festi case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
11811c1e40b5SFlorian Festi case 0x18e: map_key_clear(KEY_CALENDAR); break;
1182f362e690SOlivier Gay case 0x18f: map_key_clear(KEY_TASKMANAGER); break;
1183f362e690SOlivier Gay case 0x190: map_key_clear(KEY_JOURNAL); break;
11841c1e40b5SFlorian Festi case 0x191: map_key_clear(KEY_FINANCE); break;
1185dde5845aSJiri Kosina case 0x192: map_key_clear(KEY_CALC); break;
1186437f3b19SJarod Wilson case 0x193: map_key_clear(KEY_PLAYER); break;
1187dde5845aSJiri Kosina case 0x194: map_key_clear(KEY_FILE); break;
11881c1e40b5SFlorian Festi case 0x196: map_key_clear(KEY_WWW); break;
11890690535dSLeo P White case 0x199: map_key_clear(KEY_CHAT); break;
11903cc5f916SKhelben Blackstaff case 0x19c: map_key_clear(KEY_LOGOFF); break;
11911c1e40b5SFlorian Festi case 0x19e: map_key_clear(KEY_COFFEE); break;
1192f362e690SOlivier Gay case 0x19f: map_key_clear(KEY_CONTROLPANEL); break;
1193f362e690SOlivier Gay case 0x1a2: map_key_clear(KEY_APPSELECT); break;
11945820e4d4SHans de Goede case 0x1a3: map_key_clear(KEY_NEXT); break;
11955820e4d4SHans de Goede case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
11961c1e40b5SFlorian Festi case 0x1a6: map_key_clear(KEY_HELP); break;
1197dde5845aSJiri Kosina case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
11981fe8736dSJiri Kosina case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
1199437f3b19SJarod Wilson case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
1200f362e690SOlivier Gay case 0x1b1: map_key_clear(KEY_SCREENSAVER); break;
12015820e4d4SHans de Goede case 0x1b4: map_key_clear(KEY_FILE); break;
1202437f3b19SJarod Wilson case 0x1b6: map_key_clear(KEY_IMAGES); break;
1203437f3b19SJarod Wilson case 0x1b7: map_key_clear(KEY_AUDIO); break;
1204437f3b19SJarod Wilson case 0x1b8: map_key_clear(KEY_VIDEO); break;
12051c1e40b5SFlorian Festi case 0x1bc: map_key_clear(KEY_MESSENGER); break;
12061c1e40b5SFlorian Festi case 0x1bd: map_key_clear(KEY_INFO); break;
1207ce856634SDmitry Torokhov case 0x1cb: map_key_clear(KEY_ASSISTANT); break;
1208dde5845aSJiri Kosina case 0x201: map_key_clear(KEY_NEW); break;
12091c1e40b5SFlorian Festi case 0x202: map_key_clear(KEY_OPEN); break;
12101c1e40b5SFlorian Festi case 0x203: map_key_clear(KEY_CLOSE); break;
12111c1e40b5SFlorian Festi case 0x204: map_key_clear(KEY_EXIT); break;
1212dde5845aSJiri Kosina case 0x207: map_key_clear(KEY_SAVE); break;
1213dde5845aSJiri Kosina case 0x208: map_key_clear(KEY_PRINT); break;
1214dde5845aSJiri Kosina case 0x209: map_key_clear(KEY_PROPS); break;
1215dde5845aSJiri Kosina case 0x21a: map_key_clear(KEY_UNDO); break;
1216dde5845aSJiri Kosina case 0x21b: map_key_clear(KEY_COPY); break;
1217dde5845aSJiri Kosina case 0x21c: map_key_clear(KEY_CUT); break;
1218dde5845aSJiri Kosina case 0x21d: map_key_clear(KEY_PASTE); break;
12195fce620cSHans de Goede case 0x21f: map_key_clear(KEY_FIND); break;
12205fce620cSHans de Goede case 0x221: map_key_clear(KEY_SEARCH); break;
12215fce620cSHans de Goede case 0x222: map_key_clear(KEY_GOTO); break;
1222dde5845aSJiri Kosina case 0x223: map_key_clear(KEY_HOMEPAGE); break;
1223dde5845aSJiri Kosina case 0x224: map_key_clear(KEY_BACK); break;
1224dde5845aSJiri Kosina case 0x225: map_key_clear(KEY_FORWARD); break;
1225dde5845aSJiri Kosina case 0x226: map_key_clear(KEY_STOP); break;
1226dde5845aSJiri Kosina case 0x227: map_key_clear(KEY_REFRESH); break;
1227dde5845aSJiri Kosina case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
12281c1e40b5SFlorian Festi case 0x22d: map_key_clear(KEY_ZOOMIN); break;
12291c1e40b5SFlorian Festi case 0x22e: map_key_clear(KEY_ZOOMOUT); break;
12301c1e40b5SFlorian Festi case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
1231afbbaa1bSDmitry Torokhov case 0x232: map_key_clear(KEY_FULL_SCREEN); break;
1232dde5845aSJiri Kosina case 0x233: map_key_clear(KEY_SCROLLUP); break;
1233dde5845aSJiri Kosina case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
12342dc702c9SPeter Hutterer case 0x238: /* AC Pan */
12352dc702c9SPeter Hutterer set_bit(REL_HWHEEL, input->relbit);
12362dc702c9SPeter Hutterer map_rel(REL_HWHEEL_HI_RES);
12372dc702c9SPeter Hutterer break;
1238437f3b19SJarod Wilson case 0x23d: map_key_clear(KEY_EDIT); break;
12391c1e40b5SFlorian Festi case 0x25f: map_key_clear(KEY_CANCEL); break;
1240437f3b19SJarod Wilson case 0x269: map_key_clear(KEY_INSERT); break;
1241437f3b19SJarod Wilson case 0x26a: map_key_clear(KEY_DELETE); break;
1242dde5845aSJiri Kosina case 0x279: map_key_clear(KEY_REDO); break;
12431c1e40b5SFlorian Festi
1244dde5845aSJiri Kosina case 0x289: map_key_clear(KEY_REPLY); break;
1245dde5845aSJiri Kosina case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
1246dde5845aSJiri Kosina case 0x28c: map_key_clear(KEY_SEND); break;
1247dde5845aSJiri Kosina
1248bd21d847SDmitry Torokhov case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT); break;
1249bd21d847SDmitry Torokhov
1250327b89f0SWilliam Mahon case 0x2a2: map_key_clear(KEY_ALL_APPLICATIONS); break;
1251327b89f0SWilliam Mahon
1252f974008fSOlivier Gay case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break;
1253f974008fSOlivier Gay case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break;
1254f974008fSOlivier Gay case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); break;
1255f974008fSOlivier Gay case 0x2ca: map_key_clear(KEY_KBDINPUTASSIST_NEXTGROUP); break;
1256f974008fSOlivier Gay case 0x2cb: map_key_clear(KEY_KBDINPUTASSIST_ACCEPT); break;
1257f974008fSOlivier Gay case 0x2cc: map_key_clear(KEY_KBDINPUTASSIST_CANCEL); break;
1258f974008fSOlivier Gay
125996dd8687SDmitry Torokhov case 0x29f: map_key_clear(KEY_SCALE); break;
126096dd8687SDmitry Torokhov
1261afdb5cceSHans de Goede default: map_key_clear(KEY_UNKNOWN);
1262dde5845aSJiri Kosina }
1263dde5845aSJiri Kosina break;
1264dde5845aSJiri Kosina
12654f5ca836SJeremy Fitzhardinge case HID_UP_GENDEVCTRLS:
1266581c4484SDmitry Torokhov switch (usage->hid) {
1267581c4484SDmitry Torokhov case HID_DC_BATTERYSTRENGTH:
12689de07a4eSJohn Chen hidinput_setup_battery(device, HID_INPUT_REPORT, field, false);
12699de07a4eSJohn Chen usage->type = EV_PWR;
12709de07a4eSJohn Chen return;
12719de07a4eSJohn Chen }
12729de07a4eSJohn Chen goto unknown;
12739de07a4eSJohn Chen
12749de07a4eSJohn Chen case HID_UP_BATTERY:
12759de07a4eSJohn Chen switch (usage->hid) {
12769de07a4eSJohn Chen case HID_BAT_ABSOLUTESTATEOFCHARGE:
12779de07a4eSJohn Chen hidinput_setup_battery(device, HID_INPUT_REPORT, field, true);
1278581c4484SDmitry Torokhov usage->type = EV_PWR;
1279505f394fSDmitry Torokhov return;
1280a608dc1cSJosé Expósito case HID_BAT_CHARGING:
1281a608dc1cSJosé Expósito usage->type = EV_PWR;
1282a608dc1cSJosé Expósito return;
1283581c4484SDmitry Torokhov }
12844f5ca836SJeremy Fitzhardinge goto unknown;
1285740b2f03Sfengqi case HID_UP_CAMERA:
1286740b2f03Sfengqi switch (usage->hid & HID_USAGE) {
1287740b2f03Sfengqi case 0x020:
1288740b2f03Sfengqi map_key_clear(KEY_CAMERA_FOCUS); break;
1289740b2f03Sfengqi case 0x021:
1290740b2f03Sfengqi map_key_clear(KEY_CAMERA); break;
1291740b2f03Sfengqi default:
1292740b2f03Sfengqi goto ignore;
1293740b2f03Sfengqi }
1294740b2f03Sfengqi break;
12954f5ca836SJeremy Fitzhardinge
1296dde5845aSJiri Kosina case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
1297dde5845aSJiri Kosina set_bit(EV_REP, input->evbit);
1298dde5845aSJiri Kosina switch (usage->hid & HID_USAGE) {
1299dde5845aSJiri Kosina case 0x021: map_key_clear(KEY_PRINT); break;
1300dde5845aSJiri Kosina case 0x070: map_key_clear(KEY_HP); break;
1301dde5845aSJiri Kosina case 0x071: map_key_clear(KEY_CAMERA); break;
1302dde5845aSJiri Kosina case 0x072: map_key_clear(KEY_SOUND); break;
1303dde5845aSJiri Kosina case 0x073: map_key_clear(KEY_QUESTION); break;
1304dde5845aSJiri Kosina case 0x080: map_key_clear(KEY_EMAIL); break;
1305dde5845aSJiri Kosina case 0x081: map_key_clear(KEY_CHAT); break;
1306dde5845aSJiri Kosina case 0x082: map_key_clear(KEY_SEARCH); break;
1307dde5845aSJiri Kosina case 0x083: map_key_clear(KEY_CONNECT); break;
1308dde5845aSJiri Kosina case 0x084: map_key_clear(KEY_FINANCE); break;
1309dde5845aSJiri Kosina case 0x085: map_key_clear(KEY_SPORT); break;
1310dde5845aSJiri Kosina case 0x086: map_key_clear(KEY_SHOP); break;
1311dde5845aSJiri Kosina default: goto ignore;
1312dde5845aSJiri Kosina }
1313dde5845aSJiri Kosina break;
1314dde5845aSJiri Kosina
1315929578abSKeng-Yu Lin case HID_UP_HPVENDOR2:
1316929578abSKeng-Yu Lin set_bit(EV_REP, input->evbit);
1317929578abSKeng-Yu Lin switch (usage->hid & HID_USAGE) {
131808fc9473SAceLan Kao case 0x001: map_key_clear(KEY_MICMUTE); break;
1319929578abSKeng-Yu Lin case 0x003: map_key_clear(KEY_BRIGHTNESSDOWN); break;
1320929578abSKeng-Yu Lin case 0x004: map_key_clear(KEY_BRIGHTNESSUP); break;
1321929578abSKeng-Yu Lin default: goto ignore;
1322929578abSKeng-Yu Lin }
1323929578abSKeng-Yu Lin break;
1324929578abSKeng-Yu Lin
1325dde5845aSJiri Kosina case HID_UP_MSVENDOR:
13263c684c8cSJan Kiszka goto ignore;
1327dde5845aSJiri Kosina
132881e1a875SMichel Daenzer case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
1329dde5845aSJiri Kosina set_bit(EV_REP, input->evbit);
13308c19a515SJiri Slaby goto ignore;
1331dde5845aSJiri Kosina
133292d9e6e6SJiri Kosina case HID_UP_LOGIVENDOR:
1333b466c1ddSSimon Wood /* intentional fallback */
1334b466c1ddSSimon Wood case HID_UP_LOGIVENDOR2:
1335b466c1ddSSimon Wood /* intentional fallback */
1336b466c1ddSSimon Wood case HID_UP_LOGIVENDOR3:
133710bd065fSJiri Kosina goto ignore;
1338dde5845aSJiri Kosina
1339dde5845aSJiri Kosina case HID_UP_PID:
1340dde5845aSJiri Kosina switch (usage->hid & HID_USAGE) {
1341dde5845aSJiri Kosina case 0xa4: map_key_clear(BTN_DEAD); break;
1342dde5845aSJiri Kosina default: goto ignore;
1343dde5845aSJiri Kosina }
1344dde5845aSJiri Kosina break;
1345dde5845aSJiri Kosina
1346dde5845aSJiri Kosina default:
1347dde5845aSJiri Kosina unknown:
1348dde5845aSJiri Kosina if (field->report_size == 1) {
1349dde5845aSJiri Kosina if (field->report->type == HID_OUTPUT_REPORT) {
1350dde5845aSJiri Kosina map_led(LED_MISC);
1351dde5845aSJiri Kosina break;
1352dde5845aSJiri Kosina }
1353dde5845aSJiri Kosina map_key(BTN_MISC);
1354dde5845aSJiri Kosina break;
1355dde5845aSJiri Kosina }
1356dde5845aSJiri Kosina if (field->flags & HID_MAIN_ITEM_RELATIVE) {
1357dde5845aSJiri Kosina map_rel(REL_MISC);
1358dde5845aSJiri Kosina break;
1359dde5845aSJiri Kosina }
1360dde5845aSJiri Kosina map_abs(ABS_MISC);
1361dde5845aSJiri Kosina break;
1362dde5845aSJiri Kosina }
1363dde5845aSJiri Kosina
136410bd065fSJiri Kosina mapped:
136535556bedSMarc Zyngier /* Mapping failed, bail out */
136635556bedSMarc Zyngier if (!bit)
136735556bedSMarc Zyngier return;
136835556bedSMarc Zyngier
13694f388217SDmitry Torokhov if (device->driver->input_mapped &&
13704f388217SDmitry Torokhov device->driver->input_mapped(device, hidinput, field, usage,
13714f388217SDmitry Torokhov &bit, &max) < 0) {
13724f388217SDmitry Torokhov /*
13734f388217SDmitry Torokhov * The driver indicated that no further generic handling
13744f388217SDmitry Torokhov * of the usage is desired.
13754f388217SDmitry Torokhov */
13764f388217SDmitry Torokhov return;
13774f388217SDmitry Torokhov }
1378c500c971SJiri Slaby
1379dde5845aSJiri Kosina set_bit(usage->type, input->evbit);
1380dde5845aSJiri Kosina
1381190d7f02SBenjamin Tissoires /*
1382190d7f02SBenjamin Tissoires * This part is *really* controversial:
1383190d7f02SBenjamin Tissoires * - HID aims at being generic so we should do our best to export
1384190d7f02SBenjamin Tissoires * all incoming events
1385190d7f02SBenjamin Tissoires * - HID describes what events are, so there is no reason for ABS_X
1386190d7f02SBenjamin Tissoires * to be mapped to ABS_Y
1387190d7f02SBenjamin Tissoires * - HID is using *_MISC+N as a default value, but nothing prevents
1388190d7f02SBenjamin Tissoires * *_MISC+N to overwrite a legitimate even, which confuses userspace
1389190d7f02SBenjamin Tissoires * (for instance ABS_MISC + 7 is ABS_MT_SLOT, which has a different
1390190d7f02SBenjamin Tissoires * processing)
1391190d7f02SBenjamin Tissoires *
1392190d7f02SBenjamin Tissoires * If devices still want to use this (at their own risk), they will
1393190d7f02SBenjamin Tissoires * have to use the quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE, but
1394190d7f02SBenjamin Tissoires * the default should be a reliable mapping.
1395190d7f02SBenjamin Tissoires */
1396190d7f02SBenjamin Tissoires while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
1397190d7f02SBenjamin Tissoires if (device->quirks & HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE) {
1398190d7f02SBenjamin Tissoires usage->code = find_next_zero_bit(bit,
1399190d7f02SBenjamin Tissoires max + 1,
1400190d7f02SBenjamin Tissoires usage->code);
1401190d7f02SBenjamin Tissoires } else {
1402190d7f02SBenjamin Tissoires device->status |= HID_STAT_DUP_DETECTED;
1403190d7f02SBenjamin Tissoires goto ignore;
1404190d7f02SBenjamin Tissoires }
1405190d7f02SBenjamin Tissoires }
1406dde5845aSJiri Kosina
1407dde5845aSJiri Kosina if (usage->code > max)
1408dde5845aSJiri Kosina goto ignore;
1409dde5845aSJiri Kosina
1410dde5845aSJiri Kosina if (usage->type == EV_ABS) {
1411dde5845aSJiri Kosina
1412dde5845aSJiri Kosina int a = field->logical_minimum;
1413dde5845aSJiri Kosina int b = field->logical_maximum;
1414dde5845aSJiri Kosina
1415dde5845aSJiri Kosina if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
1416dde5845aSJiri Kosina a = field->logical_minimum = 0;
1417dde5845aSJiri Kosina b = field->logical_maximum = 255;
1418dde5845aSJiri Kosina }
1419dde5845aSJiri Kosina
1420dde5845aSJiri Kosina if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
1421dde5845aSJiri Kosina input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
1422dde5845aSJiri Kosina else input_set_abs_params(input, usage->code, a, b, 0, 0);
1423dde5845aSJiri Kosina
14244ea6e4ffSNikolai Kondrashov input_abs_set_res(input, usage->code,
14254ea6e4ffSNikolai Kondrashov hidinput_calc_abs_res(field, usage->code));
14264ea6e4ffSNikolai Kondrashov
14276967b4d9SHenrik Rydberg /* use a larger default input buffer for MT devices */
14286967b4d9SHenrik Rydberg if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
14296967b4d9SHenrik Rydberg input_set_events_per_packet(input, 60);
1430dde5845aSJiri Kosina }
1431dde5845aSJiri Kosina
1432dde5845aSJiri Kosina if (usage->type == EV_ABS &&
1433dde5845aSJiri Kosina (usage->hat_min < usage->hat_max || usage->hat_dir)) {
1434dde5845aSJiri Kosina int i;
1435dde5845aSJiri Kosina for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
1436dde5845aSJiri Kosina input_set_abs_params(input, i, -1, 1, 0, 0);
1437dde5845aSJiri Kosina set_bit(i, input->absbit);
1438dde5845aSJiri Kosina }
1439dde5845aSJiri Kosina if (usage->hat_dir && !field->dpad)
1440dde5845aSJiri Kosina field->dpad = usage->code;
1441dde5845aSJiri Kosina }
1442dde5845aSJiri Kosina
14432c1d8aeaSJiri Kosina /* for those devices which produce Consumer volume usage as relative,
14442c1d8aeaSJiri Kosina * we emulate pressing volumeup/volumedown appropriate number of times
14452c1d8aeaSJiri Kosina * in hidinput_hid_event()
14462c1d8aeaSJiri Kosina */
14472c1d8aeaSJiri Kosina if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
14482c1d8aeaSJiri Kosina (usage->code == ABS_VOLUME)) {
14492c1d8aeaSJiri Kosina set_bit(KEY_VOLUMEUP, input->keybit);
14502c1d8aeaSJiri Kosina set_bit(KEY_VOLUMEDOWN, input->keybit);
14512c1d8aeaSJiri Kosina }
14522c1d8aeaSJiri Kosina
1453c01d50d1SJiri Kosina if (usage->type == EV_KEY) {
1454c01d50d1SJiri Kosina set_bit(EV_MSC, input->evbit);
1455c01d50d1SJiri Kosina set_bit(MSC_SCAN, input->mscbit);
1456c01d50d1SJiri Kosina }
1457c01d50d1SJiri Kosina
1458dde5845aSJiri Kosina return;
1459a635f9ddSJiri Kosina
14604f388217SDmitry Torokhov ignore:
14614f388217SDmitry Torokhov usage->type = 0;
14624f388217SDmitry Torokhov usage->code = 0;
1463dde5845aSJiri Kosina }
1464dde5845aSJiri Kosina
hidinput_handle_scroll(struct hid_usage * usage,struct input_dev * input,__s32 value)14652dc702c9SPeter Hutterer static void hidinput_handle_scroll(struct hid_usage *usage,
14662dc702c9SPeter Hutterer struct input_dev *input,
14672dc702c9SPeter Hutterer __s32 value)
14682dc702c9SPeter Hutterer {
14692dc702c9SPeter Hutterer int code;
14702dc702c9SPeter Hutterer int hi_res, lo_res;
14712dc702c9SPeter Hutterer
14722dc702c9SPeter Hutterer if (value == 0)
14732dc702c9SPeter Hutterer return;
14742dc702c9SPeter Hutterer
14752dc702c9SPeter Hutterer if (usage->code == REL_WHEEL_HI_RES)
14762dc702c9SPeter Hutterer code = REL_WHEEL;
14772dc702c9SPeter Hutterer else
14782dc702c9SPeter Hutterer code = REL_HWHEEL;
14792dc702c9SPeter Hutterer
14802dc702c9SPeter Hutterer /*
14812dc702c9SPeter Hutterer * Windows reports one wheel click as value 120. Where a high-res
14822dc702c9SPeter Hutterer * scroll wheel is present, a fraction of 120 is reported instead.
14832dc702c9SPeter Hutterer * Our REL_WHEEL_HI_RES axis does the same because all HW must
14842dc702c9SPeter Hutterer * adhere to the 120 expectation.
14852dc702c9SPeter Hutterer */
14862dc702c9SPeter Hutterer hi_res = value * 120/usage->resolution_multiplier;
14872dc702c9SPeter Hutterer
14882dc702c9SPeter Hutterer usage->wheel_accumulated += hi_res;
14892dc702c9SPeter Hutterer lo_res = usage->wheel_accumulated/120;
14902dc702c9SPeter Hutterer if (lo_res)
14912dc702c9SPeter Hutterer usage->wheel_accumulated -= lo_res * 120;
14922dc702c9SPeter Hutterer
14932dc702c9SPeter Hutterer input_event(input, EV_REL, code, lo_res);
14942dc702c9SPeter Hutterer input_event(input, EV_REL, usage->code, hi_res);
14952dc702c9SPeter Hutterer }
14962dc702c9SPeter Hutterer
hid_report_release_tool(struct hid_report * report,struct input_dev * input,unsigned int tool)149787562fcdSBenjamin Tissoires static void hid_report_release_tool(struct hid_report *report, struct input_dev *input,
149887562fcdSBenjamin Tissoires unsigned int tool)
149987562fcdSBenjamin Tissoires {
150087562fcdSBenjamin Tissoires /* if the given tool is not currently reported, ignore */
150187562fcdSBenjamin Tissoires if (!test_bit(tool, input->key))
150287562fcdSBenjamin Tissoires return;
150387562fcdSBenjamin Tissoires
150487562fcdSBenjamin Tissoires /*
150587562fcdSBenjamin Tissoires * if the given tool was previously set, release it,
150687562fcdSBenjamin Tissoires * release any TOUCH and send an EV_SYN
150787562fcdSBenjamin Tissoires */
150887562fcdSBenjamin Tissoires input_event(input, EV_KEY, BTN_TOUCH, 0);
150987562fcdSBenjamin Tissoires input_event(input, EV_KEY, tool, 0);
151087562fcdSBenjamin Tissoires input_event(input, EV_SYN, SYN_REPORT, 0);
151187562fcdSBenjamin Tissoires
151287562fcdSBenjamin Tissoires report->tool = 0;
151387562fcdSBenjamin Tissoires }
151487562fcdSBenjamin Tissoires
hid_report_set_tool(struct hid_report * report,struct input_dev * input,unsigned int new_tool)151587562fcdSBenjamin Tissoires static void hid_report_set_tool(struct hid_report *report, struct input_dev *input,
151687562fcdSBenjamin Tissoires unsigned int new_tool)
151787562fcdSBenjamin Tissoires {
151887562fcdSBenjamin Tissoires if (report->tool != new_tool)
151987562fcdSBenjamin Tissoires hid_report_release_tool(report, input, report->tool);
152087562fcdSBenjamin Tissoires
152187562fcdSBenjamin Tissoires input_event(input, EV_KEY, new_tool, 1);
152287562fcdSBenjamin Tissoires report->tool = new_tool;
152387562fcdSBenjamin Tissoires }
152487562fcdSBenjamin Tissoires
hidinput_hid_event(struct hid_device * hid,struct hid_field * field,struct hid_usage * usage,__s32 value)1525dde5845aSJiri Kosina void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
1526dde5845aSJiri Kosina {
1527dde5845aSJiri Kosina struct input_dev *input;
152887562fcdSBenjamin Tissoires struct hid_report *report = field->report;
1529b4482a4bSAl Viro unsigned *quirks = &hid->quirks;
1530dde5845aSJiri Kosina
1531581c4484SDmitry Torokhov if (!usage->type)
1532581c4484SDmitry Torokhov return;
1533581c4484SDmitry Torokhov
1534581c4484SDmitry Torokhov if (usage->type == EV_PWR) {
1535a608dc1cSJosé Expósito bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
1536a608dc1cSJosé Expósito
1537a608dc1cSJosé Expósito if (!handled)
1538581c4484SDmitry Torokhov hidinput_update_battery(hid, value);
1539a608dc1cSJosé Expósito
1540581c4484SDmitry Torokhov return;
1541581c4484SDmitry Torokhov }
1542581c4484SDmitry Torokhov
1543dde5845aSJiri Kosina if (!field->hidinput)
1544dde5845aSJiri Kosina return;
1545dde5845aSJiri Kosina
1546dde5845aSJiri Kosina input = field->hidinput->input;
1547dde5845aSJiri Kosina
1548dde5845aSJiri Kosina if (usage->hat_min < usage->hat_max || usage->hat_dir) {
1549dde5845aSJiri Kosina int hat_dir = usage->hat_dir;
1550dde5845aSJiri Kosina if (!hat_dir)
1551dde5845aSJiri Kosina hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
1552dde5845aSJiri Kosina if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
1553dde5845aSJiri Kosina input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
1554dde5845aSJiri Kosina input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
1555dde5845aSJiri Kosina return;
1556dde5845aSJiri Kosina }
1557dde5845aSJiri Kosina
1558883e0e36SNikolai Kondrashov /*
1559883e0e36SNikolai Kondrashov * Ignore out-of-range values as per HID specification,
1560c3883fe0STomasz Kramkowski * section 5.10 and 6.2.25, when NULL state bit is present.
1561c3883fe0STomasz Kramkowski * When it's not, clamp the value to match Microsoft's input
1562c3883fe0STomasz Kramkowski * driver as mentioned in "Required HID usages for digitizers":
1563c3883fe0STomasz Kramkowski * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp
1564a688393bSJiri Kosina *
1565a688393bSJiri Kosina * The logical_minimum < logical_maximum check is done so that we
1566a688393bSJiri Kosina * don't unintentionally discard values sent by devices which
1567a688393bSJiri Kosina * don't specify logical min and max.
1568883e0e36SNikolai Kondrashov */
1569883e0e36SNikolai Kondrashov if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
1570187ccd6cSBenjamin Tissoires field->logical_minimum < field->logical_maximum) {
1571c3883fe0STomasz Kramkowski if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
1572883e0e36SNikolai Kondrashov (value < field->logical_minimum ||
1573883e0e36SNikolai Kondrashov value > field->logical_maximum)) {
15746da70669SJiri Kosina dbg_hid("Ignoring out-of-range value %x\n", value);
15756da70669SJiri Kosina return;
15766da70669SJiri Kosina }
1577c3883fe0STomasz Kramkowski value = clamp(value,
1578c3883fe0STomasz Kramkowski field->logical_minimum,
1579c3883fe0STomasz Kramkowski field->logical_maximum);
1580c3883fe0STomasz Kramkowski }
15816da70669SJiri Kosina
1582f2d4ddfaSBenjamin Tissoires switch (usage->hid) {
158387562fcdSBenjamin Tissoires case HID_DG_ERASER:
158487562fcdSBenjamin Tissoires report->tool_active |= !!value;
158587562fcdSBenjamin Tissoires
158687562fcdSBenjamin Tissoires /*
158787562fcdSBenjamin Tissoires * if eraser is set, we must enforce BTN_TOOL_RUBBER
158887562fcdSBenjamin Tissoires * to accommodate for devices not following the spec.
158987562fcdSBenjamin Tissoires */
159087562fcdSBenjamin Tissoires if (value)
159187562fcdSBenjamin Tissoires hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
159287562fcdSBenjamin Tissoires else if (report->tool != BTN_TOOL_RUBBER)
159387562fcdSBenjamin Tissoires /* value is off, tool is not rubber, ignore */
159487562fcdSBenjamin Tissoires return;
1595276e14e6SIllia Ostapyshyn else if (*quirks & HID_QUIRK_NOINVERT &&
1596276e14e6SIllia Ostapyshyn !test_bit(BTN_TOUCH, input->key)) {
1597276e14e6SIllia Ostapyshyn /*
1598276e14e6SIllia Ostapyshyn * There is no invert to release the tool, let hid_input
1599276e14e6SIllia Ostapyshyn * send BTN_TOUCH with scancode and release the tool after.
1600276e14e6SIllia Ostapyshyn */
1601276e14e6SIllia Ostapyshyn hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
1602276e14e6SIllia Ostapyshyn return;
1603276e14e6SIllia Ostapyshyn }
160487562fcdSBenjamin Tissoires
160587562fcdSBenjamin Tissoires /* let hid-input set BTN_TOUCH */
160687562fcdSBenjamin Tissoires break;
160787562fcdSBenjamin Tissoires
1608f2d4ddfaSBenjamin Tissoires case HID_DG_INVERT:
160987562fcdSBenjamin Tissoires report->tool_active |= !!value;
161087562fcdSBenjamin Tissoires
161187562fcdSBenjamin Tissoires /*
161287562fcdSBenjamin Tissoires * If invert is set, we store BTN_TOOL_RUBBER.
161387562fcdSBenjamin Tissoires */
161487562fcdSBenjamin Tissoires if (value)
161587562fcdSBenjamin Tissoires hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
161687562fcdSBenjamin Tissoires else if (!report->tool_active)
161787562fcdSBenjamin Tissoires /* tool_active not set means Invert and Eraser are not set */
161887562fcdSBenjamin Tissoires hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
161987562fcdSBenjamin Tissoires
162087562fcdSBenjamin Tissoires /* no further processing */
1621dde5845aSJiri Kosina return;
1622dde5845aSJiri Kosina
1623f2d4ddfaSBenjamin Tissoires case HID_DG_INRANGE:
162487562fcdSBenjamin Tissoires report->tool_active |= !!value;
162587562fcdSBenjamin Tissoires
162687562fcdSBenjamin Tissoires if (report->tool_active) {
162787562fcdSBenjamin Tissoires /*
162887562fcdSBenjamin Tissoires * if tool is not set but is marked as active,
162987562fcdSBenjamin Tissoires * assume ours
163087562fcdSBenjamin Tissoires */
163187562fcdSBenjamin Tissoires if (!report->tool)
16328db8be9cSBenjamin Tissoires report->tool = usage->code;
16338db8be9cSBenjamin Tissoires
16348db8be9cSBenjamin Tissoires /* drivers may have changed the value behind our back, resend it */
16358db8be9cSBenjamin Tissoires hid_report_set_tool(report, input, report->tool);
163687562fcdSBenjamin Tissoires } else {
163787562fcdSBenjamin Tissoires hid_report_release_tool(report, input, usage->code);
1638dde5845aSJiri Kosina }
163987562fcdSBenjamin Tissoires
164087562fcdSBenjamin Tissoires /* reset tool_active for the next event */
164187562fcdSBenjamin Tissoires report->tool_active = false;
164287562fcdSBenjamin Tissoires
164387562fcdSBenjamin Tissoires /* no further processing */
1644dde5845aSJiri Kosina return;
1645dde5845aSJiri Kosina
164687562fcdSBenjamin Tissoires case HID_DG_TIPSWITCH:
164787562fcdSBenjamin Tissoires report->tool_active |= !!value;
164887562fcdSBenjamin Tissoires
164987562fcdSBenjamin Tissoires /* if tool is set to RUBBER we should ignore the current value */
165087562fcdSBenjamin Tissoires if (report->tool == BTN_TOOL_RUBBER)
165187562fcdSBenjamin Tissoires return;
165287562fcdSBenjamin Tissoires
165387562fcdSBenjamin Tissoires break;
165487562fcdSBenjamin Tissoires
1655f2d4ddfaSBenjamin Tissoires case HID_DG_TIPPRESSURE:
1656f2d4ddfaSBenjamin Tissoires if (*quirks & HID_QUIRK_NOTOUCH) {
1657dde5845aSJiri Kosina int a = field->logical_minimum;
1658dde5845aSJiri Kosina int b = field->logical_maximum;
1659f2d4ddfaSBenjamin Tissoires
166087562fcdSBenjamin Tissoires if (value > a + ((b - a) >> 3)) {
166187562fcdSBenjamin Tissoires input_event(input, EV_KEY, BTN_TOUCH, 1);
166287562fcdSBenjamin Tissoires report->tool_active = true;
166387562fcdSBenjamin Tissoires }
1664dde5845aSJiri Kosina }
1665f2d4ddfaSBenjamin Tissoires break;
1666dde5845aSJiri Kosina
1667f2d4ddfaSBenjamin Tissoires case HID_UP_PID | 0x83UL: /* Simultaneous Effects Max */
1668dde5845aSJiri Kosina dbg_hid("Maximum Effects - %d\n",value);
1669dde5845aSJiri Kosina return;
1670dde5845aSJiri Kosina
1671f2d4ddfaSBenjamin Tissoires case HID_UP_PID | 0x7fUL:
1672dde5845aSJiri Kosina dbg_hid("PID Pool Report\n");
1673dde5845aSJiri Kosina return;
1674dde5845aSJiri Kosina }
1675dde5845aSJiri Kosina
1676f2d4ddfaSBenjamin Tissoires switch (usage->type) {
1677f2d4ddfaSBenjamin Tissoires case EV_KEY:
1678f2d4ddfaSBenjamin Tissoires if (usage->code == 0) /* Key 0 is "unassigned", not KEY_UNKNOWN */
1679dde5845aSJiri Kosina return;
1680f2d4ddfaSBenjamin Tissoires break;
1681dde5845aSJiri Kosina
1682f2d4ddfaSBenjamin Tissoires case EV_REL:
1683f2d4ddfaSBenjamin Tissoires if (usage->code == REL_WHEEL_HI_RES ||
1684f2d4ddfaSBenjamin Tissoires usage->code == REL_HWHEEL_HI_RES) {
1685dde5845aSJiri Kosina hidinput_handle_scroll(usage, input, value);
1686dde5845aSJiri Kosina return;
1687dde5845aSJiri Kosina }
1688f2d4ddfaSBenjamin Tissoires break;
1689dde5845aSJiri Kosina
1690f2d4ddfaSBenjamin Tissoires case EV_ABS:
1691f2d4ddfaSBenjamin Tissoires if ((field->flags & HID_MAIN_ITEM_RELATIVE) &&
1692f2d4ddfaSBenjamin Tissoires usage->code == ABS_VOLUME) {
16932c1d8aeaSJiri Kosina int count = abs(value);
16942c1d8aeaSJiri Kosina int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
16952c1d8aeaSJiri Kosina int i;
16962c1d8aeaSJiri Kosina
16972c1d8aeaSJiri Kosina for (i = 0; i < count; i++) {
16982c1d8aeaSJiri Kosina input_event(input, EV_KEY, direction, 1);
16992c1d8aeaSJiri Kosina input_sync(input);
17002c1d8aeaSJiri Kosina input_event(input, EV_KEY, direction, 0);
17012c1d8aeaSJiri Kosina input_sync(input);
17022c1d8aeaSJiri Kosina }
17032c1d8aeaSJiri Kosina return;
1704f2d4ddfaSBenjamin Tissoires
1705f2d4ddfaSBenjamin Tissoires } else if (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
1706f2d4ddfaSBenjamin Tissoires ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))
1707f2d4ddfaSBenjamin Tissoires value = field->logical_maximum - value;
1708f2d4ddfaSBenjamin Tissoires break;
17092c1d8aeaSJiri Kosina }
17102c1d8aeaSJiri Kosina
17116ce901ebSDavid Herrmann /*
17126ce901ebSDavid Herrmann * Ignore reports for absolute data if the data didn't change. This is
17136ce901ebSDavid Herrmann * not only an optimization but also fixes 'dead' key reports. Some
17146ce901ebSDavid Herrmann * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID
17156ce901ebSDavid Herrmann * 0x31 and 0x32) report multiple keys, even though a localized keyboard
17166ce901ebSDavid Herrmann * can only have one of them physically available. The 'dead' keys
17176ce901ebSDavid Herrmann * report constant 0. As all map to the same keycode, they'd confuse
17186ce901ebSDavid Herrmann * the input layer. If we filter the 'dead' keys on the HID level, we
17196ce901ebSDavid Herrmann * skip the keycode translation and only forward real events.
17206ce901ebSDavid Herrmann */
17216ce901ebSDavid Herrmann if (!(field->flags & (HID_MAIN_ITEM_RELATIVE |
17226ce901ebSDavid Herrmann HID_MAIN_ITEM_BUFFERED_BYTE)) &&
17238e7b3410SJiri Kosina (field->flags & HID_MAIN_ITEM_VARIABLE) &&
17246ce901ebSDavid Herrmann usage->usage_index < field->maxusage &&
17256ce901ebSDavid Herrmann value == field->value[usage->usage_index])
17266ce901ebSDavid Herrmann return;
17276ce901ebSDavid Herrmann
1728c01d50d1SJiri Kosina /* report the usage code as scancode if the key status has changed */
1729323ddaa8SJames C Boyd if (usage->type == EV_KEY &&
1730323ddaa8SJames C Boyd (!test_bit(usage->code, input->key)) == value)
1731c01d50d1SJiri Kosina input_event(input, EV_MSC, MSC_SCAN, usage->hid);
17321fe8736dSJiri Kosina
1733dde5845aSJiri Kosina input_event(input, usage->type, usage->code, value);
1734dde5845aSJiri Kosina
17353eb4351aSDmitry Torokhov if ((field->flags & HID_MAIN_ITEM_RELATIVE) &&
17363eb4351aSDmitry Torokhov usage->type == EV_KEY && value) {
17373eb4351aSDmitry Torokhov input_sync(input);
1738dde5845aSJiri Kosina input_event(input, usage->type, usage->code, 0);
1739dde5845aSJiri Kosina }
17403eb4351aSDmitry Torokhov }
1741dde5845aSJiri Kosina
hidinput_report_event(struct hid_device * hid,struct hid_report * report)1742dde5845aSJiri Kosina void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
1743dde5845aSJiri Kosina {
1744dde5845aSJiri Kosina struct hid_input *hidinput;
1745dde5845aSJiri Kosina
174624750f3eSHenrik Rydberg if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC)
174724750f3eSHenrik Rydberg return;
174824750f3eSHenrik Rydberg
1749dde5845aSJiri Kosina list_for_each_entry(hidinput, &hid->inputs, list)
1750dde5845aSJiri Kosina input_sync(hidinput->input);
1751dde5845aSJiri Kosina }
1752229695e5SJiri Kosina EXPORT_SYMBOL_GPL(hidinput_report_event);
1753dde5845aSJiri Kosina
hidinput_find_field(struct hid_device * hid,unsigned int type,unsigned int code,struct hid_field ** field)17545904a3f9SMika Westerberg static int hidinput_find_field(struct hid_device *hid, unsigned int type,
17555904a3f9SMika Westerberg unsigned int code, struct hid_field **field)
1756dde5845aSJiri Kosina {
1757dde5845aSJiri Kosina struct hid_report *report;
1758dde5845aSJiri Kosina int i, j;
1759dde5845aSJiri Kosina
1760dde5845aSJiri Kosina list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
1761dde5845aSJiri Kosina for (i = 0; i < report->maxfield; i++) {
1762dde5845aSJiri Kosina *field = report->field[i];
1763dde5845aSJiri Kosina for (j = 0; j < (*field)->maxusage; j++)
1764dde5845aSJiri Kosina if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
1765dde5845aSJiri Kosina return j;
1766dde5845aSJiri Kosina }
1767dde5845aSJiri Kosina }
1768dde5845aSJiri Kosina return -1;
1769dde5845aSJiri Kosina }
1770dde5845aSJiri Kosina
hidinput_get_led_field(struct hid_device * hid)17714371ea82SDaniel Kurtz struct hid_field *hidinput_get_led_field(struct hid_device *hid)
17724371ea82SDaniel Kurtz {
17734371ea82SDaniel Kurtz struct hid_report *report;
17744371ea82SDaniel Kurtz struct hid_field *field;
17754371ea82SDaniel Kurtz int i, j;
17764371ea82SDaniel Kurtz
17774371ea82SDaniel Kurtz list_for_each_entry(report,
17784371ea82SDaniel Kurtz &hid->report_enum[HID_OUTPUT_REPORT].report_list,
17794371ea82SDaniel Kurtz list) {
17804371ea82SDaniel Kurtz for (i = 0; i < report->maxfield; i++) {
17814371ea82SDaniel Kurtz field = report->field[i];
17824371ea82SDaniel Kurtz for (j = 0; j < field->maxusage; j++)
17834371ea82SDaniel Kurtz if (field->usage[j].type == EV_LED)
17844371ea82SDaniel Kurtz return field;
17854371ea82SDaniel Kurtz }
17864371ea82SDaniel Kurtz }
17874371ea82SDaniel Kurtz return NULL;
17884371ea82SDaniel Kurtz }
17894371ea82SDaniel Kurtz EXPORT_SYMBOL_GPL(hidinput_get_led_field);
17904371ea82SDaniel Kurtz
hidinput_count_leds(struct hid_device * hid)17914371ea82SDaniel Kurtz unsigned int hidinput_count_leds(struct hid_device *hid)
17924371ea82SDaniel Kurtz {
17934371ea82SDaniel Kurtz struct hid_report *report;
17944371ea82SDaniel Kurtz struct hid_field *field;
17954371ea82SDaniel Kurtz int i, j;
17964371ea82SDaniel Kurtz unsigned int count = 0;
17974371ea82SDaniel Kurtz
17984371ea82SDaniel Kurtz list_for_each_entry(report,
17994371ea82SDaniel Kurtz &hid->report_enum[HID_OUTPUT_REPORT].report_list,
18004371ea82SDaniel Kurtz list) {
18014371ea82SDaniel Kurtz for (i = 0; i < report->maxfield; i++) {
18024371ea82SDaniel Kurtz field = report->field[i];
18034371ea82SDaniel Kurtz for (j = 0; j < field->maxusage; j++)
18044371ea82SDaniel Kurtz if (field->usage[j].type == EV_LED &&
18054371ea82SDaniel Kurtz field->value[j])
18064371ea82SDaniel Kurtz count += 1;
18074371ea82SDaniel Kurtz }
18084371ea82SDaniel Kurtz }
18094371ea82SDaniel Kurtz return count;
18104371ea82SDaniel Kurtz }
18114371ea82SDaniel Kurtz EXPORT_SYMBOL_GPL(hidinput_count_leds);
18124371ea82SDaniel Kurtz
hidinput_led_worker(struct work_struct * work)181350c9d75bSDavid Herrmann static void hidinput_led_worker(struct work_struct *work)
181450c9d75bSDavid Herrmann {
181550c9d75bSDavid Herrmann struct hid_device *hid = container_of(work, struct hid_device,
181650c9d75bSDavid Herrmann led_work);
181750c9d75bSDavid Herrmann struct hid_field *field;
181850c9d75bSDavid Herrmann struct hid_report *report;
18193064a03bSAaron Ma int ret;
18203064a03bSAaron Ma u32 len;
182150c9d75bSDavid Herrmann __u8 *buf;
182250c9d75bSDavid Herrmann
182350c9d75bSDavid Herrmann field = hidinput_get_led_field(hid);
182450c9d75bSDavid Herrmann if (!field)
182550c9d75bSDavid Herrmann return;
182650c9d75bSDavid Herrmann
182750c9d75bSDavid Herrmann /*
182850c9d75bSDavid Herrmann * field->report is accessed unlocked regarding HID core. So there might
182950c9d75bSDavid Herrmann * be another incoming SET-LED request from user-space, which changes
183050c9d75bSDavid Herrmann * the LED state while we assemble our outgoing buffer. However, this
183150c9d75bSDavid Herrmann * doesn't matter as hid_output_report() correctly converts it into a
183250c9d75bSDavid Herrmann * boolean value no matter what information is currently set on the LED
183350c9d75bSDavid Herrmann * field (even garbage). So the remote device will always get a valid
183450c9d75bSDavid Herrmann * request.
183550c9d75bSDavid Herrmann * And in case we send a wrong value, a next led worker is spawned
183650c9d75bSDavid Herrmann * for every SET-LED request so the following worker will send the
183750c9d75bSDavid Herrmann * correct value, guaranteed!
183850c9d75bSDavid Herrmann */
183950c9d75bSDavid Herrmann
184050c9d75bSDavid Herrmann report = field->report;
184150c9d75bSDavid Herrmann
184250c9d75bSDavid Herrmann /* use custom SET_REPORT request if possible (asynchronous) */
184350c9d75bSDavid Herrmann if (hid->ll_driver->request)
184450c9d75bSDavid Herrmann return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT);
184550c9d75bSDavid Herrmann
184650c9d75bSDavid Herrmann /* fall back to generic raw-output-report */
1847dabb05c6SMathieu Magnaudet len = hid_report_len(report);
18489d27f432SBenjamin Tissoires buf = hid_alloc_report_buf(report, GFP_KERNEL);
184950c9d75bSDavid Herrmann if (!buf)
185050c9d75bSDavid Herrmann return;
185150c9d75bSDavid Herrmann
185250c9d75bSDavid Herrmann hid_output_report(report, buf);
185350c9d75bSDavid Herrmann /* synchronous output report */
18542ebaebcfSBenjamin Tissoires ret = hid_hw_output_report(hid, buf, len);
18552ebaebcfSBenjamin Tissoires if (ret == -ENOSYS)
18562ebaebcfSBenjamin Tissoires hid_hw_raw_request(hid, report->id, buf, len, HID_OUTPUT_REPORT,
18572ebaebcfSBenjamin Tissoires HID_REQ_SET_REPORT);
185850c9d75bSDavid Herrmann kfree(buf);
185950c9d75bSDavid Herrmann }
186050c9d75bSDavid Herrmann
hidinput_input_event(struct input_dev * dev,unsigned int type,unsigned int code,int value)186150c9d75bSDavid Herrmann static int hidinput_input_event(struct input_dev *dev, unsigned int type,
186250c9d75bSDavid Herrmann unsigned int code, int value)
186350c9d75bSDavid Herrmann {
186450c9d75bSDavid Herrmann struct hid_device *hid = input_get_drvdata(dev);
186550c9d75bSDavid Herrmann struct hid_field *field;
186650c9d75bSDavid Herrmann int offset;
186750c9d75bSDavid Herrmann
186850c9d75bSDavid Herrmann if (type == EV_FF)
186950c9d75bSDavid Herrmann return input_ff_event(dev, type, code, value);
187050c9d75bSDavid Herrmann
187150c9d75bSDavid Herrmann if (type != EV_LED)
187250c9d75bSDavid Herrmann return -1;
187350c9d75bSDavid Herrmann
187450c9d75bSDavid Herrmann if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
187550c9d75bSDavid Herrmann hid_warn(dev, "event field not found\n");
187650c9d75bSDavid Herrmann return -1;
187750c9d75bSDavid Herrmann }
187850c9d75bSDavid Herrmann
187950c9d75bSDavid Herrmann hid_set_field(field, offset, value);
188050c9d75bSDavid Herrmann
188150c9d75bSDavid Herrmann schedule_work(&hid->led_work);
188250c9d75bSDavid Herrmann return 0;
188350c9d75bSDavid Herrmann }
188450c9d75bSDavid Herrmann
hidinput_open(struct input_dev * dev)18857c379146SJiri Kosina static int hidinput_open(struct input_dev *dev)
18867c379146SJiri Kosina {
1887e0712985SDmitry Torokhov struct hid_device *hid = input_get_drvdata(dev);
1888e0712985SDmitry Torokhov
18895bea7660SDmitry Torokhov return hid_hw_open(hid);
18907c379146SJiri Kosina }
18917c379146SJiri Kosina
hidinput_close(struct input_dev * dev)18927c379146SJiri Kosina static void hidinput_close(struct input_dev *dev)
18937c379146SJiri Kosina {
1894e0712985SDmitry Torokhov struct hid_device *hid = input_get_drvdata(dev);
1895e0712985SDmitry Torokhov
18965bea7660SDmitry Torokhov hid_hw_close(hid);
18977c379146SJiri Kosina }
18987c379146SJiri Kosina
__hidinput_change_resolution_multipliers(struct hid_device * hid,struct hid_report * report,bool use_logical_max)1899d43c17eaSBenjamin Tissoires static bool __hidinput_change_resolution_multipliers(struct hid_device *hid,
1900d43c17eaSBenjamin Tissoires struct hid_report *report, bool use_logical_max)
19012dc702c9SPeter Hutterer {
19022dc702c9SPeter Hutterer struct hid_usage *usage;
1903d43c17eaSBenjamin Tissoires bool update_needed = false;
19041ad273d6SPeter Hutterer bool get_report_completed = false;
19052dc702c9SPeter Hutterer int i, j;
19062dc702c9SPeter Hutterer
1907d43c17eaSBenjamin Tissoires if (report->maxfield == 0)
1908d43c17eaSBenjamin Tissoires return false;
19092dc702c9SPeter Hutterer
1910d43c17eaSBenjamin Tissoires for (i = 0; i < report->maxfield; i++) {
1911d43c17eaSBenjamin Tissoires __s32 value = use_logical_max ?
1912d43c17eaSBenjamin Tissoires report->field[i]->logical_maximum :
1913d43c17eaSBenjamin Tissoires report->field[i]->logical_minimum;
19142dc702c9SPeter Hutterer
19152dc702c9SPeter Hutterer /* There is no good reason for a Resolution
19162dc702c9SPeter Hutterer * Multiplier to have a count other than 1.
19172dc702c9SPeter Hutterer * Ignore that case.
19182dc702c9SPeter Hutterer */
1919d43c17eaSBenjamin Tissoires if (report->field[i]->report_count != 1)
19202dc702c9SPeter Hutterer continue;
19212dc702c9SPeter Hutterer
1922d43c17eaSBenjamin Tissoires for (j = 0; j < report->field[i]->maxusage; j++) {
1923d43c17eaSBenjamin Tissoires usage = &report->field[i]->usage[j];
19242dc702c9SPeter Hutterer
19252dc702c9SPeter Hutterer if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
19262dc702c9SPeter Hutterer continue;
19272dc702c9SPeter Hutterer
19281ad273d6SPeter Hutterer /*
19291ad273d6SPeter Hutterer * If we have more than one feature within this
19301ad273d6SPeter Hutterer * report we need to fill in the bits from the
19311ad273d6SPeter Hutterer * others before we can overwrite the ones for the
19321ad273d6SPeter Hutterer * Resolution Multiplier.
19331ad273d6SPeter Hutterer *
19341ad273d6SPeter Hutterer * But if we're not allowed to read from the device,
19351ad273d6SPeter Hutterer * we just bail. Such a device should not exist
19361ad273d6SPeter Hutterer * anyway.
19371ad273d6SPeter Hutterer */
19381ad273d6SPeter Hutterer if (!get_report_completed && report->maxfield > 1) {
19391ad273d6SPeter Hutterer if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
19401ad273d6SPeter Hutterer return update_needed;
19411ad273d6SPeter Hutterer
19421ad273d6SPeter Hutterer hid_hw_request(hid, report, HID_REQ_GET_REPORT);
19431ad273d6SPeter Hutterer hid_hw_wait(hid);
19441ad273d6SPeter Hutterer get_report_completed = true;
19451ad273d6SPeter Hutterer }
19461ad273d6SPeter Hutterer
194739b3c3a5SBenjamin Tissoires report->field[i]->value[j] = value;
19482dc702c9SPeter Hutterer update_needed = true;
19492dc702c9SPeter Hutterer }
19502dc702c9SPeter Hutterer }
1951d43c17eaSBenjamin Tissoires
1952d43c17eaSBenjamin Tissoires return update_needed;
1953d43c17eaSBenjamin Tissoires }
1954d43c17eaSBenjamin Tissoires
hidinput_change_resolution_multipliers(struct hid_device * hid)1955d43c17eaSBenjamin Tissoires static void hidinput_change_resolution_multipliers(struct hid_device *hid)
1956d43c17eaSBenjamin Tissoires {
1957d43c17eaSBenjamin Tissoires struct hid_report_enum *rep_enum;
1958d43c17eaSBenjamin Tissoires struct hid_report *rep;
1959d43c17eaSBenjamin Tissoires int ret;
1960d43c17eaSBenjamin Tissoires
1961d43c17eaSBenjamin Tissoires rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
1962d43c17eaSBenjamin Tissoires list_for_each_entry(rep, &rep_enum->report_list, list) {
1963d43c17eaSBenjamin Tissoires bool update_needed = __hidinput_change_resolution_multipliers(hid,
1964d43c17eaSBenjamin Tissoires rep, true);
1965d43c17eaSBenjamin Tissoires
1966d43c17eaSBenjamin Tissoires if (update_needed) {
1967d43c17eaSBenjamin Tissoires ret = __hid_request(hid, rep, HID_REQ_SET_REPORT);
1968d43c17eaSBenjamin Tissoires if (ret) {
1969d43c17eaSBenjamin Tissoires __hidinput_change_resolution_multipliers(hid,
1970d43c17eaSBenjamin Tissoires rep, false);
1971d43c17eaSBenjamin Tissoires return;
1972d43c17eaSBenjamin Tissoires }
1973d43c17eaSBenjamin Tissoires }
19742dc702c9SPeter Hutterer }
19752dc702c9SPeter Hutterer
19762dc702c9SPeter Hutterer /* refresh our structs */
19772dc702c9SPeter Hutterer hid_setup_resolution_multiplier(hid);
19782dc702c9SPeter Hutterer }
19792dc702c9SPeter Hutterer
report_features(struct hid_device * hid)1980f635bd11SHenrik Rydberg static void report_features(struct hid_device *hid)
1981f635bd11SHenrik Rydberg {
1982f635bd11SHenrik Rydberg struct hid_driver *drv = hid->driver;
1983f635bd11SHenrik Rydberg struct hid_report_enum *rep_enum;
1984f635bd11SHenrik Rydberg struct hid_report *rep;
1985581c4484SDmitry Torokhov struct hid_usage *usage;
1986f635bd11SHenrik Rydberg int i, j;
1987f635bd11SHenrik Rydberg
1988f635bd11SHenrik Rydberg rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
1989f635bd11SHenrik Rydberg list_for_each_entry(rep, &rep_enum->report_list, list)
1990cc6b54aaSBenjamin Tissoires for (i = 0; i < rep->maxfield; i++) {
1991cc6b54aaSBenjamin Tissoires /* Ignore if report count is out of bounds. */
1992cc6b54aaSBenjamin Tissoires if (rep->field[i]->report_count < 1)
1993cc6b54aaSBenjamin Tissoires continue;
1994cc6b54aaSBenjamin Tissoires
1995c5a92aa3SDaniel Nicoletti for (j = 0; j < rep->field[i]->maxusage; j++) {
1996581c4484SDmitry Torokhov usage = &rep->field[i]->usage[j];
1997581c4484SDmitry Torokhov
1998c5a92aa3SDaniel Nicoletti /* Verify if Battery Strength feature is available */
1999581c4484SDmitry Torokhov if (usage->hid == HID_DC_BATTERYSTRENGTH)
2000581c4484SDmitry Torokhov hidinput_setup_battery(hid, HID_FEATURE_REPORT,
20019de07a4eSJohn Chen rep->field[i], false);
2002c5a92aa3SDaniel Nicoletti
2003c5a92aa3SDaniel Nicoletti if (drv->feature_mapping)
2004581c4484SDmitry Torokhov drv->feature_mapping(hid, rep->field[i], usage);
2005f635bd11SHenrik Rydberg }
2006c5a92aa3SDaniel Nicoletti }
2007cc6b54aaSBenjamin Tissoires }
2008f635bd11SHenrik Rydberg
hidinput_allocate(struct hid_device * hid,unsigned int application)2009c554bb04SBenjamin Tissoires static struct hid_input *hidinput_allocate(struct hid_device *hid,
2010c554bb04SBenjamin Tissoires unsigned int application)
2011ae751fa8SBenjamin Tissoires {
2012ae751fa8SBenjamin Tissoires struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
2013ae751fa8SBenjamin Tissoires struct input_dev *input_dev = input_allocate_device();
2014c554bb04SBenjamin Tissoires const char *suffix = NULL;
2015d7065620SBenjamin Tissoires size_t suffix_len, name_len;
2016c554bb04SBenjamin Tissoires
2017c554bb04SBenjamin Tissoires if (!hidinput || !input_dev)
2018c554bb04SBenjamin Tissoires goto fail;
2019c554bb04SBenjamin Tissoires
2020c554bb04SBenjamin Tissoires if ((hid->quirks & HID_QUIRK_INPUT_PER_APP) &&
2021c554bb04SBenjamin Tissoires hid->maxapplication > 1) {
2022c554bb04SBenjamin Tissoires switch (application) {
2023c554bb04SBenjamin Tissoires case HID_GD_KEYBOARD:
2024c554bb04SBenjamin Tissoires suffix = "Keyboard";
2025c554bb04SBenjamin Tissoires break;
2026c554bb04SBenjamin Tissoires case HID_GD_KEYPAD:
2027c554bb04SBenjamin Tissoires suffix = "Keypad";
2028c554bb04SBenjamin Tissoires break;
2029c554bb04SBenjamin Tissoires case HID_GD_MOUSE:
2030c554bb04SBenjamin Tissoires suffix = "Mouse";
2031c554bb04SBenjamin Tissoires break;
2032c0ee1d57SMika Westerberg case HID_DG_PEN:
2033c0ee1d57SMika Westerberg /*
2034c0ee1d57SMika Westerberg * yes, there is an issue here:
2035c0ee1d57SMika Westerberg * DG_PEN -> "Stylus"
2036c0ee1d57SMika Westerberg * DG_STYLUS -> "Pen"
2037c0ee1d57SMika Westerberg * But changing this now means users with config snippets
2038c0ee1d57SMika Westerberg * will have to change it and the test suite will not be happy.
2039c0ee1d57SMika Westerberg */
2040c0ee1d57SMika Westerberg suffix = "Stylus";
2041c0ee1d57SMika Westerberg break;
2042c554bb04SBenjamin Tissoires case HID_DG_STYLUS:
2043c554bb04SBenjamin Tissoires suffix = "Pen";
2044c554bb04SBenjamin Tissoires break;
2045c554bb04SBenjamin Tissoires case HID_DG_TOUCHSCREEN:
2046c554bb04SBenjamin Tissoires suffix = "Touchscreen";
2047c554bb04SBenjamin Tissoires break;
2048c554bb04SBenjamin Tissoires case HID_DG_TOUCHPAD:
2049c554bb04SBenjamin Tissoires suffix = "Touchpad";
2050c554bb04SBenjamin Tissoires break;
2051c554bb04SBenjamin Tissoires case HID_GD_SYSTEM_CONTROL:
2052c554bb04SBenjamin Tissoires suffix = "System Control";
2053c554bb04SBenjamin Tissoires break;
2054c554bb04SBenjamin Tissoires case HID_CP_CONSUMER_CONTROL:
2055c554bb04SBenjamin Tissoires suffix = "Consumer Control";
2056c554bb04SBenjamin Tissoires break;
2057c554bb04SBenjamin Tissoires case HID_GD_WIRELESS_RADIO_CTLS:
2058c554bb04SBenjamin Tissoires suffix = "Wireless Radio Control";
2059c554bb04SBenjamin Tissoires break;
2060ba6b055eSBenjamin Tissoires case HID_GD_SYSTEM_MULTIAXIS:
2061ba6b055eSBenjamin Tissoires suffix = "System Multi Axis";
2062ba6b055eSBenjamin Tissoires break;
2063c554bb04SBenjamin Tissoires default:
2064c554bb04SBenjamin Tissoires break;
2065c554bb04SBenjamin Tissoires }
2066c554bb04SBenjamin Tissoires }
2067c554bb04SBenjamin Tissoires
2068c554bb04SBenjamin Tissoires if (suffix) {
2069d7065620SBenjamin Tissoires name_len = strlen(hid->name);
2070d7065620SBenjamin Tissoires suffix_len = strlen(suffix);
2071d7065620SBenjamin Tissoires if ((name_len < suffix_len) ||
2072d7065620SBenjamin Tissoires strcmp(hid->name + name_len - suffix_len, suffix)) {
2073c554bb04SBenjamin Tissoires hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
2074c554bb04SBenjamin Tissoires hid->name, suffix);
2075c554bb04SBenjamin Tissoires if (!hidinput->name)
2076c554bb04SBenjamin Tissoires goto fail;
2077ae751fa8SBenjamin Tissoires }
2078d7065620SBenjamin Tissoires }
2079ae751fa8SBenjamin Tissoires
2080ae751fa8SBenjamin Tissoires input_set_drvdata(input_dev, hid);
208150c9d75bSDavid Herrmann input_dev->event = hidinput_input_event;
2082ae751fa8SBenjamin Tissoires input_dev->open = hidinput_open;
2083ae751fa8SBenjamin Tissoires input_dev->close = hidinput_close;
2084ae751fa8SBenjamin Tissoires input_dev->setkeycode = hidinput_setkeycode;
2085ae751fa8SBenjamin Tissoires input_dev->getkeycode = hidinput_getkeycode;
2086ae751fa8SBenjamin Tissoires
2087c554bb04SBenjamin Tissoires input_dev->name = hidinput->name ? hidinput->name : hid->name;
2088ae751fa8SBenjamin Tissoires input_dev->phys = hid->phys;
2089ae751fa8SBenjamin Tissoires input_dev->uniq = hid->uniq;
2090ae751fa8SBenjamin Tissoires input_dev->id.bustype = hid->bus;
2091ae751fa8SBenjamin Tissoires input_dev->id.vendor = hid->vendor;
2092ae751fa8SBenjamin Tissoires input_dev->id.product = hid->product;
2093ae751fa8SBenjamin Tissoires input_dev->id.version = hid->version;
2094bbe31754SBenjamin Tissoires input_dev->dev.parent = &hid->dev;
2095e1b63c01SBenjamin Tissoires
2096ae751fa8SBenjamin Tissoires hidinput->input = input_dev;
20970d6c3011SBenjamin Tissoires hidinput->application = application;
2098ae751fa8SBenjamin Tissoires list_add_tail(&hidinput->list, &hid->inputs);
2099ae751fa8SBenjamin Tissoires
2100e1b63c01SBenjamin Tissoires INIT_LIST_HEAD(&hidinput->reports);
2101e1b63c01SBenjamin Tissoires
2102ae751fa8SBenjamin Tissoires return hidinput;
2103c554bb04SBenjamin Tissoires
2104c554bb04SBenjamin Tissoires fail:
2105c554bb04SBenjamin Tissoires kfree(hidinput);
2106c554bb04SBenjamin Tissoires input_free_device(input_dev);
2107c554bb04SBenjamin Tissoires hid_err(hid, "Out of memory during hid input probe\n");
2108c554bb04SBenjamin Tissoires return NULL;
2109ae751fa8SBenjamin Tissoires }
2110ae751fa8SBenjamin Tissoires
hidinput_has_been_populated(struct hid_input * hidinput)21114f22decfSBenjamin Tissoires static bool hidinput_has_been_populated(struct hid_input *hidinput)
21124f22decfSBenjamin Tissoires {
21134f22decfSBenjamin Tissoires int i;
21144f22decfSBenjamin Tissoires unsigned long r = 0;
21154f22decfSBenjamin Tissoires
21164f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++)
21174f22decfSBenjamin Tissoires r |= hidinput->input->evbit[i];
21184f22decfSBenjamin Tissoires
21194f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++)
21204f22decfSBenjamin Tissoires r |= hidinput->input->keybit[i];
21214f22decfSBenjamin Tissoires
21224f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
21234f22decfSBenjamin Tissoires r |= hidinput->input->relbit[i];
21244f22decfSBenjamin Tissoires
21254f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
21264f22decfSBenjamin Tissoires r |= hidinput->input->absbit[i];
21274f22decfSBenjamin Tissoires
21284f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
21294f22decfSBenjamin Tissoires r |= hidinput->input->mscbit[i];
21304f22decfSBenjamin Tissoires
21314f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++)
21324f22decfSBenjamin Tissoires r |= hidinput->input->ledbit[i];
21334f22decfSBenjamin Tissoires
21344f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++)
21354f22decfSBenjamin Tissoires r |= hidinput->input->sndbit[i];
21364f22decfSBenjamin Tissoires
21374f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++)
21384f22decfSBenjamin Tissoires r |= hidinput->input->ffbit[i];
21394f22decfSBenjamin Tissoires
21404f22decfSBenjamin Tissoires for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++)
21414f22decfSBenjamin Tissoires r |= hidinput->input->swbit[i];
21424f22decfSBenjamin Tissoires
21434f22decfSBenjamin Tissoires return !!r;
21444f22decfSBenjamin Tissoires }
21454f22decfSBenjamin Tissoires
hidinput_cleanup_hidinput(struct hid_device * hid,struct hid_input * hidinput)21464f22decfSBenjamin Tissoires static void hidinput_cleanup_hidinput(struct hid_device *hid,
21474f22decfSBenjamin Tissoires struct hid_input *hidinput)
21484f22decfSBenjamin Tissoires {
21494f22decfSBenjamin Tissoires struct hid_report *report;
21504f22decfSBenjamin Tissoires int i, k;
21514f22decfSBenjamin Tissoires
21524f22decfSBenjamin Tissoires list_del(&hidinput->list);
21534f22decfSBenjamin Tissoires input_free_device(hidinput->input);
2154c554bb04SBenjamin Tissoires kfree(hidinput->name);
21554f22decfSBenjamin Tissoires
21564f22decfSBenjamin Tissoires for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
21574f22decfSBenjamin Tissoires if (k == HID_OUTPUT_REPORT &&
21584f22decfSBenjamin Tissoires hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
21594f22decfSBenjamin Tissoires continue;
21604f22decfSBenjamin Tissoires
21614f22decfSBenjamin Tissoires list_for_each_entry(report, &hid->report_enum[k].report_list,
21624f22decfSBenjamin Tissoires list) {
21634f22decfSBenjamin Tissoires
21644f22decfSBenjamin Tissoires for (i = 0; i < report->maxfield; i++)
21654f22decfSBenjamin Tissoires if (report->field[i]->hidinput == hidinput)
21664f22decfSBenjamin Tissoires report->field[i]->hidinput = NULL;
21674f22decfSBenjamin Tissoires }
21684f22decfSBenjamin Tissoires }
21694f22decfSBenjamin Tissoires
21704f22decfSBenjamin Tissoires kfree(hidinput);
21714f22decfSBenjamin Tissoires }
21724f22decfSBenjamin Tissoires
hidinput_match(struct hid_report * report)217372d19459SBenjamin Tissoires static struct hid_input *hidinput_match(struct hid_report *report)
217472d19459SBenjamin Tissoires {
217572d19459SBenjamin Tissoires struct hid_device *hid = report->device;
217672d19459SBenjamin Tissoires struct hid_input *hidinput;
217772d19459SBenjamin Tissoires
217872d19459SBenjamin Tissoires list_for_each_entry(hidinput, &hid->inputs, list) {
217972d19459SBenjamin Tissoires if (hidinput->report &&
218072d19459SBenjamin Tissoires hidinput->report->id == report->id)
218172d19459SBenjamin Tissoires return hidinput;
218272d19459SBenjamin Tissoires }
218372d19459SBenjamin Tissoires
218472d19459SBenjamin Tissoires return NULL;
218572d19459SBenjamin Tissoires }
218672d19459SBenjamin Tissoires
hidinput_match_application(struct hid_report * report)2187f07b3c1dSBenjamin Tissoires static struct hid_input *hidinput_match_application(struct hid_report *report)
2188f07b3c1dSBenjamin Tissoires {
2189f07b3c1dSBenjamin Tissoires struct hid_device *hid = report->device;
2190f07b3c1dSBenjamin Tissoires struct hid_input *hidinput;
2191f07b3c1dSBenjamin Tissoires
2192f07b3c1dSBenjamin Tissoires list_for_each_entry(hidinput, &hid->inputs, list) {
21930d6c3011SBenjamin Tissoires if (hidinput->application == report->application)
2194f07b3c1dSBenjamin Tissoires return hidinput;
21957c7d7ac7SDmitry Torokhov
21967c7d7ac7SDmitry Torokhov /*
21977c7d7ac7SDmitry Torokhov * Keep SystemControl and ConsumerControl applications together
21987c7d7ac7SDmitry Torokhov * with the main keyboard, if present.
21997c7d7ac7SDmitry Torokhov */
22007c7d7ac7SDmitry Torokhov if ((report->application == HID_GD_SYSTEM_CONTROL ||
22017c7d7ac7SDmitry Torokhov report->application == HID_CP_CONSUMER_CONTROL) &&
22027c7d7ac7SDmitry Torokhov hidinput->application == HID_GD_KEYBOARD) {
22037c7d7ac7SDmitry Torokhov return hidinput;
22047c7d7ac7SDmitry Torokhov }
2205f07b3c1dSBenjamin Tissoires }
2206f07b3c1dSBenjamin Tissoires
2207f07b3c1dSBenjamin Tissoires return NULL;
2208f07b3c1dSBenjamin Tissoires }
2209f07b3c1dSBenjamin Tissoires
hidinput_configure_usages(struct hid_input * hidinput,struct hid_report * report)221072d19459SBenjamin Tissoires static inline void hidinput_configure_usages(struct hid_input *hidinput,
221172d19459SBenjamin Tissoires struct hid_report *report)
221272d19459SBenjamin Tissoires {
22135c20000aSBenjamin Tissoires int i, j, k;
22145c20000aSBenjamin Tissoires int first_field_index = 0;
22155c20000aSBenjamin Tissoires int slot_collection_index = -1;
22165c20000aSBenjamin Tissoires int prev_collection_index = -1;
22175c20000aSBenjamin Tissoires unsigned int slot_idx = 0;
22185c20000aSBenjamin Tissoires struct hid_field *field;
22195c20000aSBenjamin Tissoires
22205c20000aSBenjamin Tissoires /*
22215c20000aSBenjamin Tissoires * First tag all the fields that are part of a slot,
22225c20000aSBenjamin Tissoires * a slot needs to have one Contact ID in the collection
22235c20000aSBenjamin Tissoires */
22245c20000aSBenjamin Tissoires for (i = 0; i < report->maxfield; i++) {
22255c20000aSBenjamin Tissoires field = report->field[i];
22265c20000aSBenjamin Tissoires
22275c20000aSBenjamin Tissoires /* ignore fields without usage */
22285c20000aSBenjamin Tissoires if (field->maxusage < 1)
22295c20000aSBenjamin Tissoires continue;
22305c20000aSBenjamin Tissoires
22315c20000aSBenjamin Tissoires /*
22325c20000aSBenjamin Tissoires * janitoring when collection_index changes
22335c20000aSBenjamin Tissoires */
22345c20000aSBenjamin Tissoires if (prev_collection_index != field->usage->collection_index) {
22355c20000aSBenjamin Tissoires prev_collection_index = field->usage->collection_index;
22365c20000aSBenjamin Tissoires first_field_index = i;
22375c20000aSBenjamin Tissoires }
22385c20000aSBenjamin Tissoires
22395c20000aSBenjamin Tissoires /*
22405c20000aSBenjamin Tissoires * if we already found a Contact ID in the collection,
22415c20000aSBenjamin Tissoires * tag and continue to the next.
22425c20000aSBenjamin Tissoires */
22435c20000aSBenjamin Tissoires if (slot_collection_index == field->usage->collection_index) {
22445c20000aSBenjamin Tissoires field->slot_idx = slot_idx;
22455c20000aSBenjamin Tissoires continue;
22465c20000aSBenjamin Tissoires }
22475c20000aSBenjamin Tissoires
22485c20000aSBenjamin Tissoires /* check if the current field has Contact ID */
22495c20000aSBenjamin Tissoires for (j = 0; j < field->maxusage; j++) {
22505c20000aSBenjamin Tissoires if (field->usage[j].hid == HID_DG_CONTACTID) {
22515c20000aSBenjamin Tissoires slot_collection_index = field->usage->collection_index;
22525c20000aSBenjamin Tissoires slot_idx++;
22535c20000aSBenjamin Tissoires
22545c20000aSBenjamin Tissoires /*
22555c20000aSBenjamin Tissoires * mark all previous fields and this one in the
22565c20000aSBenjamin Tissoires * current collection to be slotted.
22575c20000aSBenjamin Tissoires */
22585c20000aSBenjamin Tissoires for (k = first_field_index; k <= i; k++)
22595c20000aSBenjamin Tissoires report->field[k]->slot_idx = slot_idx;
22605c20000aSBenjamin Tissoires break;
22615c20000aSBenjamin Tissoires }
22625c20000aSBenjamin Tissoires }
22635c20000aSBenjamin Tissoires }
226472d19459SBenjamin Tissoires
226572d19459SBenjamin Tissoires for (i = 0; i < report->maxfield; i++)
226672d19459SBenjamin Tissoires for (j = 0; j < report->field[i]->maxusage; j++)
226772d19459SBenjamin Tissoires hidinput_configure_usage(hidinput, report->field[i],
2268048cddfdSBenjamin Tissoires report->field[i]->usage + j,
2269048cddfdSBenjamin Tissoires j);
227072d19459SBenjamin Tissoires }
227172d19459SBenjamin Tissoires
2272dde5845aSJiri Kosina /*
2273dde5845aSJiri Kosina * Register the input device; print a message.
2274dde5845aSJiri Kosina * Configure the input layer interface
2275dde5845aSJiri Kosina * Read all reports and initialize the absolute field values.
2276dde5845aSJiri Kosina */
2277dde5845aSJiri Kosina
hidinput_connect(struct hid_device * hid,unsigned int force)227893c10132SJiri Slaby int hidinput_connect(struct hid_device *hid, unsigned int force)
2279dde5845aSJiri Kosina {
22809ebf3d76SHenrik Rydberg struct hid_driver *drv = hid->driver;
2281dde5845aSJiri Kosina struct hid_report *report;
228272d19459SBenjamin Tissoires struct hid_input *next, *hidinput = NULL;
2283c554bb04SBenjamin Tissoires unsigned int application;
228472d19459SBenjamin Tissoires int i, k;
2285dde5845aSJiri Kosina
2286dde5845aSJiri Kosina INIT_LIST_HEAD(&hid->inputs);
228750c9d75bSDavid Herrmann INIT_WORK(&hid->led_work, hidinput_led_worker);
2288dde5845aSJiri Kosina
2289190d7f02SBenjamin Tissoires hid->status &= ~HID_STAT_DUP_DETECTED;
2290190d7f02SBenjamin Tissoires
229193c10132SJiri Slaby if (!force) {
229293c10132SJiri Slaby for (i = 0; i < hid->maxcollection; i++) {
229393c10132SJiri Slaby struct hid_collection *col = &hid->collection[i];
229493c10132SJiri Slaby if (col->type == HID_COLLECTION_APPLICATION ||
229593c10132SJiri Slaby col->type == HID_COLLECTION_PHYSICAL)
229693c10132SJiri Slaby if (IS_INPUT_APPLICATION(col->usage))
2297dde5845aSJiri Kosina break;
229893c10132SJiri Slaby }
2299dde5845aSJiri Kosina
230093c10132SJiri Slaby if (i == hid->maxcollection)
2301dde5845aSJiri Kosina return -1;
230293c10132SJiri Slaby }
2303dde5845aSJiri Kosina
2304f635bd11SHenrik Rydberg report_features(hid);
2305f635bd11SHenrik Rydberg
2306f635bd11SHenrik Rydberg for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
23070d2689c0SBenjamin Tissoires if (k == HID_OUTPUT_REPORT &&
23080d2689c0SBenjamin Tissoires hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
23090d2689c0SBenjamin Tissoires continue;
23105556feaeSAnssi Hannula
2311dde5845aSJiri Kosina list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
2312dde5845aSJiri Kosina
2313dde5845aSJiri Kosina if (!report->maxfield)
2314dde5845aSJiri Kosina continue;
2315dde5845aSJiri Kosina
2316c554bb04SBenjamin Tissoires application = report->application;
2317c554bb04SBenjamin Tissoires
231872d19459SBenjamin Tissoires /*
231972d19459SBenjamin Tissoires * Find the previous hidinput report attached
232072d19459SBenjamin Tissoires * to this report id.
232172d19459SBenjamin Tissoires */
232272d19459SBenjamin Tissoires if (hid->quirks & HID_QUIRK_MULTI_INPUT)
232372d19459SBenjamin Tissoires hidinput = hidinput_match(report);
2324f07b3c1dSBenjamin Tissoires else if (hid->maxapplication > 1 &&
2325f07b3c1dSBenjamin Tissoires (hid->quirks & HID_QUIRK_INPUT_PER_APP))
2326f07b3c1dSBenjamin Tissoires hidinput = hidinput_match_application(report);
232772d19459SBenjamin Tissoires
2328dde5845aSJiri Kosina if (!hidinput) {
2329c554bb04SBenjamin Tissoires hidinput = hidinput_allocate(hid, application);
2330ae751fa8SBenjamin Tissoires if (!hidinput)
2331368d290bSDirk Hohndel goto out_unwind;
2332dde5845aSJiri Kosina }
2333dde5845aSJiri Kosina
233472d19459SBenjamin Tissoires hidinput_configure_usages(hidinput, report);
2335dde5845aSJiri Kosina
233672d19459SBenjamin Tissoires if (hid->quirks & HID_QUIRK_MULTI_INPUT)
2337dde5845aSJiri Kosina hidinput->report = report;
2338e1b63c01SBenjamin Tissoires
2339e1b63c01SBenjamin Tissoires list_add_tail(&report->hidinput_list,
2340e1b63c01SBenjamin Tissoires &hidinput->reports);
2341dde5845aSJiri Kosina }
23420d2689c0SBenjamin Tissoires }
2343dde5845aSJiri Kosina
23442dc702c9SPeter Hutterer hidinput_change_resolution_multipliers(hid);
23452dc702c9SPeter Hutterer
234672d19459SBenjamin Tissoires list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
234739335d1cSBenjamin Tissoires if (drv->input_configured &&
234839335d1cSBenjamin Tissoires drv->input_configured(hid, hidinput))
234939335d1cSBenjamin Tissoires goto out_unwind;
235039335d1cSBenjamin Tissoires
235139335d1cSBenjamin Tissoires if (!hidinput_has_been_populated(hidinput)) {
23524f22decfSBenjamin Tissoires /* no need to register an input device not populated */
23534f22decfSBenjamin Tissoires hidinput_cleanup_hidinput(hid, hidinput);
235472d19459SBenjamin Tissoires continue;
235572d19459SBenjamin Tissoires }
235672d19459SBenjamin Tissoires
235772d19459SBenjamin Tissoires if (input_register_device(hidinput->input))
235872d19459SBenjamin Tissoires goto out_unwind;
235972d19459SBenjamin Tissoires hidinput->registered = true;
23604f22decfSBenjamin Tissoires }
23614f22decfSBenjamin Tissoires
23624f22decfSBenjamin Tissoires if (list_empty(&hid->inputs)) {
23634f22decfSBenjamin Tissoires hid_err(hid, "No inputs registered, leaving\n");
23644f22decfSBenjamin Tissoires goto out_unwind;
23654f22decfSBenjamin Tissoires }
23664f22decfSBenjamin Tissoires
2367190d7f02SBenjamin Tissoires if (hid->status & HID_STAT_DUP_DETECTED)
2368190d7f02SBenjamin Tissoires hid_dbg(hid,
2369190d7f02SBenjamin Tissoires "Some usages could not be mapped, please use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE if this is legitimate.\n");
2370190d7f02SBenjamin Tissoires
2371dde5845aSJiri Kosina return 0;
2372368d290bSDirk Hohndel
2373368d290bSDirk Hohndel out_unwind:
2374368d290bSDirk Hohndel /* unwind the ones we already registered */
2375368d290bSDirk Hohndel hidinput_disconnect(hid);
2376368d290bSDirk Hohndel
2377368d290bSDirk Hohndel return -1;
2378dde5845aSJiri Kosina }
2379229695e5SJiri Kosina EXPORT_SYMBOL_GPL(hidinput_connect);
2380dde5845aSJiri Kosina
hidinput_disconnect(struct hid_device * hid)2381dde5845aSJiri Kosina void hidinput_disconnect(struct hid_device *hid)
2382dde5845aSJiri Kosina {
2383dde5845aSJiri Kosina struct hid_input *hidinput, *next;
2384dde5845aSJiri Kosina
23854f5ca836SJeremy Fitzhardinge hidinput_cleanup_battery(hid);
23864f5ca836SJeremy Fitzhardinge
2387dde5845aSJiri Kosina list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
2388dde5845aSJiri Kosina list_del(&hidinput->list);
238972d19459SBenjamin Tissoires if (hidinput->registered)
2390dde5845aSJiri Kosina input_unregister_device(hidinput->input);
239172d19459SBenjamin Tissoires else
239272d19459SBenjamin Tissoires input_free_device(hidinput->input);
2393e38c0ac5SStefan Agner kfree(hidinput->name);
2394dde5845aSJiri Kosina kfree(hidinput);
2395dde5845aSJiri Kosina }
239650c9d75bSDavid Herrmann
239750c9d75bSDavid Herrmann /* led_work is spawned by input_dev callbacks, but doesn't access the
239850c9d75bSDavid Herrmann * parent input_dev at all. Once all input devices are removed, we
239950c9d75bSDavid Herrmann * know that led_work will never get restarted, so we can cancel it
240050c9d75bSDavid Herrmann * synchronously and are safe. */
240150c9d75bSDavid Herrmann cancel_work_sync(&hid->led_work);
2402dde5845aSJiri Kosina }
2403229695e5SJiri Kosina EXPORT_SYMBOL_GPL(hidinput_disconnect);
2404a608dc1cSJosé Expósito
2405a608dc1cSJosé Expósito #ifdef CONFIG_HID_KUNIT_TEST
2406a608dc1cSJosé Expósito #include "hid-input-test.c"
2407a608dc1cSJosé Expósito #endif
2408