xref: /openbmc/linux/drivers/hid/hid-input.c (revision 0f09e89e)
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