xref: /OK3568_Linux_fs/kernel/drivers/hid/wacom_wac.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * drivers/input/tablet/wacom_wac.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  USB Wacom tablet support - Wacom specific code
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "wacom_wac.h"
12*4882a593Smuzhiyun #include "wacom.h"
13*4882a593Smuzhiyun #include <linux/input/mt.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /* resolution for penabled devices */
16*4882a593Smuzhiyun #define WACOM_PL_RES		20
17*4882a593Smuzhiyun #define WACOM_PENPRTN_RES	40
18*4882a593Smuzhiyun #define WACOM_VOLITO_RES	50
19*4882a593Smuzhiyun #define WACOM_GRAPHIRE_RES	80
20*4882a593Smuzhiyun #define WACOM_INTUOS_RES	100
21*4882a593Smuzhiyun #define WACOM_INTUOS3_RES	200
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* Newer Cintiq and DTU have an offset between tablet and screen areas */
24*4882a593Smuzhiyun #define WACOM_DTU_OFFSET	200
25*4882a593Smuzhiyun #define WACOM_CINTIQ_OFFSET	400
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * Scale factor relating reported contact size to logical contact area.
29*4882a593Smuzhiyun  * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun #define WACOM_CONTACT_AREA_SCALE 2607
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun static bool touch_arbitration = 1;
34*4882a593Smuzhiyun module_param(touch_arbitration, bool, 0644);
35*4882a593Smuzhiyun MODULE_PARM_DESC(touch_arbitration, " on (Y) off (N)");
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun static void wacom_report_numbered_buttons(struct input_dev *input_dev,
38*4882a593Smuzhiyun 				int button_count, int mask);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static int wacom_numbered_button_to_key(int n);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
43*4882a593Smuzhiyun 			     int group);
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun  * Percent of battery capacity for Graphire.
46*4882a593Smuzhiyun  * 8th value means AC online and show 100% capacity.
47*4882a593Smuzhiyun  */
48*4882a593Smuzhiyun static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun  * Percent of battery capacity for Intuos4 WL, AC has a separate bit.
52*4882a593Smuzhiyun  */
53*4882a593Smuzhiyun static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
54*4882a593Smuzhiyun 
__wacom_notify_battery(struct wacom_battery * battery,int bat_status,int bat_capacity,bool bat_charging,bool bat_connected,bool ps_connected)55*4882a593Smuzhiyun static void __wacom_notify_battery(struct wacom_battery *battery,
56*4882a593Smuzhiyun 				   int bat_status, int bat_capacity,
57*4882a593Smuzhiyun 				   bool bat_charging, bool bat_connected,
58*4882a593Smuzhiyun 				   bool ps_connected)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	bool changed = battery->bat_status       != bat_status    ||
61*4882a593Smuzhiyun 		       battery->battery_capacity != bat_capacity  ||
62*4882a593Smuzhiyun 		       battery->bat_charging     != bat_charging  ||
63*4882a593Smuzhiyun 		       battery->bat_connected    != bat_connected ||
64*4882a593Smuzhiyun 		       battery->ps_connected     != ps_connected;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (changed) {
67*4882a593Smuzhiyun 		battery->bat_status = bat_status;
68*4882a593Smuzhiyun 		battery->battery_capacity = bat_capacity;
69*4882a593Smuzhiyun 		battery->bat_charging = bat_charging;
70*4882a593Smuzhiyun 		battery->bat_connected = bat_connected;
71*4882a593Smuzhiyun 		battery->ps_connected = ps_connected;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 		if (battery->battery)
74*4882a593Smuzhiyun 			power_supply_changed(battery->battery);
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
wacom_notify_battery(struct wacom_wac * wacom_wac,int bat_status,int bat_capacity,bool bat_charging,bool bat_connected,bool ps_connected)78*4882a593Smuzhiyun static void wacom_notify_battery(struct wacom_wac *wacom_wac,
79*4882a593Smuzhiyun 	int bat_status, int bat_capacity, bool bat_charging,
80*4882a593Smuzhiyun 	bool bat_connected, bool ps_connected)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	__wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
85*4882a593Smuzhiyun 			       bat_charging, bat_connected, ps_connected);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
wacom_penpartner_irq(struct wacom_wac * wacom)88*4882a593Smuzhiyun static int wacom_penpartner_irq(struct wacom_wac *wacom)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
91*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	switch (data[0]) {
94*4882a593Smuzhiyun 	case 1:
95*4882a593Smuzhiyun 		if (data[5] & 0x80) {
96*4882a593Smuzhiyun 			wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
97*4882a593Smuzhiyun 			wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
98*4882a593Smuzhiyun 			input_report_key(input, wacom->tool[0], 1);
99*4882a593Smuzhiyun 			input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
100*4882a593Smuzhiyun 			input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
101*4882a593Smuzhiyun 			input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
102*4882a593Smuzhiyun 			input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
103*4882a593Smuzhiyun 			input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127));
104*4882a593Smuzhiyun 			input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
105*4882a593Smuzhiyun 		} else {
106*4882a593Smuzhiyun 			input_report_key(input, wacom->tool[0], 0);
107*4882a593Smuzhiyun 			input_report_abs(input, ABS_MISC, 0); /* report tool id */
108*4882a593Smuzhiyun 			input_report_abs(input, ABS_PRESSURE, -1);
109*4882a593Smuzhiyun 			input_report_key(input, BTN_TOUCH, 0);
110*4882a593Smuzhiyun 		}
111*4882a593Smuzhiyun 		break;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	case 2:
114*4882a593Smuzhiyun 		input_report_key(input, BTN_TOOL_PEN, 1);
115*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
116*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
117*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
118*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
119*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
120*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
121*4882a593Smuzhiyun 		break;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	default:
124*4882a593Smuzhiyun 		dev_dbg(input->dev.parent,
125*4882a593Smuzhiyun 			"%s: received unknown report #%d\n", __func__, data[0]);
126*4882a593Smuzhiyun 		return 0;
127*4882a593Smuzhiyun         }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	return 1;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
wacom_pl_irq(struct wacom_wac * wacom)132*4882a593Smuzhiyun static int wacom_pl_irq(struct wacom_wac *wacom)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
135*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
136*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
137*4882a593Smuzhiyun 	int prox, pressure;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_PENABLED) {
140*4882a593Smuzhiyun 		dev_dbg(input->dev.parent,
141*4882a593Smuzhiyun 			"%s: received unknown report #%d\n", __func__, data[0]);
142*4882a593Smuzhiyun 		return 0;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	prox = data[1] & 0x40;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (!wacom->id[0]) {
148*4882a593Smuzhiyun 		if ((data[0] & 0x10) || (data[4] & 0x20)) {
149*4882a593Smuzhiyun 			wacom->tool[0] = BTN_TOOL_RUBBER;
150*4882a593Smuzhiyun 			wacom->id[0] = ERASER_DEVICE_ID;
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 		else {
153*4882a593Smuzhiyun 			wacom->tool[0] = BTN_TOOL_PEN;
154*4882a593Smuzhiyun 			wacom->id[0] = STYLUS_DEVICE_ID;
155*4882a593Smuzhiyun 		}
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	/* If the eraser is in prox, STYLUS2 is always set. If we
159*4882a593Smuzhiyun 	 * mis-detected the type and notice that STYLUS2 isn't set
160*4882a593Smuzhiyun 	 * then force the eraser out of prox and let the pen in.
161*4882a593Smuzhiyun 	 */
162*4882a593Smuzhiyun 	if (wacom->tool[0] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
163*4882a593Smuzhiyun 		input_report_key(input, BTN_TOOL_RUBBER, 0);
164*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, 0);
165*4882a593Smuzhiyun 		input_sync(input);
166*4882a593Smuzhiyun 		wacom->tool[0] = BTN_TOOL_PEN;
167*4882a593Smuzhiyun 		wacom->id[0] = STYLUS_DEVICE_ID;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (prox) {
171*4882a593Smuzhiyun 		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
172*4882a593Smuzhiyun 		if (features->pressure_max > 255)
173*4882a593Smuzhiyun 			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
174*4882a593Smuzhiyun 		pressure += (features->pressure_max + 1) / 2;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
177*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
178*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, pressure);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, data[4] & 0x08);
181*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, data[4] & 0x10);
182*4882a593Smuzhiyun 		/* Only allow the stylus2 button to be reported for the pen tool. */
183*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	if (!prox)
187*4882a593Smuzhiyun 		wacom->id[0] = 0;
188*4882a593Smuzhiyun 	input_report_key(input, wacom->tool[0], prox);
189*4882a593Smuzhiyun 	input_report_abs(input, ABS_MISC, wacom->id[0]);
190*4882a593Smuzhiyun 	return 1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
wacom_ptu_irq(struct wacom_wac * wacom)193*4882a593Smuzhiyun static int wacom_ptu_irq(struct wacom_wac *wacom)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
196*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_PENABLED) {
199*4882a593Smuzhiyun 		dev_dbg(input->dev.parent,
200*4882a593Smuzhiyun 			"%s: received unknown report #%d\n", __func__, data[0]);
201*4882a593Smuzhiyun 		return 0;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	if (data[1] & 0x04) {
205*4882a593Smuzhiyun 		input_report_key(input, BTN_TOOL_RUBBER, data[1] & 0x20);
206*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, data[1] & 0x08);
207*4882a593Smuzhiyun 		wacom->id[0] = ERASER_DEVICE_ID;
208*4882a593Smuzhiyun 	} else {
209*4882a593Smuzhiyun 		input_report_key(input, BTN_TOOL_PEN, data[1] & 0x20);
210*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, data[1] & 0x01);
211*4882a593Smuzhiyun 		wacom->id[0] = STYLUS_DEVICE_ID;
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun 	input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
214*4882a593Smuzhiyun 	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
215*4882a593Smuzhiyun 	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
216*4882a593Smuzhiyun 	input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6]));
217*4882a593Smuzhiyun 	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
218*4882a593Smuzhiyun 	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
219*4882a593Smuzhiyun 	return 1;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
wacom_dtu_irq(struct wacom_wac * wacom)222*4882a593Smuzhiyun static int wacom_dtu_irq(struct wacom_wac *wacom)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
225*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
226*4882a593Smuzhiyun 	int prox = data[1] & 0x20;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	dev_dbg(input->dev.parent,
229*4882a593Smuzhiyun 		"%s: received report #%d", __func__, data[0]);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if (prox) {
232*4882a593Smuzhiyun 		/* Going into proximity select tool */
233*4882a593Smuzhiyun 		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
234*4882a593Smuzhiyun 		if (wacom->tool[0] == BTN_TOOL_PEN)
235*4882a593Smuzhiyun 			wacom->id[0] = STYLUS_DEVICE_ID;
236*4882a593Smuzhiyun 		else
237*4882a593Smuzhiyun 			wacom->id[0] = ERASER_DEVICE_ID;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
240*4882a593Smuzhiyun 	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
241*4882a593Smuzhiyun 	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
242*4882a593Smuzhiyun 	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
243*4882a593Smuzhiyun 	input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x01) << 8) | data[6]);
244*4882a593Smuzhiyun 	input_report_key(input, BTN_TOUCH, data[1] & 0x05);
245*4882a593Smuzhiyun 	if (!prox) /* out-prox */
246*4882a593Smuzhiyun 		wacom->id[0] = 0;
247*4882a593Smuzhiyun 	input_report_key(input, wacom->tool[0], prox);
248*4882a593Smuzhiyun 	input_report_abs(input, ABS_MISC, wacom->id[0]);
249*4882a593Smuzhiyun 	return 1;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
wacom_dtus_irq(struct wacom_wac * wacom)252*4882a593Smuzhiyun static int wacom_dtus_irq(struct wacom_wac *wacom)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
255*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
256*4882a593Smuzhiyun 	unsigned short prox, pressure = 0;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) {
259*4882a593Smuzhiyun 		dev_dbg(input->dev.parent,
260*4882a593Smuzhiyun 			"%s: received unknown report #%d", __func__, data[0]);
261*4882a593Smuzhiyun 		return 0;
262*4882a593Smuzhiyun 	} else if (data[0] == WACOM_REPORT_DTUSPAD) {
263*4882a593Smuzhiyun 		input = wacom->pad_input;
264*4882a593Smuzhiyun 		input_report_key(input, BTN_0, (data[1] & 0x01));
265*4882a593Smuzhiyun 		input_report_key(input, BTN_1, (data[1] & 0x02));
266*4882a593Smuzhiyun 		input_report_key(input, BTN_2, (data[1] & 0x04));
267*4882a593Smuzhiyun 		input_report_key(input, BTN_3, (data[1] & 0x08));
268*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC,
269*4882a593Smuzhiyun 				 data[1] & 0x0f ? PAD_DEVICE_ID : 0);
270*4882a593Smuzhiyun 		return 1;
271*4882a593Smuzhiyun 	} else {
272*4882a593Smuzhiyun 		prox = data[1] & 0x80;
273*4882a593Smuzhiyun 		if (prox) {
274*4882a593Smuzhiyun 			switch ((data[1] >> 3) & 3) {
275*4882a593Smuzhiyun 			case 1: /* Rubber */
276*4882a593Smuzhiyun 				wacom->tool[0] = BTN_TOOL_RUBBER;
277*4882a593Smuzhiyun 				wacom->id[0] = ERASER_DEVICE_ID;
278*4882a593Smuzhiyun 				break;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 			case 2: /* Pen */
281*4882a593Smuzhiyun 				wacom->tool[0] = BTN_TOOL_PEN;
282*4882a593Smuzhiyun 				wacom->id[0] = STYLUS_DEVICE_ID;
283*4882a593Smuzhiyun 				break;
284*4882a593Smuzhiyun 			}
285*4882a593Smuzhiyun 		}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, data[1] & 0x20);
288*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, data[1] & 0x40);
289*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, get_unaligned_be16(&data[3]));
290*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5]));
291*4882a593Smuzhiyun 		pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff);
292*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, pressure);
293*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, pressure > 10);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		if (!prox) /* out-prox */
296*4882a593Smuzhiyun 			wacom->id[0] = 0;
297*4882a593Smuzhiyun 		input_report_key(input, wacom->tool[0], prox);
298*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, wacom->id[0]);
299*4882a593Smuzhiyun 		return 1;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
wacom_graphire_irq(struct wacom_wac * wacom)303*4882a593Smuzhiyun static int wacom_graphire_irq(struct wacom_wac *wacom)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
306*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
307*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
308*4882a593Smuzhiyun 	struct input_dev *pad_input = wacom->pad_input;
309*4882a593Smuzhiyun 	int battery_capacity, ps_connected;
310*4882a593Smuzhiyun 	int prox;
311*4882a593Smuzhiyun 	int rw = 0;
312*4882a593Smuzhiyun 	int retval = 0;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (features->type == GRAPHIRE_BT) {
315*4882a593Smuzhiyun 		if (data[0] != WACOM_REPORT_PENABLED_BT) {
316*4882a593Smuzhiyun 			dev_dbg(input->dev.parent,
317*4882a593Smuzhiyun 				"%s: received unknown report #%d\n", __func__,
318*4882a593Smuzhiyun 				data[0]);
319*4882a593Smuzhiyun 			goto exit;
320*4882a593Smuzhiyun 		}
321*4882a593Smuzhiyun 	} else if (data[0] != WACOM_REPORT_PENABLED) {
322*4882a593Smuzhiyun 		dev_dbg(input->dev.parent,
323*4882a593Smuzhiyun 			"%s: received unknown report #%d\n", __func__, data[0]);
324*4882a593Smuzhiyun 		goto exit;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	prox = data[1] & 0x80;
328*4882a593Smuzhiyun 	if (prox || wacom->id[0]) {
329*4882a593Smuzhiyun 		if (prox) {
330*4882a593Smuzhiyun 			switch ((data[1] >> 5) & 3) {
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 			case 0:	/* Pen */
333*4882a593Smuzhiyun 				wacom->tool[0] = BTN_TOOL_PEN;
334*4882a593Smuzhiyun 				wacom->id[0] = STYLUS_DEVICE_ID;
335*4882a593Smuzhiyun 				break;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 			case 1: /* Rubber */
338*4882a593Smuzhiyun 				wacom->tool[0] = BTN_TOOL_RUBBER;
339*4882a593Smuzhiyun 				wacom->id[0] = ERASER_DEVICE_ID;
340*4882a593Smuzhiyun 				break;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 			case 2: /* Mouse with wheel */
343*4882a593Smuzhiyun 				input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
344*4882a593Smuzhiyun 				fallthrough;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 			case 3: /* Mouse without wheel */
347*4882a593Smuzhiyun 				wacom->tool[0] = BTN_TOOL_MOUSE;
348*4882a593Smuzhiyun 				wacom->id[0] = CURSOR_DEVICE_ID;
349*4882a593Smuzhiyun 				break;
350*4882a593Smuzhiyun 			}
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
353*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
354*4882a593Smuzhiyun 		if (wacom->tool[0] != BTN_TOOL_MOUSE) {
355*4882a593Smuzhiyun 			if (features->type == GRAPHIRE_BT)
356*4882a593Smuzhiyun 				input_report_abs(input, ABS_PRESSURE, data[6] |
357*4882a593Smuzhiyun 					(((__u16) (data[1] & 0x08)) << 5));
358*4882a593Smuzhiyun 			else
359*4882a593Smuzhiyun 				input_report_abs(input, ABS_PRESSURE, data[6] |
360*4882a593Smuzhiyun 					((data[7] & 0x03) << 8));
361*4882a593Smuzhiyun 			input_report_key(input, BTN_TOUCH, data[1] & 0x01);
362*4882a593Smuzhiyun 			input_report_key(input, BTN_STYLUS, data[1] & 0x02);
363*4882a593Smuzhiyun 			input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
364*4882a593Smuzhiyun 		} else {
365*4882a593Smuzhiyun 			input_report_key(input, BTN_LEFT, data[1] & 0x01);
366*4882a593Smuzhiyun 			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
367*4882a593Smuzhiyun 			if (features->type == WACOM_G4 ||
368*4882a593Smuzhiyun 					features->type == WACOM_MO) {
369*4882a593Smuzhiyun 				input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f);
370*4882a593Smuzhiyun 				rw = (data[7] & 0x04) - (data[7] & 0x03);
371*4882a593Smuzhiyun 			} else if (features->type == GRAPHIRE_BT) {
372*4882a593Smuzhiyun 				/* Compute distance between mouse and tablet */
373*4882a593Smuzhiyun 				rw = 44 - (data[6] >> 2);
374*4882a593Smuzhiyun 				rw = clamp_val(rw, 0, 31);
375*4882a593Smuzhiyun 				input_report_abs(input, ABS_DISTANCE, rw);
376*4882a593Smuzhiyun 				if (((data[1] >> 5) & 3) == 2) {
377*4882a593Smuzhiyun 					/* Mouse with wheel */
378*4882a593Smuzhiyun 					input_report_key(input, BTN_MIDDLE,
379*4882a593Smuzhiyun 							data[1] & 0x04);
380*4882a593Smuzhiyun 					rw = (data[6] & 0x01) ? -1 :
381*4882a593Smuzhiyun 						(data[6] & 0x02) ? 1 : 0;
382*4882a593Smuzhiyun 				} else {
383*4882a593Smuzhiyun 					rw = 0;
384*4882a593Smuzhiyun 				}
385*4882a593Smuzhiyun 			} else {
386*4882a593Smuzhiyun 				input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f);
387*4882a593Smuzhiyun 				rw = -(signed char)data[6];
388*4882a593Smuzhiyun 			}
389*4882a593Smuzhiyun 			input_report_rel(input, REL_WHEEL, rw);
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 		if (!prox)
393*4882a593Smuzhiyun 			wacom->id[0] = 0;
394*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
395*4882a593Smuzhiyun 		input_report_key(input, wacom->tool[0], prox);
396*4882a593Smuzhiyun 		input_sync(input); /* sync last event */
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* send pad data */
400*4882a593Smuzhiyun 	switch (features->type) {
401*4882a593Smuzhiyun 	case WACOM_G4:
402*4882a593Smuzhiyun 		prox = data[7] & 0xf8;
403*4882a593Smuzhiyun 		if (prox || wacom->id[1]) {
404*4882a593Smuzhiyun 			wacom->id[1] = PAD_DEVICE_ID;
405*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_BACK, (data[7] & 0x40));
406*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x80));
407*4882a593Smuzhiyun 			rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
408*4882a593Smuzhiyun 			input_report_rel(pad_input, REL_WHEEL, rw);
409*4882a593Smuzhiyun 			if (!prox)
410*4882a593Smuzhiyun 				wacom->id[1] = 0;
411*4882a593Smuzhiyun 			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
412*4882a593Smuzhiyun 			retval = 1;
413*4882a593Smuzhiyun 		}
414*4882a593Smuzhiyun 		break;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	case WACOM_MO:
417*4882a593Smuzhiyun 		prox = (data[7] & 0xf8) || data[8];
418*4882a593Smuzhiyun 		if (prox || wacom->id[1]) {
419*4882a593Smuzhiyun 			wacom->id[1] = PAD_DEVICE_ID;
420*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_BACK, (data[7] & 0x08));
421*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_LEFT, (data[7] & 0x20));
422*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x10));
423*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_RIGHT, (data[7] & 0x40));
424*4882a593Smuzhiyun 			input_report_abs(pad_input, ABS_WHEEL, (data[8] & 0x7f));
425*4882a593Smuzhiyun 			if (!prox)
426*4882a593Smuzhiyun 				wacom->id[1] = 0;
427*4882a593Smuzhiyun 			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
428*4882a593Smuzhiyun 			retval = 1;
429*4882a593Smuzhiyun 		}
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	case GRAPHIRE_BT:
432*4882a593Smuzhiyun 		prox = data[7] & 0x03;
433*4882a593Smuzhiyun 		if (prox || wacom->id[1]) {
434*4882a593Smuzhiyun 			wacom->id[1] = PAD_DEVICE_ID;
435*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_0, (data[7] & 0x02));
436*4882a593Smuzhiyun 			input_report_key(pad_input, BTN_1, (data[7] & 0x01));
437*4882a593Smuzhiyun 			if (!prox)
438*4882a593Smuzhiyun 				wacom->id[1] = 0;
439*4882a593Smuzhiyun 			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
440*4882a593Smuzhiyun 			retval = 1;
441*4882a593Smuzhiyun 		}
442*4882a593Smuzhiyun 		break;
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* Store current battery capacity and power supply state */
446*4882a593Smuzhiyun 	if (features->type == GRAPHIRE_BT) {
447*4882a593Smuzhiyun 		rw = (data[7] >> 2 & 0x07);
448*4882a593Smuzhiyun 		battery_capacity = batcap_gr[rw];
449*4882a593Smuzhiyun 		ps_connected = rw == 7;
450*4882a593Smuzhiyun 		wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
451*4882a593Smuzhiyun 				     battery_capacity, ps_connected, 1,
452*4882a593Smuzhiyun 				     ps_connected);
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun exit:
455*4882a593Smuzhiyun 	return retval;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
wacom_intuos_schedule_prox_event(struct wacom_wac * wacom_wac)458*4882a593Smuzhiyun static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
461*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
462*4882a593Smuzhiyun 	struct hid_report *r;
463*4882a593Smuzhiyun 	struct hid_report_enum *re;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]);
466*4882a593Smuzhiyun 	if (features->type == INTUOSHT2)
467*4882a593Smuzhiyun 		r = re->report_id_hash[WACOM_REPORT_INTUOSHT2_ID];
468*4882a593Smuzhiyun 	else
469*4882a593Smuzhiyun 		r = re->report_id_hash[WACOM_REPORT_INTUOS_ID1];
470*4882a593Smuzhiyun 	if (r) {
471*4882a593Smuzhiyun 		hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
wacom_intuos_pad(struct wacom_wac * wacom)475*4882a593Smuzhiyun static int wacom_intuos_pad(struct wacom_wac *wacom)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
478*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
479*4882a593Smuzhiyun 	struct input_dev *input = wacom->pad_input;
480*4882a593Smuzhiyun 	int i;
481*4882a593Smuzhiyun 	int buttons = 0, nbuttons = features->numbered_buttons;
482*4882a593Smuzhiyun 	int keys = 0, nkeys = 0;
483*4882a593Smuzhiyun 	int ring1 = 0, ring2 = 0;
484*4882a593Smuzhiyun 	int strip1 = 0, strip2 = 0;
485*4882a593Smuzhiyun 	bool prox = false;
486*4882a593Smuzhiyun 	bool wrench = false, keyboard = false, mute_touch = false, menu = false,
487*4882a593Smuzhiyun 	     info = false;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/* pad packets. Works as a second tool and is always in prox */
490*4882a593Smuzhiyun 	if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
491*4882a593Smuzhiyun 	      data[0] == WACOM_REPORT_CINTIQPAD))
492*4882a593Smuzhiyun 		return 0;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
495*4882a593Smuzhiyun 		buttons = (data[3] << 1) | (data[2] & 0x01);
496*4882a593Smuzhiyun 		ring1 = data[1];
497*4882a593Smuzhiyun 	} else if (features->type == DTK) {
498*4882a593Smuzhiyun 		buttons = data[6];
499*4882a593Smuzhiyun 	} else if (features->type == WACOM_13HD) {
500*4882a593Smuzhiyun 		buttons = (data[4] << 1) | (data[3] & 0x01);
501*4882a593Smuzhiyun 	} else if (features->type == WACOM_24HD) {
502*4882a593Smuzhiyun 		buttons = (data[8] << 8) | data[6];
503*4882a593Smuzhiyun 		ring1 = data[1];
504*4882a593Smuzhiyun 		ring2 = data[2];
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 		/*
507*4882a593Smuzhiyun 		 * Three "buttons" are available on the 24HD which are
508*4882a593Smuzhiyun 		 * physically implemented as a touchstrip. Each button
509*4882a593Smuzhiyun 		 * is approximately 3 bits wide with a 2 bit spacing.
510*4882a593Smuzhiyun 		 * The raw touchstrip bits are stored at:
511*4882a593Smuzhiyun 		 *    ((data[3] & 0x1f) << 8) | data[4])
512*4882a593Smuzhiyun 		 */
513*4882a593Smuzhiyun 		nkeys = 3;
514*4882a593Smuzhiyun 		keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
515*4882a593Smuzhiyun 		       ((data[4] & 0xE0) ? 1<<1 : 0) |
516*4882a593Smuzhiyun 		       ((data[4] & 0x07) ? 1<<0 : 0);
517*4882a593Smuzhiyun 		keyboard = !!(data[4] & 0xE0);
518*4882a593Smuzhiyun 		info = !!(data[3] & 0x1C);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 		if (features->oPid) {
521*4882a593Smuzhiyun 			mute_touch = !!(data[4] & 0x07);
522*4882a593Smuzhiyun 			if (mute_touch)
523*4882a593Smuzhiyun 				wacom->shared->is_touch_on =
524*4882a593Smuzhiyun 					!wacom->shared->is_touch_on;
525*4882a593Smuzhiyun 		} else {
526*4882a593Smuzhiyun 			wrench = !!(data[4] & 0x07);
527*4882a593Smuzhiyun 		}
528*4882a593Smuzhiyun 	} else if (features->type == WACOM_27QHD) {
529*4882a593Smuzhiyun 		nkeys = 3;
530*4882a593Smuzhiyun 		keys = data[2] & 0x07;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 		wrench = !!(data[2] & 0x01);
533*4882a593Smuzhiyun 		keyboard = !!(data[2] & 0x02);
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 		if (features->oPid) {
536*4882a593Smuzhiyun 			mute_touch = !!(data[2] & 0x04);
537*4882a593Smuzhiyun 			if (mute_touch)
538*4882a593Smuzhiyun 				wacom->shared->is_touch_on =
539*4882a593Smuzhiyun 					!wacom->shared->is_touch_on;
540*4882a593Smuzhiyun 		} else {
541*4882a593Smuzhiyun 			menu = !!(data[2] & 0x04);
542*4882a593Smuzhiyun 		}
543*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
544*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
545*4882a593Smuzhiyun 		input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
546*4882a593Smuzhiyun 	} else if (features->type == CINTIQ_HYBRID) {
547*4882a593Smuzhiyun 		/*
548*4882a593Smuzhiyun 		 * Do not send hardware buttons under Android. They
549*4882a593Smuzhiyun 		 * are already sent to the system through GPIO (and
550*4882a593Smuzhiyun 		 * have different meaning).
551*4882a593Smuzhiyun 		 *
552*4882a593Smuzhiyun 		 * d-pad right  -> data[4] & 0x10
553*4882a593Smuzhiyun 		 * d-pad up     -> data[4] & 0x20
554*4882a593Smuzhiyun 		 * d-pad left   -> data[4] & 0x40
555*4882a593Smuzhiyun 		 * d-pad down   -> data[4] & 0x80
556*4882a593Smuzhiyun 		 * d-pad center -> data[3] & 0x01
557*4882a593Smuzhiyun 		 */
558*4882a593Smuzhiyun 		buttons = (data[4] << 1) | (data[3] & 0x01);
559*4882a593Smuzhiyun 	} else if (features->type == CINTIQ_COMPANION_2) {
560*4882a593Smuzhiyun 		/* d-pad right  -> data[2] & 0x10
561*4882a593Smuzhiyun 		 * d-pad up     -> data[2] & 0x20
562*4882a593Smuzhiyun 		 * d-pad left   -> data[2] & 0x40
563*4882a593Smuzhiyun 		 * d-pad down   -> data[2] & 0x80
564*4882a593Smuzhiyun 		 * d-pad center -> data[1] & 0x01
565*4882a593Smuzhiyun 		 */
566*4882a593Smuzhiyun 		buttons = ((data[2] >> 4) << 7) |
567*4882a593Smuzhiyun 		          ((data[1] & 0x04) << 4) |
568*4882a593Smuzhiyun 		          ((data[2] & 0x0F) << 2) |
569*4882a593Smuzhiyun 		          (data[1] & 0x03);
570*4882a593Smuzhiyun 	} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
571*4882a593Smuzhiyun 		/*
572*4882a593Smuzhiyun 		 * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
573*4882a593Smuzhiyun 		 * addition to the mechanical switch. Switch data is
574*4882a593Smuzhiyun 		 * stored in data[4], capacitive data in data[5].
575*4882a593Smuzhiyun 		 *
576*4882a593Smuzhiyun 		 * Touch ring mode switch (data[3]) has no capacitive sensor
577*4882a593Smuzhiyun 		 */
578*4882a593Smuzhiyun 		buttons = (data[4] << 1) | (data[3] & 0x01);
579*4882a593Smuzhiyun 		ring1 = data[2];
580*4882a593Smuzhiyun 	} else {
581*4882a593Smuzhiyun 		if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
582*4882a593Smuzhiyun 			buttons = (data[8] << 10) | ((data[7] & 0x01) << 9) |
583*4882a593Smuzhiyun 			          (data[6] << 1) | (data[5] & 0x01);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 			if (features->type == WACOM_22HD) {
586*4882a593Smuzhiyun 				nkeys = 3;
587*4882a593Smuzhiyun 				keys = data[9] & 0x07;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 				info = !!(data[9] & 0x01);
590*4882a593Smuzhiyun 				wrench = !!(data[9] & 0x02);
591*4882a593Smuzhiyun 			}
592*4882a593Smuzhiyun 		} else {
593*4882a593Smuzhiyun 			buttons = ((data[6] & 0x10) << 5)  |
594*4882a593Smuzhiyun 			          ((data[5] & 0x10) << 4)  |
595*4882a593Smuzhiyun 			          ((data[6] & 0x0F) << 4)  |
596*4882a593Smuzhiyun 			          (data[5] & 0x0F);
597*4882a593Smuzhiyun 		}
598*4882a593Smuzhiyun 		strip1 = ((data[1] & 0x1f) << 8) | data[2];
599*4882a593Smuzhiyun 		strip2 = ((data[3] & 0x1f) << 8) | data[4];
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	prox = (buttons & ~(~0U << nbuttons)) | (keys & ~(~0U << nkeys)) |
603*4882a593Smuzhiyun 	       (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	wacom_report_numbered_buttons(input, nbuttons, buttons);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	for (i = 0; i < nkeys; i++)
608*4882a593Smuzhiyun 		input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	input_report_key(input, KEY_BUTTONCONFIG, wrench);
611*4882a593Smuzhiyun 	input_report_key(input, KEY_ONSCREEN_KEYBOARD, keyboard);
612*4882a593Smuzhiyun 	input_report_key(input, KEY_CONTROLPANEL, menu);
613*4882a593Smuzhiyun 	input_report_key(input, KEY_INFO, info);
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	if (wacom->shared && wacom->shared->touch_input) {
616*4882a593Smuzhiyun 		input_report_switch(wacom->shared->touch_input,
617*4882a593Smuzhiyun 				    SW_MUTE_DEVICE,
618*4882a593Smuzhiyun 				    !wacom->shared->is_touch_on);
619*4882a593Smuzhiyun 		input_sync(wacom->shared->touch_input);
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	input_report_abs(input, ABS_RX, strip1);
623*4882a593Smuzhiyun 	input_report_abs(input, ABS_RY, strip2);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	input_report_abs(input, ABS_WHEEL,    (ring1 & 0x80) ? (ring1 & 0x7f) : 0);
626*4882a593Smuzhiyun 	input_report_abs(input, ABS_THROTTLE, (ring2 & 0x80) ? (ring2 & 0x7f) : 0);
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	input_report_key(input, wacom->tool[1], prox ? 1 : 0);
629*4882a593Smuzhiyun 	input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	return 1;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
wacom_intuos_id_mangle(int tool_id)636*4882a593Smuzhiyun static int wacom_intuos_id_mangle(int tool_id)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun 	return (tool_id & ~0xFFF) << 4 | (tool_id & 0xFFF);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun 
wacom_is_art_pen(int tool_id)641*4882a593Smuzhiyun static bool wacom_is_art_pen(int tool_id)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	bool is_art_pen = false;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	switch (tool_id) {
646*4882a593Smuzhiyun 	case 0x885:	/* Intuos3 Marker Pen */
647*4882a593Smuzhiyun 	case 0x804:	/* Intuos4/5 13HD/24HD Marker Pen */
648*4882a593Smuzhiyun 	case 0x10804:	/* Intuos4/5 13HD/24HD Art Pen */
649*4882a593Smuzhiyun 		is_art_pen = true;
650*4882a593Smuzhiyun 		break;
651*4882a593Smuzhiyun 	}
652*4882a593Smuzhiyun 	return is_art_pen;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun 
wacom_intuos_get_tool_type(int tool_id)655*4882a593Smuzhiyun static int wacom_intuos_get_tool_type(int tool_id)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	int tool_type = BTN_TOOL_PEN;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	if (wacom_is_art_pen(tool_id))
660*4882a593Smuzhiyun 		return tool_type;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	switch (tool_id) {
663*4882a593Smuzhiyun 	case 0x812: /* Inking pen */
664*4882a593Smuzhiyun 	case 0x801: /* Intuos3 Inking pen */
665*4882a593Smuzhiyun 	case 0x12802: /* Intuos4/5 Inking Pen */
666*4882a593Smuzhiyun 	case 0x012:
667*4882a593Smuzhiyun 		tool_type = BTN_TOOL_PENCIL;
668*4882a593Smuzhiyun 		break;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	case 0x822: /* Pen */
671*4882a593Smuzhiyun 	case 0x842:
672*4882a593Smuzhiyun 	case 0x852:
673*4882a593Smuzhiyun 	case 0x823: /* Intuos3 Grip Pen */
674*4882a593Smuzhiyun 	case 0x813: /* Intuos3 Classic Pen */
675*4882a593Smuzhiyun 	case 0x802: /* Intuos4/5 13HD/24HD General Pen */
676*4882a593Smuzhiyun 	case 0x8e2: /* IntuosHT2 pen */
677*4882a593Smuzhiyun 	case 0x022:
678*4882a593Smuzhiyun 	case 0x10842: /* MobileStudio Pro Pro Pen slim */
679*4882a593Smuzhiyun 	case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */
680*4882a593Smuzhiyun 	case 0x16802: /* Cintiq 13HD Pro Pen */
681*4882a593Smuzhiyun 	case 0x18802: /* DTH2242 Pen */
682*4882a593Smuzhiyun 	case 0x10802: /* Intuos4/5 13HD/24HD General Pen */
683*4882a593Smuzhiyun 		tool_type = BTN_TOOL_PEN;
684*4882a593Smuzhiyun 		break;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	case 0x832: /* Stroke pen */
687*4882a593Smuzhiyun 	case 0x032:
688*4882a593Smuzhiyun 		tool_type = BTN_TOOL_BRUSH;
689*4882a593Smuzhiyun 		break;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	case 0x007: /* Mouse 4D and 2D */
692*4882a593Smuzhiyun 	case 0x09c:
693*4882a593Smuzhiyun 	case 0x094:
694*4882a593Smuzhiyun 	case 0x017: /* Intuos3 2D Mouse */
695*4882a593Smuzhiyun 	case 0x806: /* Intuos4 Mouse */
696*4882a593Smuzhiyun 		tool_type = BTN_TOOL_MOUSE;
697*4882a593Smuzhiyun 		break;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	case 0x096: /* Lens cursor */
700*4882a593Smuzhiyun 	case 0x097: /* Intuos3 Lens cursor */
701*4882a593Smuzhiyun 	case 0x006: /* Intuos4 Lens cursor */
702*4882a593Smuzhiyun 		tool_type = BTN_TOOL_LENS;
703*4882a593Smuzhiyun 		break;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	case 0x82a: /* Eraser */
706*4882a593Smuzhiyun 	case 0x84a:
707*4882a593Smuzhiyun 	case 0x85a:
708*4882a593Smuzhiyun 	case 0x91a:
709*4882a593Smuzhiyun 	case 0xd1a:
710*4882a593Smuzhiyun 	case 0x0fa:
711*4882a593Smuzhiyun 	case 0x82b: /* Intuos3 Grip Pen Eraser */
712*4882a593Smuzhiyun 	case 0x81b: /* Intuos3 Classic Pen Eraser */
713*4882a593Smuzhiyun 	case 0x91b: /* Intuos3 Airbrush Eraser */
714*4882a593Smuzhiyun 	case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
715*4882a593Smuzhiyun 	case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
716*4882a593Smuzhiyun 	case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
717*4882a593Smuzhiyun 	case 0x1480a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
718*4882a593Smuzhiyun 	case 0x1090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
719*4882a593Smuzhiyun 	case 0x1080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
720*4882a593Smuzhiyun 	case 0x1084a: /* MobileStudio Pro Pro Pen slim Eraser */
721*4882a593Smuzhiyun 	case 0x1680a: /* Cintiq 13HD Pro Pen Eraser */
722*4882a593Smuzhiyun 	case 0x1880a: /* DTH2242 Eraser */
723*4882a593Smuzhiyun 	case 0x1080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
724*4882a593Smuzhiyun 		tool_type = BTN_TOOL_RUBBER;
725*4882a593Smuzhiyun 		break;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	case 0xd12:
728*4882a593Smuzhiyun 	case 0x912:
729*4882a593Smuzhiyun 	case 0x112:
730*4882a593Smuzhiyun 	case 0x913: /* Intuos3 Airbrush */
731*4882a593Smuzhiyun 	case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
732*4882a593Smuzhiyun 	case 0x10902: /* Intuos4/5 13HD/24HD Airbrush */
733*4882a593Smuzhiyun 		tool_type = BTN_TOOL_AIRBRUSH;
734*4882a593Smuzhiyun 		break;
735*4882a593Smuzhiyun 	}
736*4882a593Smuzhiyun 	return tool_type;
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun 
wacom_exit_report(struct wacom_wac * wacom)739*4882a593Smuzhiyun static void wacom_exit_report(struct wacom_wac *wacom)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
742*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
743*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
744*4882a593Smuzhiyun 	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	/*
747*4882a593Smuzhiyun 	 * Reset all states otherwise we lose the initial states
748*4882a593Smuzhiyun 	 * when in-prox next time
749*4882a593Smuzhiyun 	 */
750*4882a593Smuzhiyun 	input_report_abs(input, ABS_X, 0);
751*4882a593Smuzhiyun 	input_report_abs(input, ABS_Y, 0);
752*4882a593Smuzhiyun 	input_report_abs(input, ABS_DISTANCE, 0);
753*4882a593Smuzhiyun 	input_report_abs(input, ABS_TILT_X, 0);
754*4882a593Smuzhiyun 	input_report_abs(input, ABS_TILT_Y, 0);
755*4882a593Smuzhiyun 	if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
756*4882a593Smuzhiyun 		input_report_key(input, BTN_LEFT, 0);
757*4882a593Smuzhiyun 		input_report_key(input, BTN_MIDDLE, 0);
758*4882a593Smuzhiyun 		input_report_key(input, BTN_RIGHT, 0);
759*4882a593Smuzhiyun 		input_report_key(input, BTN_SIDE, 0);
760*4882a593Smuzhiyun 		input_report_key(input, BTN_EXTRA, 0);
761*4882a593Smuzhiyun 		input_report_abs(input, ABS_THROTTLE, 0);
762*4882a593Smuzhiyun 		input_report_abs(input, ABS_RZ, 0);
763*4882a593Smuzhiyun 	} else {
764*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, 0);
765*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, 0);
766*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, 0);
767*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, 0);
768*4882a593Smuzhiyun 		input_report_abs(input, ABS_WHEEL, 0);
769*4882a593Smuzhiyun 		if (features->type >= INTUOS3S)
770*4882a593Smuzhiyun 			input_report_abs(input, ABS_Z, 0);
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 	input_report_key(input, wacom->tool[idx], 0);
773*4882a593Smuzhiyun 	input_report_abs(input, ABS_MISC, 0); /* reset tool id */
774*4882a593Smuzhiyun 	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
775*4882a593Smuzhiyun 	wacom->id[idx] = 0;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
wacom_intuos_inout(struct wacom_wac * wacom)778*4882a593Smuzhiyun static int wacom_intuos_inout(struct wacom_wac *wacom)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
781*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
782*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
783*4882a593Smuzhiyun 	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	if (!(((data[1] & 0xfc) == 0xc0) ||  /* in prox */
786*4882a593Smuzhiyun 	    ((data[1] & 0xfe) == 0x20) ||    /* in range */
787*4882a593Smuzhiyun 	    ((data[1] & 0xfe) == 0x80)))     /* out prox */
788*4882a593Smuzhiyun 		return 0;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	/* Enter report */
791*4882a593Smuzhiyun 	if ((data[1] & 0xfc) == 0xc0) {
792*4882a593Smuzhiyun 		/* serial number of the tool */
793*4882a593Smuzhiyun 		wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
794*4882a593Smuzhiyun 			(data[4] << 20) + (data[5] << 12) +
795*4882a593Smuzhiyun 			(data[6] << 4) + (data[7] >> 4);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 		wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) |
798*4882a593Smuzhiyun 		     ((data[7] & 0x0f) << 16) | ((data[8] & 0xf0) << 8);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 		wacom->tool[idx] = wacom_intuos_get_tool_type(wacom->id[idx]);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 		wacom->shared->stylus_in_proximity = true;
803*4882a593Smuzhiyun 		return 1;
804*4882a593Smuzhiyun 	}
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	/* in Range */
807*4882a593Smuzhiyun 	if ((data[1] & 0xfe) == 0x20) {
808*4882a593Smuzhiyun 		if (features->type != INTUOSHT2)
809*4882a593Smuzhiyun 			wacom->shared->stylus_in_proximity = true;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 		/* in Range while exiting */
812*4882a593Smuzhiyun 		if (wacom->reporting_data) {
813*4882a593Smuzhiyun 			input_report_key(input, BTN_TOUCH, 0);
814*4882a593Smuzhiyun 			input_report_abs(input, ABS_PRESSURE, 0);
815*4882a593Smuzhiyun 			input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
816*4882a593Smuzhiyun 			return 2;
817*4882a593Smuzhiyun 		}
818*4882a593Smuzhiyun 		return 1;
819*4882a593Smuzhiyun 	}
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	/* Exit report */
822*4882a593Smuzhiyun 	if ((data[1] & 0xfe) == 0x80) {
823*4882a593Smuzhiyun 		wacom->shared->stylus_in_proximity = false;
824*4882a593Smuzhiyun 		wacom->reporting_data = false;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 		/* don't report exit if we don't know the ID */
827*4882a593Smuzhiyun 		if (!wacom->id[idx])
828*4882a593Smuzhiyun 			return 1;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 		wacom_exit_report(wacom);
831*4882a593Smuzhiyun 		return 2;
832*4882a593Smuzhiyun 	}
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	return 0;
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun 
report_touch_events(struct wacom_wac * wacom)837*4882a593Smuzhiyun static inline bool report_touch_events(struct wacom_wac *wacom)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun 	return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun 
delay_pen_events(struct wacom_wac * wacom)842*4882a593Smuzhiyun static inline bool delay_pen_events(struct wacom_wac *wacom)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	return (wacom->shared->touch_down && touch_arbitration);
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun 
wacom_intuos_general(struct wacom_wac * wacom)847*4882a593Smuzhiyun static int wacom_intuos_general(struct wacom_wac *wacom)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
850*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
851*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
852*4882a593Smuzhiyun 	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
853*4882a593Smuzhiyun 	unsigned char type = (data[1] >> 1) & 0x0F;
854*4882a593Smuzhiyun 	unsigned int x, y, distance, t;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_CINTIQ &&
857*4882a593Smuzhiyun 		data[0] != WACOM_REPORT_INTUOS_PEN)
858*4882a593Smuzhiyun 		return 0;
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	if (delay_pen_events(wacom))
861*4882a593Smuzhiyun 		return 1;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	/* don't report events if we don't know the tool ID */
864*4882a593Smuzhiyun 	if (!wacom->id[idx]) {
865*4882a593Smuzhiyun 		/* but reschedule a read of the current tool */
866*4882a593Smuzhiyun 		wacom_intuos_schedule_prox_event(wacom);
867*4882a593Smuzhiyun 		return 1;
868*4882a593Smuzhiyun 	}
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	/*
871*4882a593Smuzhiyun 	 * don't report events for invalid data
872*4882a593Smuzhiyun 	 */
873*4882a593Smuzhiyun 	/* older I4 styli don't work with new Cintiqs */
874*4882a593Smuzhiyun 	if ((!((wacom->id[idx] >> 16) & 0x01) &&
875*4882a593Smuzhiyun 			(features->type == WACOM_21UX2)) ||
876*4882a593Smuzhiyun 	    /* Only large Intuos support Lense Cursor */
877*4882a593Smuzhiyun 	    (wacom->tool[idx] == BTN_TOOL_LENS &&
878*4882a593Smuzhiyun 		(features->type == INTUOS3 ||
879*4882a593Smuzhiyun 		 features->type == INTUOS3S ||
880*4882a593Smuzhiyun 		 features->type == INTUOS4 ||
881*4882a593Smuzhiyun 		 features->type == INTUOS4S ||
882*4882a593Smuzhiyun 		 features->type == INTUOS5 ||
883*4882a593Smuzhiyun 		 features->type == INTUOS5S ||
884*4882a593Smuzhiyun 		 features->type == INTUOSPM ||
885*4882a593Smuzhiyun 		 features->type == INTUOSPS)) ||
886*4882a593Smuzhiyun 	   /* Cintiq doesn't send data when RDY bit isn't set */
887*4882a593Smuzhiyun 	   (features->type == CINTIQ && !(data[1] & 0x40)))
888*4882a593Smuzhiyun 		return 1;
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
891*4882a593Smuzhiyun 	y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1);
892*4882a593Smuzhiyun 	distance = data[9] >> 2;
893*4882a593Smuzhiyun 	if (features->type < INTUOS3S) {
894*4882a593Smuzhiyun 		x >>= 1;
895*4882a593Smuzhiyun 		y >>= 1;
896*4882a593Smuzhiyun 		distance >>= 1;
897*4882a593Smuzhiyun 	}
898*4882a593Smuzhiyun 	if (features->type == INTUOSHT2)
899*4882a593Smuzhiyun 		distance = features->distance_max - distance;
900*4882a593Smuzhiyun 	input_report_abs(input, ABS_X, x);
901*4882a593Smuzhiyun 	input_report_abs(input, ABS_Y, y);
902*4882a593Smuzhiyun 	input_report_abs(input, ABS_DISTANCE, distance);
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	switch (type) {
905*4882a593Smuzhiyun 	case 0x00:
906*4882a593Smuzhiyun 	case 0x01:
907*4882a593Smuzhiyun 	case 0x02:
908*4882a593Smuzhiyun 	case 0x03:
909*4882a593Smuzhiyun 		/* general pen packet */
910*4882a593Smuzhiyun 		t = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1);
911*4882a593Smuzhiyun 		if (features->pressure_max < 2047)
912*4882a593Smuzhiyun 			t >>= 1;
913*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, t);
914*4882a593Smuzhiyun 		if (features->type != INTUOSHT2) {
915*4882a593Smuzhiyun 		    input_report_abs(input, ABS_TILT_X,
916*4882a593Smuzhiyun 				 (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
917*4882a593Smuzhiyun 		    input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
918*4882a593Smuzhiyun 		}
919*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, data[1] & 2);
920*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, data[1] & 4);
921*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, t > 10);
922*4882a593Smuzhiyun 		break;
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	case 0x0a:
925*4882a593Smuzhiyun 		/* airbrush second packet */
926*4882a593Smuzhiyun 		input_report_abs(input, ABS_WHEEL,
927*4882a593Smuzhiyun 				(data[6] << 2) | ((data[7] >> 6) & 3));
928*4882a593Smuzhiyun 		input_report_abs(input, ABS_TILT_X,
929*4882a593Smuzhiyun 				 (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
930*4882a593Smuzhiyun 		input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
931*4882a593Smuzhiyun 		break;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	case 0x05:
934*4882a593Smuzhiyun 		/* Rotation packet */
935*4882a593Smuzhiyun 		if (features->type >= INTUOS3S) {
936*4882a593Smuzhiyun 			/* I3 marker pen rotation */
937*4882a593Smuzhiyun 			t = (data[6] << 3) | ((data[7] >> 5) & 7);
938*4882a593Smuzhiyun 			t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
939*4882a593Smuzhiyun 				((t-1) / 2 + 450)) : (450 - t / 2) ;
940*4882a593Smuzhiyun 			input_report_abs(input, ABS_Z, t);
941*4882a593Smuzhiyun 		} else {
942*4882a593Smuzhiyun 			/* 4D mouse 2nd packet */
943*4882a593Smuzhiyun 			t = (data[6] << 3) | ((data[7] >> 5) & 7);
944*4882a593Smuzhiyun 			input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
945*4882a593Smuzhiyun 				((t - 1) / 2) : -t / 2);
946*4882a593Smuzhiyun 		}
947*4882a593Smuzhiyun 		break;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	case 0x04:
950*4882a593Smuzhiyun 		/* 4D mouse 1st packet */
951*4882a593Smuzhiyun 		input_report_key(input, BTN_LEFT,   data[8] & 0x01);
952*4882a593Smuzhiyun 		input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
953*4882a593Smuzhiyun 		input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 		input_report_key(input, BTN_SIDE,   data[8] & 0x20);
956*4882a593Smuzhiyun 		input_report_key(input, BTN_EXTRA,  data[8] & 0x10);
957*4882a593Smuzhiyun 		t = (data[6] << 2) | ((data[7] >> 6) & 3);
958*4882a593Smuzhiyun 		input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
959*4882a593Smuzhiyun 		break;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	case 0x06:
962*4882a593Smuzhiyun 		/* I4 mouse */
963*4882a593Smuzhiyun 		input_report_key(input, BTN_LEFT,   data[6] & 0x01);
964*4882a593Smuzhiyun 		input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
965*4882a593Smuzhiyun 		input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
966*4882a593Smuzhiyun 		input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
967*4882a593Smuzhiyun 				 - ((data[7] & 0x40) >> 6));
968*4882a593Smuzhiyun 		input_report_key(input, BTN_SIDE,   data[6] & 0x08);
969*4882a593Smuzhiyun 		input_report_key(input, BTN_EXTRA,  data[6] & 0x10);
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 		input_report_abs(input, ABS_TILT_X,
972*4882a593Smuzhiyun 			(((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
973*4882a593Smuzhiyun 		input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
974*4882a593Smuzhiyun 		break;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	case 0x08:
977*4882a593Smuzhiyun 		if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
978*4882a593Smuzhiyun 			/* 2D mouse packet */
979*4882a593Smuzhiyun 			input_report_key(input, BTN_LEFT,   data[8] & 0x04);
980*4882a593Smuzhiyun 			input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
981*4882a593Smuzhiyun 			input_report_key(input, BTN_RIGHT,  data[8] & 0x10);
982*4882a593Smuzhiyun 			input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
983*4882a593Smuzhiyun 					 - ((data[8] & 0x02) >> 1));
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 			/* I3 2D mouse side buttons */
986*4882a593Smuzhiyun 			if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
987*4882a593Smuzhiyun 				input_report_key(input, BTN_SIDE,   data[8] & 0x40);
988*4882a593Smuzhiyun 				input_report_key(input, BTN_EXTRA,  data[8] & 0x20);
989*4882a593Smuzhiyun 			}
990*4882a593Smuzhiyun 		}
991*4882a593Smuzhiyun 		else if (wacom->tool[idx] == BTN_TOOL_LENS) {
992*4882a593Smuzhiyun 			/* Lens cursor packets */
993*4882a593Smuzhiyun 			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
994*4882a593Smuzhiyun 			input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
995*4882a593Smuzhiyun 			input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
996*4882a593Smuzhiyun 			input_report_key(input, BTN_SIDE,   data[8] & 0x10);
997*4882a593Smuzhiyun 			input_report_key(input, BTN_EXTRA,  data[8] & 0x08);
998*4882a593Smuzhiyun 		}
999*4882a593Smuzhiyun 		break;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	case 0x07:
1002*4882a593Smuzhiyun 	case 0x09:
1003*4882a593Smuzhiyun 	case 0x0b:
1004*4882a593Smuzhiyun 	case 0x0c:
1005*4882a593Smuzhiyun 	case 0x0d:
1006*4882a593Smuzhiyun 	case 0x0e:
1007*4882a593Smuzhiyun 	case 0x0f:
1008*4882a593Smuzhiyun 		/* unhandled */
1009*4882a593Smuzhiyun 		break;
1010*4882a593Smuzhiyun 	}
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	input_report_abs(input, ABS_MISC,
1013*4882a593Smuzhiyun 			 wacom_intuos_id_mangle(wacom->id[idx])); /* report tool id */
1014*4882a593Smuzhiyun 	input_report_key(input, wacom->tool[idx], 1);
1015*4882a593Smuzhiyun 	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
1016*4882a593Smuzhiyun 	wacom->reporting_data = true;
1017*4882a593Smuzhiyun 	return 2;
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun 
wacom_intuos_irq(struct wacom_wac * wacom)1020*4882a593Smuzhiyun static int wacom_intuos_irq(struct wacom_wac *wacom)
1021*4882a593Smuzhiyun {
1022*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1023*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
1024*4882a593Smuzhiyun 	int result;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_PENABLED &&
1027*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_INTUOS_ID1 &&
1028*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_INTUOS_ID2 &&
1029*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_INTUOSPAD &&
1030*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_INTUOS_PEN &&
1031*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_CINTIQ &&
1032*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_CINTIQPAD &&
1033*4882a593Smuzhiyun 	    data[0] != WACOM_REPORT_INTUOS5PAD) {
1034*4882a593Smuzhiyun 		dev_dbg(input->dev.parent,
1035*4882a593Smuzhiyun 			"%s: received unknown report #%d\n", __func__, data[0]);
1036*4882a593Smuzhiyun                 return 0;
1037*4882a593Smuzhiyun 	}
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	/* process pad events */
1040*4882a593Smuzhiyun 	result = wacom_intuos_pad(wacom);
1041*4882a593Smuzhiyun 	if (result)
1042*4882a593Smuzhiyun 		return result;
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	/* process in/out prox events */
1045*4882a593Smuzhiyun 	result = wacom_intuos_inout(wacom);
1046*4882a593Smuzhiyun 	if (result)
1047*4882a593Smuzhiyun 		return result - 1;
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	/* process general packets */
1050*4882a593Smuzhiyun 	result = wacom_intuos_general(wacom);
1051*4882a593Smuzhiyun 	if (result)
1052*4882a593Smuzhiyun 		return result - 1;
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	return 0;
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun 
wacom_remote_irq(struct wacom_wac * wacom_wac,size_t len)1057*4882a593Smuzhiyun static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
1058*4882a593Smuzhiyun {
1059*4882a593Smuzhiyun 	unsigned char *data = wacom_wac->data;
1060*4882a593Smuzhiyun 	struct input_dev *input;
1061*4882a593Smuzhiyun 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
1062*4882a593Smuzhiyun 	struct wacom_remote *remote = wacom->remote;
1063*4882a593Smuzhiyun 	int bat_charging, bat_percent, touch_ring_mode;
1064*4882a593Smuzhiyun 	__u32 serial;
1065*4882a593Smuzhiyun 	int i, index = -1;
1066*4882a593Smuzhiyun 	unsigned long flags;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_REMOTE) {
1069*4882a593Smuzhiyun 		hid_dbg(wacom->hdev, "%s: received unknown report #%d",
1070*4882a593Smuzhiyun 			__func__, data[0]);
1071*4882a593Smuzhiyun 		return 0;
1072*4882a593Smuzhiyun 	}
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	serial = data[3] + (data[4] << 8) + (data[5] << 16);
1075*4882a593Smuzhiyun 	wacom_wac->id[0] = PAD_DEVICE_ID;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	spin_lock_irqsave(&remote->remote_lock, flags);
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1080*4882a593Smuzhiyun 		if (remote->remotes[i].serial == serial) {
1081*4882a593Smuzhiyun 			index = i;
1082*4882a593Smuzhiyun 			break;
1083*4882a593Smuzhiyun 		}
1084*4882a593Smuzhiyun 	}
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	if (index < 0 || !remote->remotes[index].registered)
1087*4882a593Smuzhiyun 		goto out;
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	input = remote->remotes[index].input;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	input_report_key(input, BTN_0, (data[9] & 0x01));
1092*4882a593Smuzhiyun 	input_report_key(input, BTN_1, (data[9] & 0x02));
1093*4882a593Smuzhiyun 	input_report_key(input, BTN_2, (data[9] & 0x04));
1094*4882a593Smuzhiyun 	input_report_key(input, BTN_3, (data[9] & 0x08));
1095*4882a593Smuzhiyun 	input_report_key(input, BTN_4, (data[9] & 0x10));
1096*4882a593Smuzhiyun 	input_report_key(input, BTN_5, (data[9] & 0x20));
1097*4882a593Smuzhiyun 	input_report_key(input, BTN_6, (data[9] & 0x40));
1098*4882a593Smuzhiyun 	input_report_key(input, BTN_7, (data[9] & 0x80));
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	input_report_key(input, BTN_8, (data[10] & 0x01));
1101*4882a593Smuzhiyun 	input_report_key(input, BTN_9, (data[10] & 0x02));
1102*4882a593Smuzhiyun 	input_report_key(input, BTN_A, (data[10] & 0x04));
1103*4882a593Smuzhiyun 	input_report_key(input, BTN_B, (data[10] & 0x08));
1104*4882a593Smuzhiyun 	input_report_key(input, BTN_C, (data[10] & 0x10));
1105*4882a593Smuzhiyun 	input_report_key(input, BTN_X, (data[10] & 0x20));
1106*4882a593Smuzhiyun 	input_report_key(input, BTN_Y, (data[10] & 0x40));
1107*4882a593Smuzhiyun 	input_report_key(input, BTN_Z, (data[10] & 0x80));
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun 	input_report_key(input, BTN_BASE, (data[11] & 0x01));
1110*4882a593Smuzhiyun 	input_report_key(input, BTN_BASE2, (data[11] & 0x02));
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	if (data[12] & 0x80)
1113*4882a593Smuzhiyun 		input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f) - 1);
1114*4882a593Smuzhiyun 	else
1115*4882a593Smuzhiyun 		input_report_abs(input, ABS_WHEEL, 0);
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	bat_percent = data[7] & 0x7f;
1118*4882a593Smuzhiyun 	bat_charging = !!(data[7] & 0x80);
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	if (data[9] | data[10] | (data[11] & 0x03) | data[12])
1121*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
1122*4882a593Smuzhiyun 	else
1123*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, 0);
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	input_event(input, EV_MSC, MSC_SERIAL, serial);
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 	input_sync(input);
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	/*Which mode select (LED light) is currently on?*/
1130*4882a593Smuzhiyun 	touch_ring_mode = (data[11] & 0xC0) >> 6;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1133*4882a593Smuzhiyun 		if (remote->remotes[i].serial == serial)
1134*4882a593Smuzhiyun 			wacom->led.groups[i].select = touch_ring_mode;
1135*4882a593Smuzhiyun 	}
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	__wacom_notify_battery(&remote->remotes[index].battery,
1138*4882a593Smuzhiyun 				WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
1139*4882a593Smuzhiyun 				bat_charging, 1, bat_charging);
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun out:
1142*4882a593Smuzhiyun 	spin_unlock_irqrestore(&remote->remote_lock, flags);
1143*4882a593Smuzhiyun 	return 0;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun 
wacom_remote_status_irq(struct wacom_wac * wacom_wac,size_t len)1146*4882a593Smuzhiyun static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
1149*4882a593Smuzhiyun 	unsigned char *data = wacom_wac->data;
1150*4882a593Smuzhiyun 	struct wacom_remote *remote = wacom->remote;
1151*4882a593Smuzhiyun 	struct wacom_remote_data remote_data;
1152*4882a593Smuzhiyun 	unsigned long flags;
1153*4882a593Smuzhiyun 	int i, ret;
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_DEVICE_LIST)
1156*4882a593Smuzhiyun 		return;
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	memset(&remote_data, 0, sizeof(struct wacom_remote_data));
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1161*4882a593Smuzhiyun 		int j = i * 6;
1162*4882a593Smuzhiyun 		int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
1163*4882a593Smuzhiyun 		bool connected = data[j+2];
1164*4882a593Smuzhiyun 
1165*4882a593Smuzhiyun 		remote_data.remote[i].serial = serial;
1166*4882a593Smuzhiyun 		remote_data.remote[i].connected = connected;
1167*4882a593Smuzhiyun 	}
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	spin_lock_irqsave(&remote->remote_lock, flags);
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
1172*4882a593Smuzhiyun 	if (ret != sizeof(remote_data)) {
1173*4882a593Smuzhiyun 		spin_unlock_irqrestore(&remote->remote_lock, flags);
1174*4882a593Smuzhiyun 		hid_err(wacom->hdev, "Can't queue Remote status event.\n");
1175*4882a593Smuzhiyun 		return;
1176*4882a593Smuzhiyun 	}
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	spin_unlock_irqrestore(&remote->remote_lock, flags);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun 
int_dist(int x1,int y1,int x2,int y2)1183*4882a593Smuzhiyun static int int_dist(int x1, int y1, int x2, int y2)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun 	int x = x2 - x1;
1186*4882a593Smuzhiyun 	int y = y2 - y1;
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	return int_sqrt(x*x + y*y);
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun 
wacom_intuos_bt_process_data(struct wacom_wac * wacom,unsigned char * data)1191*4882a593Smuzhiyun static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
1192*4882a593Smuzhiyun 		unsigned char *data)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun 	memcpy(wacom->data, data, 10);
1195*4882a593Smuzhiyun 	wacom_intuos_irq(wacom);
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	input_sync(wacom->pen_input);
1198*4882a593Smuzhiyun 	if (wacom->pad_input)
1199*4882a593Smuzhiyun 		input_sync(wacom->pad_input);
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun 
wacom_intuos_bt_irq(struct wacom_wac * wacom,size_t len)1202*4882a593Smuzhiyun static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun 	unsigned char data[WACOM_PKGLEN_MAX];
1205*4882a593Smuzhiyun 	int i = 1;
1206*4882a593Smuzhiyun 	unsigned power_raw, battery_capacity, bat_charging, ps_connected;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	memcpy(data, wacom->data, len);
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	switch (data[0]) {
1211*4882a593Smuzhiyun 	case 0x04:
1212*4882a593Smuzhiyun 		wacom_intuos_bt_process_data(wacom, data + i);
1213*4882a593Smuzhiyun 		i += 10;
1214*4882a593Smuzhiyun 		fallthrough;
1215*4882a593Smuzhiyun 	case 0x03:
1216*4882a593Smuzhiyun 		wacom_intuos_bt_process_data(wacom, data + i);
1217*4882a593Smuzhiyun 		i += 10;
1218*4882a593Smuzhiyun 		wacom_intuos_bt_process_data(wacom, data + i);
1219*4882a593Smuzhiyun 		i += 10;
1220*4882a593Smuzhiyun 		power_raw = data[i];
1221*4882a593Smuzhiyun 		bat_charging = (power_raw & 0x08) ? 1 : 0;
1222*4882a593Smuzhiyun 		ps_connected = (power_raw & 0x10) ? 1 : 0;
1223*4882a593Smuzhiyun 		battery_capacity = batcap_i4[power_raw & 0x07];
1224*4882a593Smuzhiyun 		wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
1225*4882a593Smuzhiyun 				     battery_capacity, bat_charging,
1226*4882a593Smuzhiyun 				     battery_capacity || bat_charging,
1227*4882a593Smuzhiyun 				     ps_connected);
1228*4882a593Smuzhiyun 		break;
1229*4882a593Smuzhiyun 	default:
1230*4882a593Smuzhiyun 		dev_dbg(wacom->pen_input->dev.parent,
1231*4882a593Smuzhiyun 				"Unknown report: %d,%d size:%zu\n",
1232*4882a593Smuzhiyun 				data[0], data[1], len);
1233*4882a593Smuzhiyun 		return 0;
1234*4882a593Smuzhiyun 	}
1235*4882a593Smuzhiyun 	return 0;
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun 
wacom_wac_finger_count_touches(struct wacom_wac * wacom)1238*4882a593Smuzhiyun static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
1241*4882a593Smuzhiyun 	unsigned touch_max = wacom->features.touch_max;
1242*4882a593Smuzhiyun 	int count = 0;
1243*4882a593Smuzhiyun 	int i;
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 	if (!touch_max)
1246*4882a593Smuzhiyun 		return 0;
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun 	if (touch_max == 1)
1249*4882a593Smuzhiyun 		return test_bit(BTN_TOUCH, input->key) &&
1250*4882a593Smuzhiyun 			report_touch_events(wacom);
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	for (i = 0; i < input->mt->num_slots; i++) {
1253*4882a593Smuzhiyun 		struct input_mt_slot *ps = &input->mt->slots[i];
1254*4882a593Smuzhiyun 		int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
1255*4882a593Smuzhiyun 		if (id >= 0)
1256*4882a593Smuzhiyun 			count++;
1257*4882a593Smuzhiyun 	}
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	return count;
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun 
wacom_intuos_pro2_bt_pen(struct wacom_wac * wacom)1262*4882a593Smuzhiyun static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
1263*4882a593Smuzhiyun {
1264*4882a593Smuzhiyun 	int pen_frame_len, pen_frames;
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	struct input_dev *pen_input = wacom->pen_input;
1267*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1268*4882a593Smuzhiyun 	int i;
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	if (wacom->features.type == INTUOSP2_BT ||
1271*4882a593Smuzhiyun 	    wacom->features.type == INTUOSP2S_BT) {
1272*4882a593Smuzhiyun 		wacom->serial[0] = get_unaligned_le64(&data[99]);
1273*4882a593Smuzhiyun 		wacom->id[0]     = get_unaligned_le16(&data[107]);
1274*4882a593Smuzhiyun 		pen_frame_len = 14;
1275*4882a593Smuzhiyun 		pen_frames = 7;
1276*4882a593Smuzhiyun 	} else {
1277*4882a593Smuzhiyun 		wacom->serial[0] = get_unaligned_le64(&data[33]);
1278*4882a593Smuzhiyun 		wacom->id[0]     = get_unaligned_le16(&data[41]);
1279*4882a593Smuzhiyun 		pen_frame_len = 8;
1280*4882a593Smuzhiyun 		pen_frames = 4;
1281*4882a593Smuzhiyun 	}
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	if (wacom->serial[0] >> 52 == 1) {
1284*4882a593Smuzhiyun 		/* Add back in missing bits of ID for non-USI pens */
1285*4882a593Smuzhiyun 		wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
1286*4882a593Smuzhiyun 	}
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun 	for (i = 0; i < pen_frames; i++) {
1289*4882a593Smuzhiyun 		unsigned char *frame = &data[i*pen_frame_len + 1];
1290*4882a593Smuzhiyun 		bool valid = frame[0] & 0x80;
1291*4882a593Smuzhiyun 		bool prox = frame[0] & 0x40;
1292*4882a593Smuzhiyun 		bool range = frame[0] & 0x20;
1293*4882a593Smuzhiyun 		bool invert = frame[0] & 0x10;
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 		if (!valid)
1296*4882a593Smuzhiyun 			continue;
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 		if (!prox) {
1299*4882a593Smuzhiyun 			wacom->shared->stylus_in_proximity = false;
1300*4882a593Smuzhiyun 			wacom_exit_report(wacom);
1301*4882a593Smuzhiyun 			input_sync(pen_input);
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 			wacom->tool[0] = 0;
1304*4882a593Smuzhiyun 			wacom->id[0] = 0;
1305*4882a593Smuzhiyun 			wacom->serial[0] = 0;
1306*4882a593Smuzhiyun 			return;
1307*4882a593Smuzhiyun 		}
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 		if (range) {
1310*4882a593Smuzhiyun 			if (!wacom->tool[0]) { /* first in range */
1311*4882a593Smuzhiyun 				/* Going into range select tool */
1312*4882a593Smuzhiyun 				if (invert)
1313*4882a593Smuzhiyun 					wacom->tool[0] = BTN_TOOL_RUBBER;
1314*4882a593Smuzhiyun 				else if (wacom->id[0])
1315*4882a593Smuzhiyun 					wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0]);
1316*4882a593Smuzhiyun 				else
1317*4882a593Smuzhiyun 					wacom->tool[0] = BTN_TOOL_PEN;
1318*4882a593Smuzhiyun 			}
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 			input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
1321*4882a593Smuzhiyun 			input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 			if (wacom->features.type == INTUOSP2_BT ||
1324*4882a593Smuzhiyun 			    wacom->features.type == INTUOSP2S_BT) {
1325*4882a593Smuzhiyun 				/* Fix rotation alignment: userspace expects zero at left */
1326*4882a593Smuzhiyun 				int16_t rotation =
1327*4882a593Smuzhiyun 					(int16_t)get_unaligned_le16(&frame[9]);
1328*4882a593Smuzhiyun 				rotation += 1800/4;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 				if (rotation > 899)
1331*4882a593Smuzhiyun 					rotation -= 1800;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 				input_report_abs(pen_input, ABS_TILT_X,
1334*4882a593Smuzhiyun 						 (char)frame[7]);
1335*4882a593Smuzhiyun 				input_report_abs(pen_input, ABS_TILT_Y,
1336*4882a593Smuzhiyun 						 (char)frame[8]);
1337*4882a593Smuzhiyun 				input_report_abs(pen_input, ABS_Z, rotation);
1338*4882a593Smuzhiyun 				input_report_abs(pen_input, ABS_WHEEL,
1339*4882a593Smuzhiyun 						 get_unaligned_le16(&frame[11]));
1340*4882a593Smuzhiyun 			}
1341*4882a593Smuzhiyun 		}
1342*4882a593Smuzhiyun 		if (wacom->tool[0]) {
1343*4882a593Smuzhiyun 			input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
1344*4882a593Smuzhiyun 			if (wacom->features.type == INTUOSP2_BT ||
1345*4882a593Smuzhiyun 			    wacom->features.type == INTUOSP2S_BT) {
1346*4882a593Smuzhiyun 				input_report_abs(pen_input, ABS_DISTANCE,
1347*4882a593Smuzhiyun 						 range ? frame[13] : wacom->features.distance_max);
1348*4882a593Smuzhiyun 			} else {
1349*4882a593Smuzhiyun 				input_report_abs(pen_input, ABS_DISTANCE,
1350*4882a593Smuzhiyun 						 range ? frame[7] : wacom->features.distance_max);
1351*4882a593Smuzhiyun 			}
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 			input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x09);
1354*4882a593Smuzhiyun 			input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
1355*4882a593Smuzhiyun 			input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 			input_report_key(pen_input, wacom->tool[0], prox);
1358*4882a593Smuzhiyun 			input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
1359*4882a593Smuzhiyun 			input_report_abs(pen_input, ABS_MISC,
1360*4882a593Smuzhiyun 					 wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
1361*4882a593Smuzhiyun 		}
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 		wacom->shared->stylus_in_proximity = prox;
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun 		input_sync(pen_input);
1366*4882a593Smuzhiyun 	}
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun 
wacom_intuos_pro2_bt_touch(struct wacom_wac * wacom)1369*4882a593Smuzhiyun static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
1370*4882a593Smuzhiyun {
1371*4882a593Smuzhiyun 	const int finger_touch_len = 8;
1372*4882a593Smuzhiyun 	const int finger_frames = 4;
1373*4882a593Smuzhiyun 	const int finger_frame_len = 43;
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun 	struct input_dev *touch_input = wacom->touch_input;
1376*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1377*4882a593Smuzhiyun 	int num_contacts_left = 5;
1378*4882a593Smuzhiyun 	int i, j;
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	for (i = 0; i < finger_frames; i++) {
1381*4882a593Smuzhiyun 		unsigned char *frame = &data[i*finger_frame_len + 109];
1382*4882a593Smuzhiyun 		int current_num_contacts = frame[0] & 0x7F;
1383*4882a593Smuzhiyun 		int contacts_to_send;
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun 		if (!(frame[0] & 0x80))
1386*4882a593Smuzhiyun 			continue;
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 		/*
1389*4882a593Smuzhiyun 		 * First packet resets the counter since only the first
1390*4882a593Smuzhiyun 		 * packet in series will have non-zero current_num_contacts.
1391*4882a593Smuzhiyun 		 */
1392*4882a593Smuzhiyun 		if (current_num_contacts)
1393*4882a593Smuzhiyun 			wacom->num_contacts_left = current_num_contacts;
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 		contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 		for (j = 0; j < contacts_to_send; j++) {
1398*4882a593Smuzhiyun 			unsigned char *touch = &frame[j*finger_touch_len + 1];
1399*4882a593Smuzhiyun 			int slot = input_mt_get_slot_by_key(touch_input, touch[0]);
1400*4882a593Smuzhiyun 			int x = get_unaligned_le16(&touch[2]);
1401*4882a593Smuzhiyun 			int y = get_unaligned_le16(&touch[4]);
1402*4882a593Smuzhiyun 			int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X);
1403*4882a593Smuzhiyun 			int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y);
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 			if (slot < 0)
1406*4882a593Smuzhiyun 				continue;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 			input_mt_slot(touch_input, slot);
1409*4882a593Smuzhiyun 			input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01);
1410*4882a593Smuzhiyun 			input_report_abs(touch_input, ABS_MT_POSITION_X, x);
1411*4882a593Smuzhiyun 			input_report_abs(touch_input, ABS_MT_POSITION_Y, y);
1412*4882a593Smuzhiyun 			input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h));
1413*4882a593Smuzhiyun 			input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h));
1414*4882a593Smuzhiyun 			input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h);
1415*4882a593Smuzhiyun 		}
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun 		input_mt_sync_frame(touch_input);
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun 		wacom->num_contacts_left -= contacts_to_send;
1420*4882a593Smuzhiyun 		if (wacom->num_contacts_left <= 0) {
1421*4882a593Smuzhiyun 			wacom->num_contacts_left = 0;
1422*4882a593Smuzhiyun 			wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1423*4882a593Smuzhiyun 			input_sync(touch_input);
1424*4882a593Smuzhiyun 		}
1425*4882a593Smuzhiyun 	}
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	if (wacom->num_contacts_left == 0) {
1428*4882a593Smuzhiyun 		// Be careful that we don't accidentally call input_sync with
1429*4882a593Smuzhiyun 		// only a partial set of fingers of processed
1430*4882a593Smuzhiyun 		input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
1431*4882a593Smuzhiyun 		input_sync(touch_input);
1432*4882a593Smuzhiyun 	}
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun }
1435*4882a593Smuzhiyun 
wacom_intuos_pro2_bt_pad(struct wacom_wac * wacom)1436*4882a593Smuzhiyun static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
1437*4882a593Smuzhiyun {
1438*4882a593Smuzhiyun 	struct input_dev *pad_input = wacom->pad_input;
1439*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1440*4882a593Smuzhiyun 	int nbuttons = wacom->features.numbered_buttons;
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun 	int expresskeys = data[282];
1443*4882a593Smuzhiyun 	int center = (data[281] & 0x40) >> 6;
1444*4882a593Smuzhiyun 	int ring = data[285] & 0x7F;
1445*4882a593Smuzhiyun 	bool ringstatus = data[285] & 0x80;
1446*4882a593Smuzhiyun 	bool prox = expresskeys || center || ringstatus;
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	/* Fix touchring data: userspace expects 0 at left and increasing clockwise */
1449*4882a593Smuzhiyun 	ring = 71 - ring;
1450*4882a593Smuzhiyun 	ring += 3*72/16;
1451*4882a593Smuzhiyun 	if (ring > 71)
1452*4882a593Smuzhiyun 		ring -= 72;
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	wacom_report_numbered_buttons(pad_input, nbuttons,
1455*4882a593Smuzhiyun                                       expresskeys | (center << (nbuttons - 1)));
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun 	input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0);
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
1460*4882a593Smuzhiyun 	input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
1461*4882a593Smuzhiyun 	input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	input_sync(pad_input);
1464*4882a593Smuzhiyun }
1465*4882a593Smuzhiyun 
wacom_intuos_pro2_bt_battery(struct wacom_wac * wacom)1466*4882a593Smuzhiyun static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
1467*4882a593Smuzhiyun {
1468*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	bool chg = data[284] & 0x80;
1471*4882a593Smuzhiyun 	int battery_status = data[284] & 0x7F;
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
1474*4882a593Smuzhiyun 			     battery_status, chg, 1, chg);
1475*4882a593Smuzhiyun }
1476*4882a593Smuzhiyun 
wacom_intuos_gen3_bt_pad(struct wacom_wac * wacom)1477*4882a593Smuzhiyun static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom)
1478*4882a593Smuzhiyun {
1479*4882a593Smuzhiyun 	struct input_dev *pad_input = wacom->pad_input;
1480*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	int buttons = data[44];
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 	wacom_report_numbered_buttons(pad_input, 4, buttons);
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun 	input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0);
1487*4882a593Smuzhiyun 	input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0);
1488*4882a593Smuzhiyun 	input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	input_sync(pad_input);
1491*4882a593Smuzhiyun }
1492*4882a593Smuzhiyun 
wacom_intuos_gen3_bt_battery(struct wacom_wac * wacom)1493*4882a593Smuzhiyun static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom)
1494*4882a593Smuzhiyun {
1495*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	bool chg = data[45] & 0x80;
1498*4882a593Smuzhiyun 	int battery_status = data[45] & 0x7F;
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
1501*4882a593Smuzhiyun 			     battery_status, chg, 1, chg);
1502*4882a593Smuzhiyun }
1503*4882a593Smuzhiyun 
wacom_intuos_pro2_bt_irq(struct wacom_wac * wacom,size_t len)1504*4882a593Smuzhiyun static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 	if (data[0] != 0x80 && data[0] != 0x81) {
1509*4882a593Smuzhiyun 		dev_dbg(wacom->pen_input->dev.parent,
1510*4882a593Smuzhiyun 			"%s: received unknown report #%d\n", __func__, data[0]);
1511*4882a593Smuzhiyun 		return 0;
1512*4882a593Smuzhiyun 	}
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun 	wacom_intuos_pro2_bt_pen(wacom);
1515*4882a593Smuzhiyun 	if (wacom->features.type == INTUOSP2_BT ||
1516*4882a593Smuzhiyun 	    wacom->features.type == INTUOSP2S_BT) {
1517*4882a593Smuzhiyun 		wacom_intuos_pro2_bt_touch(wacom);
1518*4882a593Smuzhiyun 		wacom_intuos_pro2_bt_pad(wacom);
1519*4882a593Smuzhiyun 		wacom_intuos_pro2_bt_battery(wacom);
1520*4882a593Smuzhiyun 	} else {
1521*4882a593Smuzhiyun 		wacom_intuos_gen3_bt_pad(wacom);
1522*4882a593Smuzhiyun 		wacom_intuos_gen3_bt_battery(wacom);
1523*4882a593Smuzhiyun 	}
1524*4882a593Smuzhiyun 	return 0;
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun 
wacom_24hdt_irq(struct wacom_wac * wacom)1527*4882a593Smuzhiyun static int wacom_24hdt_irq(struct wacom_wac *wacom)
1528*4882a593Smuzhiyun {
1529*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
1530*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1531*4882a593Smuzhiyun 	int i;
1532*4882a593Smuzhiyun 	int current_num_contacts = data[61];
1533*4882a593Smuzhiyun 	int contacts_to_send = 0;
1534*4882a593Smuzhiyun 	int num_contacts_left = 4; /* maximum contacts per packet */
1535*4882a593Smuzhiyun 	int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
1536*4882a593Smuzhiyun 	int y_offset = 2;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	if (wacom->shared->has_mute_touch_switch &&
1539*4882a593Smuzhiyun 	    !wacom->shared->is_touch_on) {
1540*4882a593Smuzhiyun 		if (!wacom->shared->touch_down)
1541*4882a593Smuzhiyun 			return 0;
1542*4882a593Smuzhiyun 	}
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun 	if (wacom->features.type == WACOM_27QHDT) {
1545*4882a593Smuzhiyun 		current_num_contacts = data[63];
1546*4882a593Smuzhiyun 		num_contacts_left = 10;
1547*4882a593Smuzhiyun 		byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
1548*4882a593Smuzhiyun 		y_offset = 0;
1549*4882a593Smuzhiyun 	}
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	/*
1552*4882a593Smuzhiyun 	 * First packet resets the counter since only the first
1553*4882a593Smuzhiyun 	 * packet in series will have non-zero current_num_contacts.
1554*4882a593Smuzhiyun 	 */
1555*4882a593Smuzhiyun 	if (current_num_contacts)
1556*4882a593Smuzhiyun 		wacom->num_contacts_left = current_num_contacts;
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	for (i = 0; i < contacts_to_send; i++) {
1561*4882a593Smuzhiyun 		int offset = (byte_per_packet * i) + 1;
1562*4882a593Smuzhiyun 		bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
1563*4882a593Smuzhiyun 		int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 		if (slot < 0)
1566*4882a593Smuzhiyun 			continue;
1567*4882a593Smuzhiyun 		input_mt_slot(input, slot);
1568*4882a593Smuzhiyun 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 		if (touch) {
1571*4882a593Smuzhiyun 			int t_x = get_unaligned_le16(&data[offset + 2]);
1572*4882a593Smuzhiyun 			int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]);
1573*4882a593Smuzhiyun 
1574*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_X, t_x);
1575*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_Y, t_y);
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 			if (wacom->features.type != WACOM_27QHDT) {
1578*4882a593Smuzhiyun 				int c_x = get_unaligned_le16(&data[offset + 4]);
1579*4882a593Smuzhiyun 				int c_y = get_unaligned_le16(&data[offset + 8]);
1580*4882a593Smuzhiyun 				int w = get_unaligned_le16(&data[offset + 10]);
1581*4882a593Smuzhiyun 				int h = get_unaligned_le16(&data[offset + 12]);
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 				input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
1584*4882a593Smuzhiyun 				input_report_abs(input, ABS_MT_WIDTH_MAJOR,
1585*4882a593Smuzhiyun 						 min(w, h) + int_dist(t_x, t_y, c_x, c_y));
1586*4882a593Smuzhiyun 				input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
1587*4882a593Smuzhiyun 				input_report_abs(input, ABS_MT_ORIENTATION, w > h);
1588*4882a593Smuzhiyun 			}
1589*4882a593Smuzhiyun 		}
1590*4882a593Smuzhiyun 	}
1591*4882a593Smuzhiyun 	input_mt_sync_frame(input);
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	wacom->num_contacts_left -= contacts_to_send;
1594*4882a593Smuzhiyun 	if (wacom->num_contacts_left <= 0) {
1595*4882a593Smuzhiyun 		wacom->num_contacts_left = 0;
1596*4882a593Smuzhiyun 		wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1597*4882a593Smuzhiyun 	}
1598*4882a593Smuzhiyun 	return 1;
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun 
wacom_mt_touch(struct wacom_wac * wacom)1601*4882a593Smuzhiyun static int wacom_mt_touch(struct wacom_wac *wacom)
1602*4882a593Smuzhiyun {
1603*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
1604*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1605*4882a593Smuzhiyun 	int i;
1606*4882a593Smuzhiyun 	int current_num_contacts = data[2];
1607*4882a593Smuzhiyun 	int contacts_to_send = 0;
1608*4882a593Smuzhiyun 	int x_offset = 0;
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun 	/* MTTPC does not support Height and Width */
1611*4882a593Smuzhiyun 	if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
1612*4882a593Smuzhiyun 		x_offset = -4;
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	/*
1615*4882a593Smuzhiyun 	 * First packet resets the counter since only the first
1616*4882a593Smuzhiyun 	 * packet in series will have non-zero current_num_contacts.
1617*4882a593Smuzhiyun 	 */
1618*4882a593Smuzhiyun 	if (current_num_contacts)
1619*4882a593Smuzhiyun 		wacom->num_contacts_left = current_num_contacts;
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 	/* There are at most 5 contacts per packet */
1622*4882a593Smuzhiyun 	contacts_to_send = min(5, wacom->num_contacts_left);
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	for (i = 0; i < contacts_to_send; i++) {
1625*4882a593Smuzhiyun 		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
1626*4882a593Smuzhiyun 		bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
1627*4882a593Smuzhiyun 		int id = get_unaligned_le16(&data[offset + 1]);
1628*4882a593Smuzhiyun 		int slot = input_mt_get_slot_by_key(input, id);
1629*4882a593Smuzhiyun 
1630*4882a593Smuzhiyun 		if (slot < 0)
1631*4882a593Smuzhiyun 			continue;
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 		input_mt_slot(input, slot);
1634*4882a593Smuzhiyun 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
1635*4882a593Smuzhiyun 		if (touch) {
1636*4882a593Smuzhiyun 			int x = get_unaligned_le16(&data[offset + x_offset + 7]);
1637*4882a593Smuzhiyun 			int y = get_unaligned_le16(&data[offset + x_offset + 9]);
1638*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_X, x);
1639*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_Y, y);
1640*4882a593Smuzhiyun 		}
1641*4882a593Smuzhiyun 	}
1642*4882a593Smuzhiyun 	input_mt_sync_frame(input);
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun 	wacom->num_contacts_left -= contacts_to_send;
1645*4882a593Smuzhiyun 	if (wacom->num_contacts_left <= 0) {
1646*4882a593Smuzhiyun 		wacom->num_contacts_left = 0;
1647*4882a593Smuzhiyun 		wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1648*4882a593Smuzhiyun 	}
1649*4882a593Smuzhiyun 	return 1;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun 
wacom_tpc_mt_touch(struct wacom_wac * wacom)1652*4882a593Smuzhiyun static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
1653*4882a593Smuzhiyun {
1654*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
1655*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1656*4882a593Smuzhiyun 	int i;
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
1659*4882a593Smuzhiyun 		int p = data[1] & (1 << i);
1660*4882a593Smuzhiyun 		bool touch = p && report_touch_events(wacom);
1661*4882a593Smuzhiyun 
1662*4882a593Smuzhiyun 		input_mt_slot(input, i);
1663*4882a593Smuzhiyun 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
1664*4882a593Smuzhiyun 		if (touch) {
1665*4882a593Smuzhiyun 			int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff;
1666*4882a593Smuzhiyun 			int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff;
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_X, x);
1669*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_Y, y);
1670*4882a593Smuzhiyun 		}
1671*4882a593Smuzhiyun 	}
1672*4882a593Smuzhiyun 	input_mt_sync_frame(input);
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun 	/* keep touch state for pen event */
1675*4882a593Smuzhiyun 	wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	return 1;
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun 
wacom_tpc_single_touch(struct wacom_wac * wacom,size_t len)1680*4882a593Smuzhiyun static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1683*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
1684*4882a593Smuzhiyun 	bool prox = report_touch_events(wacom);
1685*4882a593Smuzhiyun 	int x = 0, y = 0;
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
1688*4882a593Smuzhiyun 		return 0;
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	if (len == WACOM_PKGLEN_TPC1FG) {
1691*4882a593Smuzhiyun 		prox = prox && (data[0] & 0x01);
1692*4882a593Smuzhiyun 		x = get_unaligned_le16(&data[1]);
1693*4882a593Smuzhiyun 		y = get_unaligned_le16(&data[3]);
1694*4882a593Smuzhiyun 	} else if (len == WACOM_PKGLEN_TPC1FG_B) {
1695*4882a593Smuzhiyun 		prox = prox && (data[2] & 0x01);
1696*4882a593Smuzhiyun 		x = get_unaligned_le16(&data[3]);
1697*4882a593Smuzhiyun 		y = get_unaligned_le16(&data[5]);
1698*4882a593Smuzhiyun 	} else {
1699*4882a593Smuzhiyun 		prox = prox && (data[1] & 0x01);
1700*4882a593Smuzhiyun 		x = le16_to_cpup((__le16 *)&data[2]);
1701*4882a593Smuzhiyun 		y = le16_to_cpup((__le16 *)&data[4]);
1702*4882a593Smuzhiyun 	}
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	if (prox) {
1705*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, x);
1706*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, y);
1707*4882a593Smuzhiyun 	}
1708*4882a593Smuzhiyun 	input_report_key(input, BTN_TOUCH, prox);
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	/* keep touch state for pen events */
1711*4882a593Smuzhiyun 	wacom->shared->touch_down = prox;
1712*4882a593Smuzhiyun 
1713*4882a593Smuzhiyun 	return 1;
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun 
wacom_tpc_pen(struct wacom_wac * wacom)1716*4882a593Smuzhiyun static int wacom_tpc_pen(struct wacom_wac *wacom)
1717*4882a593Smuzhiyun {
1718*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1719*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
1720*4882a593Smuzhiyun 	bool prox = data[1] & 0x20;
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	if (!wacom->shared->stylus_in_proximity) /* first in prox */
1723*4882a593Smuzhiyun 		/* Going into proximity select tool */
1724*4882a593Smuzhiyun 		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	/* keep pen state for touch events */
1727*4882a593Smuzhiyun 	wacom->shared->stylus_in_proximity = prox;
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	/* send pen events only when touch is up or forced out
1730*4882a593Smuzhiyun 	 * or touch arbitration is off
1731*4882a593Smuzhiyun 	 */
1732*4882a593Smuzhiyun 	if (!delay_pen_events(wacom)) {
1733*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, data[1] & 0x02);
1734*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
1735*4882a593Smuzhiyun 		input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
1736*4882a593Smuzhiyun 		input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
1737*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x07) << 8) | data[6]);
1738*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, data[1] & 0x05);
1739*4882a593Smuzhiyun 		input_report_key(input, wacom->tool[0], prox);
1740*4882a593Smuzhiyun 		return 1;
1741*4882a593Smuzhiyun 	}
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 	return 0;
1744*4882a593Smuzhiyun }
1745*4882a593Smuzhiyun 
wacom_tpc_irq(struct wacom_wac * wacom,size_t len)1746*4882a593Smuzhiyun static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
1747*4882a593Smuzhiyun {
1748*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	if (wacom->pen_input) {
1751*4882a593Smuzhiyun 		dev_dbg(wacom->pen_input->dev.parent,
1752*4882a593Smuzhiyun 			"%s: received report #%d\n", __func__, data[0]);
1753*4882a593Smuzhiyun 
1754*4882a593Smuzhiyun 		if (len == WACOM_PKGLEN_PENABLED ||
1755*4882a593Smuzhiyun 		    data[0] == WACOM_REPORT_PENABLED)
1756*4882a593Smuzhiyun 			return wacom_tpc_pen(wacom);
1757*4882a593Smuzhiyun 	}
1758*4882a593Smuzhiyun 	else if (wacom->touch_input) {
1759*4882a593Smuzhiyun 		dev_dbg(wacom->touch_input->dev.parent,
1760*4882a593Smuzhiyun 			"%s: received report #%d\n", __func__, data[0]);
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun 		switch (len) {
1763*4882a593Smuzhiyun 		case WACOM_PKGLEN_TPC1FG:
1764*4882a593Smuzhiyun 			return wacom_tpc_single_touch(wacom, len);
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 		case WACOM_PKGLEN_TPC2FG:
1767*4882a593Smuzhiyun 			return wacom_tpc_mt_touch(wacom);
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 		default:
1770*4882a593Smuzhiyun 			switch (data[0]) {
1771*4882a593Smuzhiyun 			case WACOM_REPORT_TPC1FG:
1772*4882a593Smuzhiyun 			case WACOM_REPORT_TPCHID:
1773*4882a593Smuzhiyun 			case WACOM_REPORT_TPCST:
1774*4882a593Smuzhiyun 			case WACOM_REPORT_TPC1FGE:
1775*4882a593Smuzhiyun 				return wacom_tpc_single_touch(wacom, len);
1776*4882a593Smuzhiyun 
1777*4882a593Smuzhiyun 			case WACOM_REPORT_TPCMT:
1778*4882a593Smuzhiyun 			case WACOM_REPORT_TPCMT2:
1779*4882a593Smuzhiyun 				return wacom_mt_touch(wacom);
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 			}
1782*4882a593Smuzhiyun 		}
1783*4882a593Smuzhiyun 	}
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun 	return 0;
1786*4882a593Smuzhiyun }
1787*4882a593Smuzhiyun 
wacom_offset_rotation(struct input_dev * input,struct hid_usage * usage,int value,int num,int denom)1788*4882a593Smuzhiyun static int wacom_offset_rotation(struct input_dev *input, struct hid_usage *usage,
1789*4882a593Smuzhiyun 				 int value, int num, int denom)
1790*4882a593Smuzhiyun {
1791*4882a593Smuzhiyun 	struct input_absinfo *abs = &input->absinfo[usage->code];
1792*4882a593Smuzhiyun 	int range = (abs->maximum - abs->minimum + 1);
1793*4882a593Smuzhiyun 
1794*4882a593Smuzhiyun 	value += num*range/denom;
1795*4882a593Smuzhiyun 	if (value > abs->maximum)
1796*4882a593Smuzhiyun 		value -= range;
1797*4882a593Smuzhiyun 	else if (value < abs->minimum)
1798*4882a593Smuzhiyun 		value += range;
1799*4882a593Smuzhiyun 	return value;
1800*4882a593Smuzhiyun }
1801*4882a593Smuzhiyun 
wacom_equivalent_usage(int usage)1802*4882a593Smuzhiyun int wacom_equivalent_usage(int usage)
1803*4882a593Smuzhiyun {
1804*4882a593Smuzhiyun 	if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
1805*4882a593Smuzhiyun 		int subpage = (usage & 0xFF00) << 8;
1806*4882a593Smuzhiyun 		int subusage = (usage & 0xFF);
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 		if (subpage == WACOM_HID_SP_PAD ||
1809*4882a593Smuzhiyun 		    subpage == WACOM_HID_SP_BUTTON ||
1810*4882a593Smuzhiyun 		    subpage == WACOM_HID_SP_DIGITIZER ||
1811*4882a593Smuzhiyun 		    subpage == WACOM_HID_SP_DIGITIZERINFO ||
1812*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_SENSE ||
1813*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_SERIALHI ||
1814*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_TOOLTYPE ||
1815*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_DISTANCE ||
1816*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_TOUCHSTRIP ||
1817*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_TOUCHSTRIP2 ||
1818*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_TOUCHRING ||
1819*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_TOUCHRINGSTATUS ||
1820*4882a593Smuzhiyun 		    usage == WACOM_HID_WD_REPORT_VALID) {
1821*4882a593Smuzhiyun 			return usage;
1822*4882a593Smuzhiyun 		}
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 		if (subpage == HID_UP_UNDEFINED)
1825*4882a593Smuzhiyun 			subpage = HID_UP_DIGITIZER;
1826*4882a593Smuzhiyun 
1827*4882a593Smuzhiyun 		return subpage | subusage;
1828*4882a593Smuzhiyun 	}
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun 	if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMTOUCH) {
1831*4882a593Smuzhiyun 		int subpage = (usage & 0xFF00) << 8;
1832*4882a593Smuzhiyun 		int subusage = (usage & 0xFF);
1833*4882a593Smuzhiyun 
1834*4882a593Smuzhiyun 		if (usage == WACOM_HID_WT_REPORT_VALID)
1835*4882a593Smuzhiyun 			return usage;
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun 		if (subpage == HID_UP_UNDEFINED)
1838*4882a593Smuzhiyun 			subpage = WACOM_HID_SP_DIGITIZER;
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 		return subpage | subusage;
1841*4882a593Smuzhiyun 	}
1842*4882a593Smuzhiyun 
1843*4882a593Smuzhiyun 	return usage;
1844*4882a593Smuzhiyun }
1845*4882a593Smuzhiyun 
wacom_map_usage(struct input_dev * input,struct hid_usage * usage,struct hid_field * field,__u8 type,__u16 code,int fuzz)1846*4882a593Smuzhiyun static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
1847*4882a593Smuzhiyun 		struct hid_field *field, __u8 type, __u16 code, int fuzz)
1848*4882a593Smuzhiyun {
1849*4882a593Smuzhiyun 	struct wacom *wacom = input_get_drvdata(input);
1850*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1851*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
1852*4882a593Smuzhiyun 	int fmin = field->logical_minimum;
1853*4882a593Smuzhiyun 	int fmax = field->logical_maximum;
1854*4882a593Smuzhiyun 	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
1855*4882a593Smuzhiyun 	int resolution_code = code;
1856*4882a593Smuzhiyun 
1857*4882a593Smuzhiyun 	if (equivalent_usage == HID_DG_TWIST) {
1858*4882a593Smuzhiyun 		resolution_code = ABS_RZ;
1859*4882a593Smuzhiyun 	}
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun 	if (equivalent_usage == HID_GD_X) {
1862*4882a593Smuzhiyun 		fmin += features->offset_left;
1863*4882a593Smuzhiyun 		fmax -= features->offset_right;
1864*4882a593Smuzhiyun 	}
1865*4882a593Smuzhiyun 	if (equivalent_usage == HID_GD_Y) {
1866*4882a593Smuzhiyun 		fmin += features->offset_top;
1867*4882a593Smuzhiyun 		fmax -= features->offset_bottom;
1868*4882a593Smuzhiyun 	}
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun 	usage->type = type;
1871*4882a593Smuzhiyun 	usage->code = code;
1872*4882a593Smuzhiyun 
1873*4882a593Smuzhiyun 	set_bit(type, input->evbit);
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun 	switch (type) {
1876*4882a593Smuzhiyun 	case EV_ABS:
1877*4882a593Smuzhiyun 		input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
1878*4882a593Smuzhiyun 		input_abs_set_res(input, code,
1879*4882a593Smuzhiyun 				  hidinput_calc_abs_res(field, resolution_code));
1880*4882a593Smuzhiyun 		break;
1881*4882a593Smuzhiyun 	case EV_KEY:
1882*4882a593Smuzhiyun 		input_set_capability(input, EV_KEY, code);
1883*4882a593Smuzhiyun 		break;
1884*4882a593Smuzhiyun 	case EV_MSC:
1885*4882a593Smuzhiyun 		input_set_capability(input, EV_MSC, code);
1886*4882a593Smuzhiyun 		break;
1887*4882a593Smuzhiyun 	case EV_SW:
1888*4882a593Smuzhiyun 		input_set_capability(input, EV_SW, code);
1889*4882a593Smuzhiyun 		break;
1890*4882a593Smuzhiyun 	}
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun 
wacom_wac_battery_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)1893*4882a593Smuzhiyun static void wacom_wac_battery_usage_mapping(struct hid_device *hdev,
1894*4882a593Smuzhiyun 		struct hid_field *field, struct hid_usage *usage)
1895*4882a593Smuzhiyun {
1896*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
1897*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1898*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
1899*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun 	switch (equivalent_usage) {
1902*4882a593Smuzhiyun 	case HID_DG_BATTERYSTRENGTH:
1903*4882a593Smuzhiyun 	case WACOM_HID_WD_BATTERY_LEVEL:
1904*4882a593Smuzhiyun 	case WACOM_HID_WD_BATTERY_CHARGING:
1905*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_BATTERY;
1906*4882a593Smuzhiyun 		break;
1907*4882a593Smuzhiyun 	}
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun 
wacom_wac_battery_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)1910*4882a593Smuzhiyun static void wacom_wac_battery_event(struct hid_device *hdev, struct hid_field *field,
1911*4882a593Smuzhiyun 		struct hid_usage *usage, __s32 value)
1912*4882a593Smuzhiyun {
1913*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
1914*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1915*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
1916*4882a593Smuzhiyun 
1917*4882a593Smuzhiyun 	switch (equivalent_usage) {
1918*4882a593Smuzhiyun 	case HID_DG_BATTERYSTRENGTH:
1919*4882a593Smuzhiyun 		if (value == 0) {
1920*4882a593Smuzhiyun 			wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
1921*4882a593Smuzhiyun 		}
1922*4882a593Smuzhiyun 		else {
1923*4882a593Smuzhiyun 			value = value * 100 / (field->logical_maximum - field->logical_minimum);
1924*4882a593Smuzhiyun 			wacom_wac->hid_data.battery_capacity = value;
1925*4882a593Smuzhiyun 			wacom_wac->hid_data.bat_connected = 1;
1926*4882a593Smuzhiyun 			wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
1927*4882a593Smuzhiyun 		}
1928*4882a593Smuzhiyun 		break;
1929*4882a593Smuzhiyun 	case WACOM_HID_WD_BATTERY_LEVEL:
1930*4882a593Smuzhiyun 		value = value * 100 / (field->logical_maximum - field->logical_minimum);
1931*4882a593Smuzhiyun 		wacom_wac->hid_data.battery_capacity = value;
1932*4882a593Smuzhiyun 		wacom_wac->hid_data.bat_connected = 1;
1933*4882a593Smuzhiyun 		wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
1934*4882a593Smuzhiyun 		break;
1935*4882a593Smuzhiyun 	case WACOM_HID_WD_BATTERY_CHARGING:
1936*4882a593Smuzhiyun 		wacom_wac->hid_data.bat_charging = value;
1937*4882a593Smuzhiyun 		wacom_wac->hid_data.ps_connected = value;
1938*4882a593Smuzhiyun 		wacom_wac->hid_data.bat_connected = 1;
1939*4882a593Smuzhiyun 		wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
1940*4882a593Smuzhiyun 		break;
1941*4882a593Smuzhiyun 	}
1942*4882a593Smuzhiyun }
1943*4882a593Smuzhiyun 
wacom_wac_battery_pre_report(struct hid_device * hdev,struct hid_report * report)1944*4882a593Smuzhiyun static void wacom_wac_battery_pre_report(struct hid_device *hdev,
1945*4882a593Smuzhiyun 		struct hid_report *report)
1946*4882a593Smuzhiyun {
1947*4882a593Smuzhiyun 	return;
1948*4882a593Smuzhiyun }
1949*4882a593Smuzhiyun 
wacom_wac_battery_report(struct hid_device * hdev,struct hid_report * report)1950*4882a593Smuzhiyun static void wacom_wac_battery_report(struct hid_device *hdev,
1951*4882a593Smuzhiyun 		struct hid_report *report)
1952*4882a593Smuzhiyun {
1953*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
1954*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1955*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun 	if (features->quirks & WACOM_QUIRK_BATTERY) {
1958*4882a593Smuzhiyun 		int status = wacom_wac->hid_data.bat_status;
1959*4882a593Smuzhiyun 		int capacity = wacom_wac->hid_data.battery_capacity;
1960*4882a593Smuzhiyun 		bool charging = wacom_wac->hid_data.bat_charging;
1961*4882a593Smuzhiyun 		bool connected = wacom_wac->hid_data.bat_connected;
1962*4882a593Smuzhiyun 		bool powered = wacom_wac->hid_data.ps_connected;
1963*4882a593Smuzhiyun 
1964*4882a593Smuzhiyun 		wacom_notify_battery(wacom_wac, status, capacity, charging,
1965*4882a593Smuzhiyun 				     connected, powered);
1966*4882a593Smuzhiyun 	}
1967*4882a593Smuzhiyun }
1968*4882a593Smuzhiyun 
wacom_wac_pad_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)1969*4882a593Smuzhiyun static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
1970*4882a593Smuzhiyun 		struct hid_field *field, struct hid_usage *usage)
1971*4882a593Smuzhiyun {
1972*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
1973*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1974*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
1975*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->pad_input;
1976*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
1977*4882a593Smuzhiyun 
1978*4882a593Smuzhiyun 	switch (equivalent_usage) {
1979*4882a593Smuzhiyun 	case WACOM_HID_WD_ACCELEROMETER_X:
1980*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
1981*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 0);
1982*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
1983*4882a593Smuzhiyun 		break;
1984*4882a593Smuzhiyun 	case WACOM_HID_WD_ACCELEROMETER_Y:
1985*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
1986*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 0);
1987*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
1988*4882a593Smuzhiyun 		break;
1989*4882a593Smuzhiyun 	case WACOM_HID_WD_ACCELEROMETER_Z:
1990*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
1991*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
1992*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
1993*4882a593Smuzhiyun 		break;
1994*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONCENTER:
1995*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONHOME:
1996*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONUP:
1997*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONDOWN:
1998*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONLEFT:
1999*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONRIGHT:
2000*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY,
2001*4882a593Smuzhiyun 				wacom_numbered_button_to_key(features->numbered_buttons),
2002*4882a593Smuzhiyun 				0);
2003*4882a593Smuzhiyun 		features->numbered_buttons++;
2004*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2005*4882a593Smuzhiyun 		break;
2006*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHONOFF:
2007*4882a593Smuzhiyun 	case WACOM_HID_WD_MUTE_DEVICE:
2008*4882a593Smuzhiyun 		/*
2009*4882a593Smuzhiyun 		 * This usage, which is used to mute touch events, comes
2010*4882a593Smuzhiyun 		 * from the pad packet, but is reported on the touch
2011*4882a593Smuzhiyun 		 * interface. Because the touch interface may not have
2012*4882a593Smuzhiyun 		 * been created yet, we cannot call wacom_map_usage(). In
2013*4882a593Smuzhiyun 		 * order to process this usage when we receive it, we set
2014*4882a593Smuzhiyun 		 * the usage type and code directly.
2015*4882a593Smuzhiyun 		 */
2016*4882a593Smuzhiyun 		wacom_wac->has_mute_touch_switch = true;
2017*4882a593Smuzhiyun 		usage->type = EV_SW;
2018*4882a593Smuzhiyun 		usage->code = SW_MUTE_DEVICE;
2019*4882a593Smuzhiyun 		break;
2020*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHSTRIP:
2021*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0);
2022*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2023*4882a593Smuzhiyun 		break;
2024*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHSTRIP2:
2025*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_RY, 0);
2026*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2027*4882a593Smuzhiyun 		break;
2028*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHRING:
2029*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
2030*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2031*4882a593Smuzhiyun 		break;
2032*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHRINGSTATUS:
2033*4882a593Smuzhiyun 		/*
2034*4882a593Smuzhiyun 		 * Only set up type/code association. Completely mapping
2035*4882a593Smuzhiyun 		 * this usage may overwrite the axis resolution and range.
2036*4882a593Smuzhiyun 		 */
2037*4882a593Smuzhiyun 		usage->type = EV_ABS;
2038*4882a593Smuzhiyun 		usage->code = ABS_WHEEL;
2039*4882a593Smuzhiyun 		set_bit(EV_ABS, input->evbit);
2040*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2041*4882a593Smuzhiyun 		break;
2042*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONCONFIG:
2043*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
2044*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2045*4882a593Smuzhiyun 		break;
2046*4882a593Smuzhiyun 	case WACOM_HID_WD_ONSCREEN_KEYBOARD:
2047*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
2048*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2049*4882a593Smuzhiyun 		break;
2050*4882a593Smuzhiyun 	case WACOM_HID_WD_CONTROLPANEL:
2051*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
2052*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2053*4882a593Smuzhiyun 		break;
2054*4882a593Smuzhiyun 	case WACOM_HID_WD_MODE_CHANGE:
2055*4882a593Smuzhiyun 		/* do not overwrite previous data */
2056*4882a593Smuzhiyun 		if (!wacom_wac->has_mode_change) {
2057*4882a593Smuzhiyun 			wacom_wac->has_mode_change = true;
2058*4882a593Smuzhiyun 			wacom_wac->is_direct_mode = true;
2059*4882a593Smuzhiyun 		}
2060*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2061*4882a593Smuzhiyun 		break;
2062*4882a593Smuzhiyun 	}
2063*4882a593Smuzhiyun 
2064*4882a593Smuzhiyun 	switch (equivalent_usage & 0xfffffff0) {
2065*4882a593Smuzhiyun 	case WACOM_HID_WD_EXPRESSKEY00:
2066*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY,
2067*4882a593Smuzhiyun 				wacom_numbered_button_to_key(features->numbered_buttons),
2068*4882a593Smuzhiyun 				0);
2069*4882a593Smuzhiyun 		features->numbered_buttons++;
2070*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
2071*4882a593Smuzhiyun 		break;
2072*4882a593Smuzhiyun 	}
2073*4882a593Smuzhiyun }
2074*4882a593Smuzhiyun 
wacom_wac_pad_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2075*4882a593Smuzhiyun static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field,
2076*4882a593Smuzhiyun 		struct hid_usage *usage, __s32 value)
2077*4882a593Smuzhiyun {
2078*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2079*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2080*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->pad_input;
2081*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
2082*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
2083*4882a593Smuzhiyun 	int i;
2084*4882a593Smuzhiyun 	bool do_report = false;
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	/*
2087*4882a593Smuzhiyun 	 * Avoid reporting this event and setting inrange_state if this usage
2088*4882a593Smuzhiyun 	 * hasn't been mapped.
2089*4882a593Smuzhiyun 	 */
2090*4882a593Smuzhiyun 	if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
2091*4882a593Smuzhiyun 		return;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 	if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
2094*4882a593Smuzhiyun 		if (usage->hid != WACOM_HID_WD_TOUCHRING)
2095*4882a593Smuzhiyun 			wacom_wac->hid_data.inrange_state |= value;
2096*4882a593Smuzhiyun 	}
2097*4882a593Smuzhiyun 
2098*4882a593Smuzhiyun 	/* Process touch switch state first since it is reported through touch interface,
2099*4882a593Smuzhiyun 	 * which is indepentent of pad interface. In the case when there are no other pad
2100*4882a593Smuzhiyun 	 * events, the pad interface will not even be created.
2101*4882a593Smuzhiyun 	 */
2102*4882a593Smuzhiyun 	if ((equivalent_usage == WACOM_HID_WD_MUTE_DEVICE) ||
2103*4882a593Smuzhiyun 	   (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)) {
2104*4882a593Smuzhiyun 		if (wacom_wac->shared->touch_input) {
2105*4882a593Smuzhiyun 			bool *is_touch_on = &wacom_wac->shared->is_touch_on;
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun 			if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value)
2108*4882a593Smuzhiyun 				*is_touch_on = !(*is_touch_on);
2109*4882a593Smuzhiyun 			else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)
2110*4882a593Smuzhiyun 				*is_touch_on = value;
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun 			input_report_switch(wacom_wac->shared->touch_input,
2113*4882a593Smuzhiyun 					    SW_MUTE_DEVICE, !(*is_touch_on));
2114*4882a593Smuzhiyun 			input_sync(wacom_wac->shared->touch_input);
2115*4882a593Smuzhiyun 		}
2116*4882a593Smuzhiyun 		return;
2117*4882a593Smuzhiyun 	}
2118*4882a593Smuzhiyun 
2119*4882a593Smuzhiyun 	if (!input)
2120*4882a593Smuzhiyun 		return;
2121*4882a593Smuzhiyun 
2122*4882a593Smuzhiyun 	switch (equivalent_usage) {
2123*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHRING:
2124*4882a593Smuzhiyun 		/*
2125*4882a593Smuzhiyun 		 * Userspace expects touchrings to increase in value with
2126*4882a593Smuzhiyun 		 * clockwise gestures and have their zero point at the
2127*4882a593Smuzhiyun 		 * tablet's left. HID events "should" be clockwise-
2128*4882a593Smuzhiyun 		 * increasing and zero at top, though the MobileStudio
2129*4882a593Smuzhiyun 		 * Pro and 2nd-gen Intuos Pro don't do this...
2130*4882a593Smuzhiyun 		 */
2131*4882a593Smuzhiyun 		if (hdev->vendor == 0x56a &&
2132*4882a593Smuzhiyun 		    (hdev->product == 0x34d || hdev->product == 0x34e ||  /* MobileStudio Pro */
2133*4882a593Smuzhiyun 		     hdev->product == 0x357 || hdev->product == 0x358 ||  /* Intuos Pro 2 */
2134*4882a593Smuzhiyun 		     hdev->product == 0x392 ||				  /* Intuos Pro 2 */
2135*4882a593Smuzhiyun 		     hdev->product == 0x398 || hdev->product == 0x399 ||  /* MobileStudio Pro */
2136*4882a593Smuzhiyun 		     hdev->product == 0x3AA)) {				  /* MobileStudio Pro */
2137*4882a593Smuzhiyun 			value = (field->logical_maximum - value);
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 			if (hdev->product == 0x357 || hdev->product == 0x358 ||
2140*4882a593Smuzhiyun 			    hdev->product == 0x392)
2141*4882a593Smuzhiyun 				value = wacom_offset_rotation(input, usage, value, 3, 16);
2142*4882a593Smuzhiyun 			else if (hdev->product == 0x34d || hdev->product == 0x34e ||
2143*4882a593Smuzhiyun 				 hdev->product == 0x398 || hdev->product == 0x399 ||
2144*4882a593Smuzhiyun 				 hdev->product == 0x3AA)
2145*4882a593Smuzhiyun 				value = wacom_offset_rotation(input, usage, value, 1, 2);
2146*4882a593Smuzhiyun 		}
2147*4882a593Smuzhiyun 		else {
2148*4882a593Smuzhiyun 			value = wacom_offset_rotation(input, usage, value, 1, 4);
2149*4882a593Smuzhiyun 		}
2150*4882a593Smuzhiyun 		do_report = true;
2151*4882a593Smuzhiyun 		break;
2152*4882a593Smuzhiyun 	case WACOM_HID_WD_TOUCHRINGSTATUS:
2153*4882a593Smuzhiyun 		if (!value)
2154*4882a593Smuzhiyun 			input_event(input, usage->type, usage->code, 0);
2155*4882a593Smuzhiyun 		break;
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	case WACOM_HID_WD_MODE_CHANGE:
2158*4882a593Smuzhiyun 		if (wacom_wac->is_direct_mode != value) {
2159*4882a593Smuzhiyun 			wacom_wac->is_direct_mode = value;
2160*4882a593Smuzhiyun 			wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
2161*4882a593Smuzhiyun 		}
2162*4882a593Smuzhiyun 		break;
2163*4882a593Smuzhiyun 
2164*4882a593Smuzhiyun 	case WACOM_HID_WD_BUTTONCENTER:
2165*4882a593Smuzhiyun 		for (i = 0; i < wacom->led.count; i++)
2166*4882a593Smuzhiyun 			wacom_update_led(wacom, features->numbered_buttons,
2167*4882a593Smuzhiyun 					 value, i);
2168*4882a593Smuzhiyun 		fallthrough;
2169*4882a593Smuzhiyun 	default:
2170*4882a593Smuzhiyun 		do_report = true;
2171*4882a593Smuzhiyun 		break;
2172*4882a593Smuzhiyun 	}
2173*4882a593Smuzhiyun 
2174*4882a593Smuzhiyun 	if (do_report) {
2175*4882a593Smuzhiyun 		input_event(input, usage->type, usage->code, value);
2176*4882a593Smuzhiyun 		if (value)
2177*4882a593Smuzhiyun 			wacom_wac->hid_data.pad_input_event_flag = true;
2178*4882a593Smuzhiyun 	}
2179*4882a593Smuzhiyun }
2180*4882a593Smuzhiyun 
wacom_wac_pad_pre_report(struct hid_device * hdev,struct hid_report * report)2181*4882a593Smuzhiyun static void wacom_wac_pad_pre_report(struct hid_device *hdev,
2182*4882a593Smuzhiyun 		struct hid_report *report)
2183*4882a593Smuzhiyun {
2184*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2185*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2186*4882a593Smuzhiyun 
2187*4882a593Smuzhiyun 	wacom_wac->hid_data.inrange_state = 0;
2188*4882a593Smuzhiyun }
2189*4882a593Smuzhiyun 
wacom_wac_pad_report(struct hid_device * hdev,struct hid_report * report,struct hid_field * field)2190*4882a593Smuzhiyun static void wacom_wac_pad_report(struct hid_device *hdev,
2191*4882a593Smuzhiyun 		struct hid_report *report, struct hid_field *field)
2192*4882a593Smuzhiyun {
2193*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2194*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2195*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->pad_input;
2196*4882a593Smuzhiyun 	bool active = wacom_wac->hid_data.inrange_state != 0;
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	/* report prox for expresskey events */
2199*4882a593Smuzhiyun 	if (wacom_wac->hid_data.pad_input_event_flag) {
2200*4882a593Smuzhiyun 		input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
2201*4882a593Smuzhiyun 		input_sync(input);
2202*4882a593Smuzhiyun 		if (!active)
2203*4882a593Smuzhiyun 			wacom_wac->hid_data.pad_input_event_flag = false;
2204*4882a593Smuzhiyun 	}
2205*4882a593Smuzhiyun }
2206*4882a593Smuzhiyun 
wacom_wac_pen_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)2207*4882a593Smuzhiyun static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
2208*4882a593Smuzhiyun 		struct hid_field *field, struct hid_usage *usage)
2209*4882a593Smuzhiyun {
2210*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2211*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2212*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
2213*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->pen_input;
2214*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun 	switch (equivalent_usage) {
2217*4882a593Smuzhiyun 	case HID_GD_X:
2218*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
2219*4882a593Smuzhiyun 		break;
2220*4882a593Smuzhiyun 	case HID_GD_Y:
2221*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
2222*4882a593Smuzhiyun 		break;
2223*4882a593Smuzhiyun 	case WACOM_HID_WD_DISTANCE:
2224*4882a593Smuzhiyun 	case HID_GD_Z:
2225*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_DISTANCE, 0);
2226*4882a593Smuzhiyun 		break;
2227*4882a593Smuzhiyun 	case HID_DG_TIPPRESSURE:
2228*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_PRESSURE, 0);
2229*4882a593Smuzhiyun 		break;
2230*4882a593Smuzhiyun 	case HID_DG_INRANGE:
2231*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
2232*4882a593Smuzhiyun 		break;
2233*4882a593Smuzhiyun 	case HID_DG_INVERT:
2234*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY,
2235*4882a593Smuzhiyun 				BTN_TOOL_RUBBER, 0);
2236*4882a593Smuzhiyun 		break;
2237*4882a593Smuzhiyun 	case HID_DG_TILT_X:
2238*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_TILT_X, 0);
2239*4882a593Smuzhiyun 		break;
2240*4882a593Smuzhiyun 	case HID_DG_TILT_Y:
2241*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_TILT_Y, 0);
2242*4882a593Smuzhiyun 		break;
2243*4882a593Smuzhiyun 	case HID_DG_TWIST:
2244*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
2245*4882a593Smuzhiyun 		break;
2246*4882a593Smuzhiyun 	case HID_DG_ERASER:
2247*4882a593Smuzhiyun 	case HID_DG_TIPSWITCH:
2248*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
2249*4882a593Smuzhiyun 		break;
2250*4882a593Smuzhiyun 	case HID_DG_BARRELSWITCH:
2251*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS, 0);
2252*4882a593Smuzhiyun 		break;
2253*4882a593Smuzhiyun 	case HID_DG_BARRELSWITCH2:
2254*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0);
2255*4882a593Smuzhiyun 		break;
2256*4882a593Smuzhiyun 	case HID_DG_TOOLSERIALNUMBER:
2257*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_TOOLSERIAL;
2258*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
2259*4882a593Smuzhiyun 		break;
2260*4882a593Smuzhiyun 	case WACOM_HID_WD_SENSE:
2261*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_SENSE;
2262*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
2263*4882a593Smuzhiyun 		break;
2264*4882a593Smuzhiyun 	case WACOM_HID_WD_SERIALHI:
2265*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0);
2266*4882a593Smuzhiyun 
2267*4882a593Smuzhiyun 		if (!(features->quirks & WACOM_QUIRK_AESPEN)) {
2268*4882a593Smuzhiyun 			set_bit(EV_KEY, input->evbit);
2269*4882a593Smuzhiyun 			input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
2270*4882a593Smuzhiyun 			input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
2271*4882a593Smuzhiyun 			input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
2272*4882a593Smuzhiyun 			input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
2273*4882a593Smuzhiyun 			input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
2274*4882a593Smuzhiyun 			if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
2275*4882a593Smuzhiyun 				input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
2276*4882a593Smuzhiyun 				input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
2277*4882a593Smuzhiyun 			}
2278*4882a593Smuzhiyun 		}
2279*4882a593Smuzhiyun 		break;
2280*4882a593Smuzhiyun 	case WACOM_HID_WD_FINGERWHEEL:
2281*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
2282*4882a593Smuzhiyun 		break;
2283*4882a593Smuzhiyun 	}
2284*4882a593Smuzhiyun }
2285*4882a593Smuzhiyun 
wacom_wac_pen_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2286*4882a593Smuzhiyun static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
2287*4882a593Smuzhiyun 		struct hid_usage *usage, __s32 value)
2288*4882a593Smuzhiyun {
2289*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2290*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2291*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
2292*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->pen_input;
2293*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 	if (wacom_wac->is_invalid_bt_frame)
2296*4882a593Smuzhiyun 		return;
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	switch (equivalent_usage) {
2299*4882a593Smuzhiyun 	case HID_GD_Z:
2300*4882a593Smuzhiyun 		/*
2301*4882a593Smuzhiyun 		 * HID_GD_Z "should increase as the control's position is
2302*4882a593Smuzhiyun 		 * moved from high to low", while ABS_DISTANCE instead
2303*4882a593Smuzhiyun 		 * increases in value as the tool moves from low to high.
2304*4882a593Smuzhiyun 		 */
2305*4882a593Smuzhiyun 		value = field->logical_maximum - value;
2306*4882a593Smuzhiyun 		break;
2307*4882a593Smuzhiyun 	case HID_DG_INRANGE:
2308*4882a593Smuzhiyun 		wacom_wac->hid_data.inrange_state = value;
2309*4882a593Smuzhiyun 		if (!(features->quirks & WACOM_QUIRK_SENSE))
2310*4882a593Smuzhiyun 			wacom_wac->hid_data.sense_state = value;
2311*4882a593Smuzhiyun 		return;
2312*4882a593Smuzhiyun 	case HID_DG_INVERT:
2313*4882a593Smuzhiyun 		wacom_wac->hid_data.invert_state = value;
2314*4882a593Smuzhiyun 		return;
2315*4882a593Smuzhiyun 	case HID_DG_ERASER:
2316*4882a593Smuzhiyun 	case HID_DG_TIPSWITCH:
2317*4882a593Smuzhiyun 		wacom_wac->hid_data.tipswitch |= value;
2318*4882a593Smuzhiyun 		return;
2319*4882a593Smuzhiyun 	case HID_DG_BARRELSWITCH:
2320*4882a593Smuzhiyun 		wacom_wac->hid_data.barrelswitch = value;
2321*4882a593Smuzhiyun 		return;
2322*4882a593Smuzhiyun 	case HID_DG_BARRELSWITCH2:
2323*4882a593Smuzhiyun 		wacom_wac->hid_data.barrelswitch2 = value;
2324*4882a593Smuzhiyun 		return;
2325*4882a593Smuzhiyun 	case HID_DG_TOOLSERIALNUMBER:
2326*4882a593Smuzhiyun 		if (value) {
2327*4882a593Smuzhiyun 			wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
2328*4882a593Smuzhiyun 			wacom_wac->serial[0] |= wacom_s32tou(value, field->report_size);
2329*4882a593Smuzhiyun 		}
2330*4882a593Smuzhiyun 		return;
2331*4882a593Smuzhiyun 	case HID_DG_TWIST:
2332*4882a593Smuzhiyun 		/* don't modify the value if the pen doesn't support the feature */
2333*4882a593Smuzhiyun 		if (!wacom_is_art_pen(wacom_wac->id[0])) return;
2334*4882a593Smuzhiyun 
2335*4882a593Smuzhiyun 		/*
2336*4882a593Smuzhiyun 		 * Userspace expects pen twist to have its zero point when
2337*4882a593Smuzhiyun 		 * the buttons/finger is on the tablet's left. HID values
2338*4882a593Smuzhiyun 		 * are zero when buttons are toward the top.
2339*4882a593Smuzhiyun 		 */
2340*4882a593Smuzhiyun 		value = wacom_offset_rotation(input, usage, value, 1, 4);
2341*4882a593Smuzhiyun 		break;
2342*4882a593Smuzhiyun 	case WACOM_HID_WD_SENSE:
2343*4882a593Smuzhiyun 		wacom_wac->hid_data.sense_state = value;
2344*4882a593Smuzhiyun 		return;
2345*4882a593Smuzhiyun 	case WACOM_HID_WD_SERIALHI:
2346*4882a593Smuzhiyun 		if (value) {
2347*4882a593Smuzhiyun 			__u32 raw_value = wacom_s32tou(value, field->report_size);
2348*4882a593Smuzhiyun 
2349*4882a593Smuzhiyun 			wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
2350*4882a593Smuzhiyun 			wacom_wac->serial[0] |= ((__u64)raw_value) << 32;
2351*4882a593Smuzhiyun 			/*
2352*4882a593Smuzhiyun 			 * Non-USI EMR devices may contain additional tool type
2353*4882a593Smuzhiyun 			 * information here. See WACOM_HID_WD_TOOLTYPE case for
2354*4882a593Smuzhiyun 			 * more details.
2355*4882a593Smuzhiyun 			 */
2356*4882a593Smuzhiyun 			if (value >> 20 == 1) {
2357*4882a593Smuzhiyun 				wacom_wac->id[0] |= raw_value & 0xFFFFF;
2358*4882a593Smuzhiyun 			}
2359*4882a593Smuzhiyun 		}
2360*4882a593Smuzhiyun 		return;
2361*4882a593Smuzhiyun 	case WACOM_HID_WD_TOOLTYPE:
2362*4882a593Smuzhiyun 		/*
2363*4882a593Smuzhiyun 		 * Some devices (MobileStudio Pro, and possibly later
2364*4882a593Smuzhiyun 		 * devices as well) do not return the complete tool
2365*4882a593Smuzhiyun 		 * type in their WACOM_HID_WD_TOOLTYPE usage. Use a
2366*4882a593Smuzhiyun 		 * bitwise OR so the complete value can be built
2367*4882a593Smuzhiyun 		 * up over time :(
2368*4882a593Smuzhiyun 		 */
2369*4882a593Smuzhiyun 		wacom_wac->id[0] |= wacom_s32tou(value, field->report_size);
2370*4882a593Smuzhiyun 		return;
2371*4882a593Smuzhiyun 	case WACOM_HID_WD_OFFSETLEFT:
2372*4882a593Smuzhiyun 		if (features->offset_left && value != features->offset_left)
2373*4882a593Smuzhiyun 			hid_warn(hdev, "%s: overriding existing left offset "
2374*4882a593Smuzhiyun 				 "%d -> %d\n", __func__, value,
2375*4882a593Smuzhiyun 				 features->offset_left);
2376*4882a593Smuzhiyun 		features->offset_left = value;
2377*4882a593Smuzhiyun 		return;
2378*4882a593Smuzhiyun 	case WACOM_HID_WD_OFFSETRIGHT:
2379*4882a593Smuzhiyun 		if (features->offset_right && value != features->offset_right)
2380*4882a593Smuzhiyun 			hid_warn(hdev, "%s: overriding existing right offset "
2381*4882a593Smuzhiyun 				 "%d -> %d\n", __func__, value,
2382*4882a593Smuzhiyun 				 features->offset_right);
2383*4882a593Smuzhiyun 		features->offset_right = value;
2384*4882a593Smuzhiyun 		return;
2385*4882a593Smuzhiyun 	case WACOM_HID_WD_OFFSETTOP:
2386*4882a593Smuzhiyun 		if (features->offset_top && value != features->offset_top)
2387*4882a593Smuzhiyun 			hid_warn(hdev, "%s: overriding existing top offset "
2388*4882a593Smuzhiyun 				 "%d -> %d\n", __func__, value,
2389*4882a593Smuzhiyun 				 features->offset_top);
2390*4882a593Smuzhiyun 		features->offset_top = value;
2391*4882a593Smuzhiyun 		return;
2392*4882a593Smuzhiyun 	case WACOM_HID_WD_OFFSETBOTTOM:
2393*4882a593Smuzhiyun 		if (features->offset_bottom && value != features->offset_bottom)
2394*4882a593Smuzhiyun 			hid_warn(hdev, "%s: overriding existing bottom offset "
2395*4882a593Smuzhiyun 				 "%d -> %d\n", __func__, value,
2396*4882a593Smuzhiyun 				 features->offset_bottom);
2397*4882a593Smuzhiyun 		features->offset_bottom = value;
2398*4882a593Smuzhiyun 		return;
2399*4882a593Smuzhiyun 	case WACOM_HID_WD_REPORT_VALID:
2400*4882a593Smuzhiyun 		wacom_wac->is_invalid_bt_frame = !value;
2401*4882a593Smuzhiyun 		return;
2402*4882a593Smuzhiyun 	}
2403*4882a593Smuzhiyun 
2404*4882a593Smuzhiyun 	/* send pen events only when touch is up or forced out
2405*4882a593Smuzhiyun 	 * or touch arbitration is off
2406*4882a593Smuzhiyun 	 */
2407*4882a593Smuzhiyun 	if (!usage->type || delay_pen_events(wacom_wac))
2408*4882a593Smuzhiyun 		return;
2409*4882a593Smuzhiyun 
2410*4882a593Smuzhiyun 	/* send pen events only when the pen is in range */
2411*4882a593Smuzhiyun 	if (wacom_wac->hid_data.inrange_state)
2412*4882a593Smuzhiyun 		input_event(input, usage->type, usage->code, value);
2413*4882a593Smuzhiyun 	else if (wacom_wac->shared->stylus_in_proximity && !wacom_wac->hid_data.sense_state)
2414*4882a593Smuzhiyun 		input_event(input, usage->type, usage->code, 0);
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun 
wacom_wac_pen_pre_report(struct hid_device * hdev,struct hid_report * report)2417*4882a593Smuzhiyun static void wacom_wac_pen_pre_report(struct hid_device *hdev,
2418*4882a593Smuzhiyun 		struct hid_report *report)
2419*4882a593Smuzhiyun {
2420*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2421*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2422*4882a593Smuzhiyun 
2423*4882a593Smuzhiyun 	wacom_wac->is_invalid_bt_frame = false;
2424*4882a593Smuzhiyun 	return;
2425*4882a593Smuzhiyun }
2426*4882a593Smuzhiyun 
wacom_wac_pen_report(struct hid_device * hdev,struct hid_report * report)2427*4882a593Smuzhiyun static void wacom_wac_pen_report(struct hid_device *hdev,
2428*4882a593Smuzhiyun 		struct hid_report *report)
2429*4882a593Smuzhiyun {
2430*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2431*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2432*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->pen_input;
2433*4882a593Smuzhiyun 	bool range = wacom_wac->hid_data.inrange_state;
2434*4882a593Smuzhiyun 	bool sense = wacom_wac->hid_data.sense_state;
2435*4882a593Smuzhiyun 
2436*4882a593Smuzhiyun 	if (wacom_wac->is_invalid_bt_frame)
2437*4882a593Smuzhiyun 		return;
2438*4882a593Smuzhiyun 
2439*4882a593Smuzhiyun 	if (!wacom_wac->tool[0] && range) { /* first in range */
2440*4882a593Smuzhiyun 		/* Going into range select tool */
2441*4882a593Smuzhiyun 		if (wacom_wac->hid_data.invert_state)
2442*4882a593Smuzhiyun 			wacom_wac->tool[0] = BTN_TOOL_RUBBER;
2443*4882a593Smuzhiyun 		else if (wacom_wac->id[0])
2444*4882a593Smuzhiyun 			wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]);
2445*4882a593Smuzhiyun 		else
2446*4882a593Smuzhiyun 			wacom_wac->tool[0] = BTN_TOOL_PEN;
2447*4882a593Smuzhiyun 	}
2448*4882a593Smuzhiyun 
2449*4882a593Smuzhiyun 	/* keep pen state for touch events */
2450*4882a593Smuzhiyun 	wacom_wac->shared->stylus_in_proximity = sense;
2451*4882a593Smuzhiyun 
2452*4882a593Smuzhiyun 	if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
2453*4882a593Smuzhiyun 		int id = wacom_wac->id[0];
2454*4882a593Smuzhiyun 		int sw_state = wacom_wac->hid_data.barrelswitch |
2455*4882a593Smuzhiyun 			       (wacom_wac->hid_data.barrelswitch2 << 1);
2456*4882a593Smuzhiyun 
2457*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, sw_state == 1);
2458*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, sw_state == 2);
2459*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS3, sw_state == 3);
2460*4882a593Smuzhiyun 
2461*4882a593Smuzhiyun 		/*
2462*4882a593Smuzhiyun 		 * Non-USI EMR tools should have their IDs mangled to
2463*4882a593Smuzhiyun 		 * match the legacy behavior of wacom_intuos_general
2464*4882a593Smuzhiyun 		 */
2465*4882a593Smuzhiyun 		if (wacom_wac->serial[0] >> 52 == 1)
2466*4882a593Smuzhiyun 			id = wacom_intuos_id_mangle(id);
2467*4882a593Smuzhiyun 
2468*4882a593Smuzhiyun 		/*
2469*4882a593Smuzhiyun 		 * To ensure compatibility with xf86-input-wacom, we should
2470*4882a593Smuzhiyun 		 * report the BTN_TOOL_* event prior to the ABS_MISC or
2471*4882a593Smuzhiyun 		 * MSC_SERIAL events.
2472*4882a593Smuzhiyun 		 */
2473*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH,
2474*4882a593Smuzhiyun 				wacom_wac->hid_data.tipswitch);
2475*4882a593Smuzhiyun 		input_report_key(input, wacom_wac->tool[0], sense);
2476*4882a593Smuzhiyun 		if (wacom_wac->serial[0]) {
2477*4882a593Smuzhiyun 			input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
2478*4882a593Smuzhiyun 			input_report_abs(input, ABS_MISC, sense ? id : 0);
2479*4882a593Smuzhiyun 		}
2480*4882a593Smuzhiyun 
2481*4882a593Smuzhiyun 		wacom_wac->hid_data.tipswitch = false;
2482*4882a593Smuzhiyun 
2483*4882a593Smuzhiyun 		input_sync(input);
2484*4882a593Smuzhiyun 	}
2485*4882a593Smuzhiyun 
2486*4882a593Smuzhiyun 	if (!sense) {
2487*4882a593Smuzhiyun 		wacom_wac->tool[0] = 0;
2488*4882a593Smuzhiyun 		wacom_wac->id[0] = 0;
2489*4882a593Smuzhiyun 		wacom_wac->serial[0] = 0;
2490*4882a593Smuzhiyun 	}
2491*4882a593Smuzhiyun }
2492*4882a593Smuzhiyun 
wacom_wac_finger_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)2493*4882a593Smuzhiyun static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
2494*4882a593Smuzhiyun 		struct hid_field *field, struct hid_usage *usage)
2495*4882a593Smuzhiyun {
2496*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2497*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2498*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->touch_input;
2499*4882a593Smuzhiyun 	unsigned touch_max = wacom_wac->features.touch_max;
2500*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
2501*4882a593Smuzhiyun 
2502*4882a593Smuzhiyun 	switch (equivalent_usage) {
2503*4882a593Smuzhiyun 	case HID_GD_X:
2504*4882a593Smuzhiyun 		if (touch_max == 1)
2505*4882a593Smuzhiyun 			wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
2506*4882a593Smuzhiyun 		else
2507*4882a593Smuzhiyun 			wacom_map_usage(input, usage, field, EV_ABS,
2508*4882a593Smuzhiyun 					ABS_MT_POSITION_X, 4);
2509*4882a593Smuzhiyun 		break;
2510*4882a593Smuzhiyun 	case HID_GD_Y:
2511*4882a593Smuzhiyun 		if (touch_max == 1)
2512*4882a593Smuzhiyun 			wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
2513*4882a593Smuzhiyun 		else
2514*4882a593Smuzhiyun 			wacom_map_usage(input, usage, field, EV_ABS,
2515*4882a593Smuzhiyun 					ABS_MT_POSITION_Y, 4);
2516*4882a593Smuzhiyun 		break;
2517*4882a593Smuzhiyun 	case HID_DG_WIDTH:
2518*4882a593Smuzhiyun 	case HID_DG_HEIGHT:
2519*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
2520*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
2521*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
2522*4882a593Smuzhiyun 		break;
2523*4882a593Smuzhiyun 	case HID_DG_TIPSWITCH:
2524*4882a593Smuzhiyun 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
2525*4882a593Smuzhiyun 		break;
2526*4882a593Smuzhiyun 	case HID_DG_CONTACTCOUNT:
2527*4882a593Smuzhiyun 		wacom_wac->hid_data.cc_report = field->report->id;
2528*4882a593Smuzhiyun 		wacom_wac->hid_data.cc_index = field->index;
2529*4882a593Smuzhiyun 		wacom_wac->hid_data.cc_value_index = usage->usage_index;
2530*4882a593Smuzhiyun 		break;
2531*4882a593Smuzhiyun 	case HID_DG_CONTACTID:
2532*4882a593Smuzhiyun 		if ((field->logical_maximum - field->logical_minimum) < touch_max) {
2533*4882a593Smuzhiyun 			/*
2534*4882a593Smuzhiyun 			 * The HID descriptor for G11 sensors leaves logical
2535*4882a593Smuzhiyun 			 * maximum set to '1' despite it being a multitouch
2536*4882a593Smuzhiyun 			 * device. Override to a sensible number.
2537*4882a593Smuzhiyun 			 */
2538*4882a593Smuzhiyun 			field->logical_maximum = 255;
2539*4882a593Smuzhiyun 		}
2540*4882a593Smuzhiyun 		break;
2541*4882a593Smuzhiyun 	}
2542*4882a593Smuzhiyun }
2543*4882a593Smuzhiyun 
wacom_wac_finger_slot(struct wacom_wac * wacom_wac,struct input_dev * input)2544*4882a593Smuzhiyun static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
2545*4882a593Smuzhiyun 		struct input_dev *input)
2546*4882a593Smuzhiyun {
2547*4882a593Smuzhiyun 	struct hid_data *hid_data = &wacom_wac->hid_data;
2548*4882a593Smuzhiyun 	bool mt = wacom_wac->features.touch_max > 1;
2549*4882a593Smuzhiyun 	bool prox = hid_data->tipswitch &&
2550*4882a593Smuzhiyun 		    report_touch_events(wacom_wac);
2551*4882a593Smuzhiyun 
2552*4882a593Smuzhiyun 	if (wacom_wac->shared->has_mute_touch_switch &&
2553*4882a593Smuzhiyun 	    !wacom_wac->shared->is_touch_on) {
2554*4882a593Smuzhiyun 		if (!wacom_wac->shared->touch_down)
2555*4882a593Smuzhiyun 			return;
2556*4882a593Smuzhiyun 		prox = false;
2557*4882a593Smuzhiyun 	}
2558*4882a593Smuzhiyun 
2559*4882a593Smuzhiyun 	wacom_wac->hid_data.num_received++;
2560*4882a593Smuzhiyun 	if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
2561*4882a593Smuzhiyun 		return;
2562*4882a593Smuzhiyun 
2563*4882a593Smuzhiyun 	if (mt) {
2564*4882a593Smuzhiyun 		int slot;
2565*4882a593Smuzhiyun 
2566*4882a593Smuzhiyun 		slot = input_mt_get_slot_by_key(input, hid_data->id);
2567*4882a593Smuzhiyun 		input_mt_slot(input, slot);
2568*4882a593Smuzhiyun 		input_mt_report_slot_state(input, MT_TOOL_FINGER, prox);
2569*4882a593Smuzhiyun 	}
2570*4882a593Smuzhiyun 	else {
2571*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, prox);
2572*4882a593Smuzhiyun 	}
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun 	if (prox) {
2575*4882a593Smuzhiyun 		input_report_abs(input, mt ? ABS_MT_POSITION_X : ABS_X,
2576*4882a593Smuzhiyun 				 hid_data->x);
2577*4882a593Smuzhiyun 		input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y,
2578*4882a593Smuzhiyun 				 hid_data->y);
2579*4882a593Smuzhiyun 
2580*4882a593Smuzhiyun 		if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) {
2581*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height));
2582*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height));
2583*4882a593Smuzhiyun 			if (hid_data->width != hid_data->height)
2584*4882a593Smuzhiyun 				input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1);
2585*4882a593Smuzhiyun 		}
2586*4882a593Smuzhiyun 	}
2587*4882a593Smuzhiyun }
2588*4882a593Smuzhiyun 
wacom_wac_slot_is_active(struct input_dev * dev,int key)2589*4882a593Smuzhiyun static bool wacom_wac_slot_is_active(struct input_dev *dev, int key)
2590*4882a593Smuzhiyun {
2591*4882a593Smuzhiyun 	struct input_mt *mt = dev->mt;
2592*4882a593Smuzhiyun 	struct input_mt_slot *s;
2593*4882a593Smuzhiyun 
2594*4882a593Smuzhiyun 	if (!mt)
2595*4882a593Smuzhiyun 		return false;
2596*4882a593Smuzhiyun 
2597*4882a593Smuzhiyun 	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
2598*4882a593Smuzhiyun 		if (s->key == key &&
2599*4882a593Smuzhiyun 			input_mt_get_value(s, ABS_MT_TRACKING_ID) >= 0) {
2600*4882a593Smuzhiyun 			return true;
2601*4882a593Smuzhiyun 		}
2602*4882a593Smuzhiyun 	}
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	return false;
2605*4882a593Smuzhiyun }
2606*4882a593Smuzhiyun 
wacom_wac_finger_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2607*4882a593Smuzhiyun static void wacom_wac_finger_event(struct hid_device *hdev,
2608*4882a593Smuzhiyun 		struct hid_field *field, struct hid_usage *usage, __s32 value)
2609*4882a593Smuzhiyun {
2610*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2611*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2612*4882a593Smuzhiyun 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
2613*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->wacom_wac.features;
2614*4882a593Smuzhiyun 
2615*4882a593Smuzhiyun 	if (wacom_wac->is_invalid_bt_frame)
2616*4882a593Smuzhiyun 		return;
2617*4882a593Smuzhiyun 
2618*4882a593Smuzhiyun 	switch (equivalent_usage) {
2619*4882a593Smuzhiyun 	case HID_DG_CONFIDENCE:
2620*4882a593Smuzhiyun 		wacom_wac->hid_data.confidence = value;
2621*4882a593Smuzhiyun 		break;
2622*4882a593Smuzhiyun 	case HID_GD_X:
2623*4882a593Smuzhiyun 		wacom_wac->hid_data.x = value;
2624*4882a593Smuzhiyun 		break;
2625*4882a593Smuzhiyun 	case HID_GD_Y:
2626*4882a593Smuzhiyun 		wacom_wac->hid_data.y = value;
2627*4882a593Smuzhiyun 		break;
2628*4882a593Smuzhiyun 	case HID_DG_WIDTH:
2629*4882a593Smuzhiyun 		wacom_wac->hid_data.width = value;
2630*4882a593Smuzhiyun 		break;
2631*4882a593Smuzhiyun 	case HID_DG_HEIGHT:
2632*4882a593Smuzhiyun 		wacom_wac->hid_data.height = value;
2633*4882a593Smuzhiyun 		break;
2634*4882a593Smuzhiyun 	case HID_DG_CONTACTID:
2635*4882a593Smuzhiyun 		wacom_wac->hid_data.id = value;
2636*4882a593Smuzhiyun 		break;
2637*4882a593Smuzhiyun 	case HID_DG_TIPSWITCH:
2638*4882a593Smuzhiyun 		wacom_wac->hid_data.tipswitch = value;
2639*4882a593Smuzhiyun 		break;
2640*4882a593Smuzhiyun 	case WACOM_HID_WT_REPORT_VALID:
2641*4882a593Smuzhiyun 		wacom_wac->is_invalid_bt_frame = !value;
2642*4882a593Smuzhiyun 		return;
2643*4882a593Smuzhiyun 	case HID_DG_CONTACTMAX:
2644*4882a593Smuzhiyun 		if (!features->touch_max) {
2645*4882a593Smuzhiyun 			features->touch_max = value;
2646*4882a593Smuzhiyun 		} else {
2647*4882a593Smuzhiyun 			hid_warn(hdev, "%s: ignoring attempt to overwrite non-zero touch_max "
2648*4882a593Smuzhiyun 				 "%d -> %d\n", __func__, features->touch_max, value);
2649*4882a593Smuzhiyun 		}
2650*4882a593Smuzhiyun 		return;
2651*4882a593Smuzhiyun 	}
2652*4882a593Smuzhiyun 
2653*4882a593Smuzhiyun 	if (usage->usage_index + 1 == field->report_count) {
2654*4882a593Smuzhiyun 		if (equivalent_usage == wacom_wac->hid_data.last_slot_field) {
2655*4882a593Smuzhiyun 			bool touch_removed = wacom_wac_slot_is_active(wacom_wac->touch_input,
2656*4882a593Smuzhiyun 				wacom_wac->hid_data.id) && !wacom_wac->hid_data.tipswitch;
2657*4882a593Smuzhiyun 
2658*4882a593Smuzhiyun 			if (wacom_wac->hid_data.confidence || touch_removed) {
2659*4882a593Smuzhiyun 				wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
2660*4882a593Smuzhiyun 			}
2661*4882a593Smuzhiyun 		}
2662*4882a593Smuzhiyun 	}
2663*4882a593Smuzhiyun }
2664*4882a593Smuzhiyun 
wacom_wac_finger_pre_report(struct hid_device * hdev,struct hid_report * report)2665*4882a593Smuzhiyun static void wacom_wac_finger_pre_report(struct hid_device *hdev,
2666*4882a593Smuzhiyun 		struct hid_report *report)
2667*4882a593Smuzhiyun {
2668*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2669*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2670*4882a593Smuzhiyun 	struct hid_data* hid_data = &wacom_wac->hid_data;
2671*4882a593Smuzhiyun 	int i;
2672*4882a593Smuzhiyun 
2673*4882a593Smuzhiyun 	wacom_wac->is_invalid_bt_frame = false;
2674*4882a593Smuzhiyun 
2675*4882a593Smuzhiyun 	hid_data->confidence = true;
2676*4882a593Smuzhiyun 
2677*4882a593Smuzhiyun 	hid_data->cc_report = 0;
2678*4882a593Smuzhiyun 	hid_data->cc_index = -1;
2679*4882a593Smuzhiyun 	hid_data->cc_value_index = -1;
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	for (i = 0; i < report->maxfield; i++) {
2682*4882a593Smuzhiyun 		struct hid_field *field = report->field[i];
2683*4882a593Smuzhiyun 		int j;
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 		for (j = 0; j < field->maxusage; j++) {
2686*4882a593Smuzhiyun 			struct hid_usage *usage = &field->usage[j];
2687*4882a593Smuzhiyun 			unsigned int equivalent_usage =
2688*4882a593Smuzhiyun 				wacom_equivalent_usage(usage->hid);
2689*4882a593Smuzhiyun 
2690*4882a593Smuzhiyun 			switch (equivalent_usage) {
2691*4882a593Smuzhiyun 			case HID_GD_X:
2692*4882a593Smuzhiyun 			case HID_GD_Y:
2693*4882a593Smuzhiyun 			case HID_DG_WIDTH:
2694*4882a593Smuzhiyun 			case HID_DG_HEIGHT:
2695*4882a593Smuzhiyun 			case HID_DG_CONTACTID:
2696*4882a593Smuzhiyun 			case HID_DG_INRANGE:
2697*4882a593Smuzhiyun 			case HID_DG_INVERT:
2698*4882a593Smuzhiyun 			case HID_DG_TIPSWITCH:
2699*4882a593Smuzhiyun 				hid_data->last_slot_field = equivalent_usage;
2700*4882a593Smuzhiyun 				break;
2701*4882a593Smuzhiyun 			case HID_DG_CONTACTCOUNT:
2702*4882a593Smuzhiyun 				hid_data->cc_report = report->id;
2703*4882a593Smuzhiyun 				hid_data->cc_index = i;
2704*4882a593Smuzhiyun 				hid_data->cc_value_index = j;
2705*4882a593Smuzhiyun 				break;
2706*4882a593Smuzhiyun 			}
2707*4882a593Smuzhiyun 		}
2708*4882a593Smuzhiyun 	}
2709*4882a593Smuzhiyun 
2710*4882a593Smuzhiyun 	if (hid_data->cc_report != 0 &&
2711*4882a593Smuzhiyun 	    hid_data->cc_index >= 0) {
2712*4882a593Smuzhiyun 		struct hid_field *field = report->field[hid_data->cc_index];
2713*4882a593Smuzhiyun 		int value = field->value[hid_data->cc_value_index];
2714*4882a593Smuzhiyun 		if (value) {
2715*4882a593Smuzhiyun 			hid_data->num_expected = value;
2716*4882a593Smuzhiyun 			hid_data->num_received = 0;
2717*4882a593Smuzhiyun 		}
2718*4882a593Smuzhiyun 	}
2719*4882a593Smuzhiyun 	else {
2720*4882a593Smuzhiyun 		hid_data->num_expected = wacom_wac->features.touch_max;
2721*4882a593Smuzhiyun 		hid_data->num_received = 0;
2722*4882a593Smuzhiyun 	}
2723*4882a593Smuzhiyun }
2724*4882a593Smuzhiyun 
wacom_wac_finger_report(struct hid_device * hdev,struct hid_report * report)2725*4882a593Smuzhiyun static void wacom_wac_finger_report(struct hid_device *hdev,
2726*4882a593Smuzhiyun 		struct hid_report *report)
2727*4882a593Smuzhiyun {
2728*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2729*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2730*4882a593Smuzhiyun 	struct input_dev *input = wacom_wac->touch_input;
2731*4882a593Smuzhiyun 	unsigned touch_max = wacom_wac->features.touch_max;
2732*4882a593Smuzhiyun 
2733*4882a593Smuzhiyun 	/* If more packets of data are expected, give us a chance to
2734*4882a593Smuzhiyun 	 * process them rather than immediately syncing a partial
2735*4882a593Smuzhiyun 	 * update.
2736*4882a593Smuzhiyun 	 */
2737*4882a593Smuzhiyun 	if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected)
2738*4882a593Smuzhiyun 		return;
2739*4882a593Smuzhiyun 
2740*4882a593Smuzhiyun 	if (touch_max > 1)
2741*4882a593Smuzhiyun 		input_mt_sync_frame(input);
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun 	input_sync(input);
2744*4882a593Smuzhiyun 	wacom_wac->hid_data.num_received = 0;
2745*4882a593Smuzhiyun 	wacom_wac->hid_data.num_expected = 0;
2746*4882a593Smuzhiyun 
2747*4882a593Smuzhiyun 	/* keep touch state for pen event */
2748*4882a593Smuzhiyun 	wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
2749*4882a593Smuzhiyun }
2750*4882a593Smuzhiyun 
wacom_wac_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)2751*4882a593Smuzhiyun void wacom_wac_usage_mapping(struct hid_device *hdev,
2752*4882a593Smuzhiyun 		struct hid_field *field, struct hid_usage *usage)
2753*4882a593Smuzhiyun {
2754*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2755*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2756*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
2757*4882a593Smuzhiyun 
2758*4882a593Smuzhiyun 	if (WACOM_DIRECT_DEVICE(field))
2759*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_DIRECT;
2760*4882a593Smuzhiyun 
2761*4882a593Smuzhiyun 	/* usage tests must precede field tests */
2762*4882a593Smuzhiyun 	if (WACOM_BATTERY_USAGE(usage))
2763*4882a593Smuzhiyun 		wacom_wac_battery_usage_mapping(hdev, field, usage);
2764*4882a593Smuzhiyun 	else if (WACOM_PAD_FIELD(field))
2765*4882a593Smuzhiyun 		wacom_wac_pad_usage_mapping(hdev, field, usage);
2766*4882a593Smuzhiyun 	else if (WACOM_PEN_FIELD(field))
2767*4882a593Smuzhiyun 		wacom_wac_pen_usage_mapping(hdev, field, usage);
2768*4882a593Smuzhiyun 	else if (WACOM_FINGER_FIELD(field))
2769*4882a593Smuzhiyun 		wacom_wac_finger_usage_mapping(hdev, field, usage);
2770*4882a593Smuzhiyun }
2771*4882a593Smuzhiyun 
wacom_wac_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2772*4882a593Smuzhiyun void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
2773*4882a593Smuzhiyun 		struct hid_usage *usage, __s32 value)
2774*4882a593Smuzhiyun {
2775*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2776*4882a593Smuzhiyun 
2777*4882a593Smuzhiyun 	if (wacom->wacom_wac.features.type != HID_GENERIC)
2778*4882a593Smuzhiyun 		return;
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	if (value > field->logical_maximum || value < field->logical_minimum)
2781*4882a593Smuzhiyun 		return;
2782*4882a593Smuzhiyun 
2783*4882a593Smuzhiyun 	/* usage tests must precede field tests */
2784*4882a593Smuzhiyun 	if (WACOM_BATTERY_USAGE(usage))
2785*4882a593Smuzhiyun 		wacom_wac_battery_event(hdev, field, usage, value);
2786*4882a593Smuzhiyun 	else if (WACOM_PAD_FIELD(field))
2787*4882a593Smuzhiyun 		wacom_wac_pad_event(hdev, field, usage, value);
2788*4882a593Smuzhiyun 	else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
2789*4882a593Smuzhiyun 		wacom_wac_pen_event(hdev, field, usage, value);
2790*4882a593Smuzhiyun 	else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
2791*4882a593Smuzhiyun 		wacom_wac_finger_event(hdev, field, usage, value);
2792*4882a593Smuzhiyun }
2793*4882a593Smuzhiyun 
wacom_report_events(struct hid_device * hdev,struct hid_report * report,int collection_index,int field_index)2794*4882a593Smuzhiyun static void wacom_report_events(struct hid_device *hdev,
2795*4882a593Smuzhiyun 				struct hid_report *report, int collection_index,
2796*4882a593Smuzhiyun 				int field_index)
2797*4882a593Smuzhiyun {
2798*4882a593Smuzhiyun 	int r;
2799*4882a593Smuzhiyun 
2800*4882a593Smuzhiyun 	for (r = field_index; r < report->maxfield; r++) {
2801*4882a593Smuzhiyun 		struct hid_field *field;
2802*4882a593Smuzhiyun 		unsigned count, n;
2803*4882a593Smuzhiyun 
2804*4882a593Smuzhiyun 		field = report->field[r];
2805*4882a593Smuzhiyun 		count = field->report_count;
2806*4882a593Smuzhiyun 
2807*4882a593Smuzhiyun 		if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
2808*4882a593Smuzhiyun 			continue;
2809*4882a593Smuzhiyun 
2810*4882a593Smuzhiyun 		for (n = 0 ; n < count; n++) {
2811*4882a593Smuzhiyun 			if (field->usage[n].collection_index == collection_index)
2812*4882a593Smuzhiyun 				wacom_wac_event(hdev, field, &field->usage[n],
2813*4882a593Smuzhiyun 						field->value[n]);
2814*4882a593Smuzhiyun 			else
2815*4882a593Smuzhiyun 				return;
2816*4882a593Smuzhiyun 		}
2817*4882a593Smuzhiyun 	}
2818*4882a593Smuzhiyun }
2819*4882a593Smuzhiyun 
wacom_wac_collection(struct hid_device * hdev,struct hid_report * report,int collection_index,struct hid_field * field,int field_index)2820*4882a593Smuzhiyun static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
2821*4882a593Smuzhiyun 			 int collection_index, struct hid_field *field,
2822*4882a593Smuzhiyun 			 int field_index)
2823*4882a593Smuzhiyun {
2824*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2825*4882a593Smuzhiyun 
2826*4882a593Smuzhiyun 	wacom_report_events(hdev, report, collection_index, field_index);
2827*4882a593Smuzhiyun 
2828*4882a593Smuzhiyun 	/*
2829*4882a593Smuzhiyun 	 * Non-input reports may be sent prior to the device being
2830*4882a593Smuzhiyun 	 * completely initialized. Since only their events need
2831*4882a593Smuzhiyun 	 * to be processed, exit after 'wacom_report_events' has
2832*4882a593Smuzhiyun 	 * been called to prevent potential crashes in the report-
2833*4882a593Smuzhiyun 	 * processing functions.
2834*4882a593Smuzhiyun 	 */
2835*4882a593Smuzhiyun 	if (report->type != HID_INPUT_REPORT)
2836*4882a593Smuzhiyun 		return -1;
2837*4882a593Smuzhiyun 
2838*4882a593Smuzhiyun 	if (WACOM_PAD_FIELD(field))
2839*4882a593Smuzhiyun 		return 0;
2840*4882a593Smuzhiyun 	else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
2841*4882a593Smuzhiyun 		wacom_wac_pen_report(hdev, report);
2842*4882a593Smuzhiyun 	else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
2843*4882a593Smuzhiyun 		wacom_wac_finger_report(hdev, report);
2844*4882a593Smuzhiyun 
2845*4882a593Smuzhiyun 	return 0;
2846*4882a593Smuzhiyun }
2847*4882a593Smuzhiyun 
wacom_wac_report(struct hid_device * hdev,struct hid_report * report)2848*4882a593Smuzhiyun void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
2849*4882a593Smuzhiyun {
2850*4882a593Smuzhiyun 	struct wacom *wacom = hid_get_drvdata(hdev);
2851*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2852*4882a593Smuzhiyun 	struct hid_field *field;
2853*4882a593Smuzhiyun 	bool pad_in_hid_field = false, pen_in_hid_field = false,
2854*4882a593Smuzhiyun 		finger_in_hid_field = false, true_pad = false;
2855*4882a593Smuzhiyun 	int r;
2856*4882a593Smuzhiyun 	int prev_collection = -1;
2857*4882a593Smuzhiyun 
2858*4882a593Smuzhiyun 	if (wacom_wac->features.type != HID_GENERIC)
2859*4882a593Smuzhiyun 		return;
2860*4882a593Smuzhiyun 
2861*4882a593Smuzhiyun 	for (r = 0; r < report->maxfield; r++) {
2862*4882a593Smuzhiyun 		field = report->field[r];
2863*4882a593Smuzhiyun 
2864*4882a593Smuzhiyun 		if (WACOM_PAD_FIELD(field))
2865*4882a593Smuzhiyun 			pad_in_hid_field = true;
2866*4882a593Smuzhiyun 		if (WACOM_PEN_FIELD(field))
2867*4882a593Smuzhiyun 			pen_in_hid_field = true;
2868*4882a593Smuzhiyun 		if (WACOM_FINGER_FIELD(field))
2869*4882a593Smuzhiyun 			finger_in_hid_field = true;
2870*4882a593Smuzhiyun 		if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY)
2871*4882a593Smuzhiyun 			true_pad = true;
2872*4882a593Smuzhiyun 	}
2873*4882a593Smuzhiyun 
2874*4882a593Smuzhiyun 	wacom_wac_battery_pre_report(hdev, report);
2875*4882a593Smuzhiyun 
2876*4882a593Smuzhiyun 	if (pad_in_hid_field && wacom->wacom_wac.pad_input)
2877*4882a593Smuzhiyun 		wacom_wac_pad_pre_report(hdev, report);
2878*4882a593Smuzhiyun 	if (pen_in_hid_field && wacom->wacom_wac.pen_input)
2879*4882a593Smuzhiyun 		wacom_wac_pen_pre_report(hdev, report);
2880*4882a593Smuzhiyun 	if (finger_in_hid_field && wacom->wacom_wac.touch_input)
2881*4882a593Smuzhiyun 		wacom_wac_finger_pre_report(hdev, report);
2882*4882a593Smuzhiyun 
2883*4882a593Smuzhiyun 	for (r = 0; r < report->maxfield; r++) {
2884*4882a593Smuzhiyun 		field = report->field[r];
2885*4882a593Smuzhiyun 
2886*4882a593Smuzhiyun 		if (field->usage[0].collection_index != prev_collection) {
2887*4882a593Smuzhiyun 			if (wacom_wac_collection(hdev, report,
2888*4882a593Smuzhiyun 				field->usage[0].collection_index, field, r) < 0)
2889*4882a593Smuzhiyun 				return;
2890*4882a593Smuzhiyun 			prev_collection = field->usage[0].collection_index;
2891*4882a593Smuzhiyun 		}
2892*4882a593Smuzhiyun 	}
2893*4882a593Smuzhiyun 
2894*4882a593Smuzhiyun 	wacom_wac_battery_report(hdev, report);
2895*4882a593Smuzhiyun 
2896*4882a593Smuzhiyun 	if (true_pad && wacom->wacom_wac.pad_input)
2897*4882a593Smuzhiyun 		wacom_wac_pad_report(hdev, report, field);
2898*4882a593Smuzhiyun }
2899*4882a593Smuzhiyun 
wacom_bpt_touch(struct wacom_wac * wacom)2900*4882a593Smuzhiyun static int wacom_bpt_touch(struct wacom_wac *wacom)
2901*4882a593Smuzhiyun {
2902*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
2903*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
2904*4882a593Smuzhiyun 	struct input_dev *pad_input = wacom->pad_input;
2905*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
2906*4882a593Smuzhiyun 	int i;
2907*4882a593Smuzhiyun 
2908*4882a593Smuzhiyun 	if (data[0] != 0x02)
2909*4882a593Smuzhiyun 	    return 0;
2910*4882a593Smuzhiyun 
2911*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
2912*4882a593Smuzhiyun 		int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
2913*4882a593Smuzhiyun 		bool touch = report_touch_events(wacom)
2914*4882a593Smuzhiyun 			   && (data[offset + 3] & 0x80);
2915*4882a593Smuzhiyun 
2916*4882a593Smuzhiyun 		input_mt_slot(input, i);
2917*4882a593Smuzhiyun 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
2918*4882a593Smuzhiyun 		if (touch) {
2919*4882a593Smuzhiyun 			int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
2920*4882a593Smuzhiyun 			int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
2921*4882a593Smuzhiyun 			if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
2922*4882a593Smuzhiyun 				x <<= 5;
2923*4882a593Smuzhiyun 				y <<= 5;
2924*4882a593Smuzhiyun 			}
2925*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_X, x);
2926*4882a593Smuzhiyun 			input_report_abs(input, ABS_MT_POSITION_Y, y);
2927*4882a593Smuzhiyun 		}
2928*4882a593Smuzhiyun 	}
2929*4882a593Smuzhiyun 
2930*4882a593Smuzhiyun 	input_mt_sync_frame(input);
2931*4882a593Smuzhiyun 
2932*4882a593Smuzhiyun 	input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
2933*4882a593Smuzhiyun 	input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
2934*4882a593Smuzhiyun 	input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
2935*4882a593Smuzhiyun 	input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
2936*4882a593Smuzhiyun 	wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
2937*4882a593Smuzhiyun 
2938*4882a593Smuzhiyun 	return 1;
2939*4882a593Smuzhiyun }
2940*4882a593Smuzhiyun 
wacom_bpt3_touch_msg(struct wacom_wac * wacom,unsigned char * data)2941*4882a593Smuzhiyun static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
2942*4882a593Smuzhiyun {
2943*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
2944*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
2945*4882a593Smuzhiyun 	bool touch = data[1] & 0x80;
2946*4882a593Smuzhiyun 	int slot = input_mt_get_slot_by_key(input, data[0]);
2947*4882a593Smuzhiyun 
2948*4882a593Smuzhiyun 	if (slot < 0)
2949*4882a593Smuzhiyun 		return;
2950*4882a593Smuzhiyun 
2951*4882a593Smuzhiyun 	touch = touch && report_touch_events(wacom);
2952*4882a593Smuzhiyun 
2953*4882a593Smuzhiyun 	input_mt_slot(input, slot);
2954*4882a593Smuzhiyun 	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
2955*4882a593Smuzhiyun 
2956*4882a593Smuzhiyun 	if (touch) {
2957*4882a593Smuzhiyun 		int x = (data[2] << 4) | (data[4] >> 4);
2958*4882a593Smuzhiyun 		int y = (data[3] << 4) | (data[4] & 0x0f);
2959*4882a593Smuzhiyun 		int width, height;
2960*4882a593Smuzhiyun 
2961*4882a593Smuzhiyun 		if (features->type >= INTUOSPS && features->type <= INTUOSHT2) {
2962*4882a593Smuzhiyun 			width  = data[5] * 100;
2963*4882a593Smuzhiyun 			height = data[6] * 100;
2964*4882a593Smuzhiyun 		} else {
2965*4882a593Smuzhiyun 			/*
2966*4882a593Smuzhiyun 			 * "a" is a scaled-down area which we assume is
2967*4882a593Smuzhiyun 			 * roughly circular and which can be described as:
2968*4882a593Smuzhiyun 			 * a=(pi*r^2)/C.
2969*4882a593Smuzhiyun 			 */
2970*4882a593Smuzhiyun 			int a = data[5];
2971*4882a593Smuzhiyun 			int x_res = input_abs_get_res(input, ABS_MT_POSITION_X);
2972*4882a593Smuzhiyun 			int y_res = input_abs_get_res(input, ABS_MT_POSITION_Y);
2973*4882a593Smuzhiyun 			width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
2974*4882a593Smuzhiyun 			height = width * y_res / x_res;
2975*4882a593Smuzhiyun 		}
2976*4882a593Smuzhiyun 
2977*4882a593Smuzhiyun 		input_report_abs(input, ABS_MT_POSITION_X, x);
2978*4882a593Smuzhiyun 		input_report_abs(input, ABS_MT_POSITION_Y, y);
2979*4882a593Smuzhiyun 		input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
2980*4882a593Smuzhiyun 		input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
2981*4882a593Smuzhiyun 	}
2982*4882a593Smuzhiyun }
2983*4882a593Smuzhiyun 
wacom_bpt3_button_msg(struct wacom_wac * wacom,unsigned char * data)2984*4882a593Smuzhiyun static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
2985*4882a593Smuzhiyun {
2986*4882a593Smuzhiyun 	struct input_dev *input = wacom->pad_input;
2987*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
2988*4882a593Smuzhiyun 
2989*4882a593Smuzhiyun 	if (features->type == INTUOSHT || features->type == INTUOSHT2) {
2990*4882a593Smuzhiyun 		input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
2991*4882a593Smuzhiyun 		input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
2992*4882a593Smuzhiyun 	} else {
2993*4882a593Smuzhiyun 		input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
2994*4882a593Smuzhiyun 		input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
2995*4882a593Smuzhiyun 	}
2996*4882a593Smuzhiyun 	input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
2997*4882a593Smuzhiyun 	input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
2998*4882a593Smuzhiyun }
2999*4882a593Smuzhiyun 
wacom_bpt3_touch(struct wacom_wac * wacom)3000*4882a593Smuzhiyun static int wacom_bpt3_touch(struct wacom_wac *wacom)
3001*4882a593Smuzhiyun {
3002*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
3003*4882a593Smuzhiyun 	int count = data[1] & 0x07;
3004*4882a593Smuzhiyun 	int  touch_changed = 0, i;
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun 	if (data[0] != 0x02)
3007*4882a593Smuzhiyun 	    return 0;
3008*4882a593Smuzhiyun 
3009*4882a593Smuzhiyun 	/* data has up to 7 fixed sized 8-byte messages starting at data[2] */
3010*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
3011*4882a593Smuzhiyun 		int offset = (8 * i) + 2;
3012*4882a593Smuzhiyun 		int msg_id = data[offset];
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun 		if (msg_id >= 2 && msg_id <= 17) {
3015*4882a593Smuzhiyun 			wacom_bpt3_touch_msg(wacom, data + offset);
3016*4882a593Smuzhiyun 			touch_changed++;
3017*4882a593Smuzhiyun 		} else if (msg_id == 128)
3018*4882a593Smuzhiyun 			wacom_bpt3_button_msg(wacom, data + offset);
3019*4882a593Smuzhiyun 
3020*4882a593Smuzhiyun 	}
3021*4882a593Smuzhiyun 
3022*4882a593Smuzhiyun 	/* only update touch if we actually have a touchpad and touch data changed */
3023*4882a593Smuzhiyun 	if (wacom->touch_input && touch_changed) {
3024*4882a593Smuzhiyun 		input_mt_sync_frame(wacom->touch_input);
3025*4882a593Smuzhiyun 		wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
3026*4882a593Smuzhiyun 	}
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun 	return 1;
3029*4882a593Smuzhiyun }
3030*4882a593Smuzhiyun 
wacom_bpt_pen(struct wacom_wac * wacom)3031*4882a593Smuzhiyun static int wacom_bpt_pen(struct wacom_wac *wacom)
3032*4882a593Smuzhiyun {
3033*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
3034*4882a593Smuzhiyun 	struct input_dev *input = wacom->pen_input;
3035*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
3036*4882a593Smuzhiyun 	int x = 0, y = 0, p = 0, d = 0;
3037*4882a593Smuzhiyun 	bool pen = false, btn1 = false, btn2 = false;
3038*4882a593Smuzhiyun 	bool range, prox, rdy;
3039*4882a593Smuzhiyun 
3040*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_PENABLED)
3041*4882a593Smuzhiyun 	    return 0;
3042*4882a593Smuzhiyun 
3043*4882a593Smuzhiyun 	range = (data[1] & 0x80) == 0x80;
3044*4882a593Smuzhiyun 	prox = (data[1] & 0x40) == 0x40;
3045*4882a593Smuzhiyun 	rdy = (data[1] & 0x20) == 0x20;
3046*4882a593Smuzhiyun 
3047*4882a593Smuzhiyun 	wacom->shared->stylus_in_proximity = range;
3048*4882a593Smuzhiyun 	if (delay_pen_events(wacom))
3049*4882a593Smuzhiyun 		return 0;
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 	if (rdy) {
3052*4882a593Smuzhiyun 		p = le16_to_cpup((__le16 *)&data[6]);
3053*4882a593Smuzhiyun 		pen = data[1] & 0x01;
3054*4882a593Smuzhiyun 		btn1 = data[1] & 0x02;
3055*4882a593Smuzhiyun 		btn2 = data[1] & 0x04;
3056*4882a593Smuzhiyun 	}
3057*4882a593Smuzhiyun 	if (prox) {
3058*4882a593Smuzhiyun 		x = le16_to_cpup((__le16 *)&data[2]);
3059*4882a593Smuzhiyun 		y = le16_to_cpup((__le16 *)&data[4]);
3060*4882a593Smuzhiyun 
3061*4882a593Smuzhiyun 		if (data[1] & 0x08) {
3062*4882a593Smuzhiyun 			wacom->tool[0] = BTN_TOOL_RUBBER;
3063*4882a593Smuzhiyun 			wacom->id[0] = ERASER_DEVICE_ID;
3064*4882a593Smuzhiyun 		} else {
3065*4882a593Smuzhiyun 			wacom->tool[0] = BTN_TOOL_PEN;
3066*4882a593Smuzhiyun 			wacom->id[0] = STYLUS_DEVICE_ID;
3067*4882a593Smuzhiyun 		}
3068*4882a593Smuzhiyun 		wacom->reporting_data = true;
3069*4882a593Smuzhiyun 	}
3070*4882a593Smuzhiyun 	if (range) {
3071*4882a593Smuzhiyun 		/*
3072*4882a593Smuzhiyun 		 * Convert distance from out prox to distance from tablet.
3073*4882a593Smuzhiyun 		 * distance will be greater than distance_max once
3074*4882a593Smuzhiyun 		 * touching and applying pressure; do not report negative
3075*4882a593Smuzhiyun 		 * distance.
3076*4882a593Smuzhiyun 		 */
3077*4882a593Smuzhiyun 		if (data[8] <= features->distance_max)
3078*4882a593Smuzhiyun 			d = features->distance_max - data[8];
3079*4882a593Smuzhiyun 	} else {
3080*4882a593Smuzhiyun 		wacom->id[0] = 0;
3081*4882a593Smuzhiyun 	}
3082*4882a593Smuzhiyun 
3083*4882a593Smuzhiyun 	if (wacom->reporting_data) {
3084*4882a593Smuzhiyun 		input_report_key(input, BTN_TOUCH, pen);
3085*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS, btn1);
3086*4882a593Smuzhiyun 		input_report_key(input, BTN_STYLUS2, btn2);
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 		if (prox || !range) {
3089*4882a593Smuzhiyun 			input_report_abs(input, ABS_X, x);
3090*4882a593Smuzhiyun 			input_report_abs(input, ABS_Y, y);
3091*4882a593Smuzhiyun 		}
3092*4882a593Smuzhiyun 		input_report_abs(input, ABS_PRESSURE, p);
3093*4882a593Smuzhiyun 		input_report_abs(input, ABS_DISTANCE, d);
3094*4882a593Smuzhiyun 
3095*4882a593Smuzhiyun 		input_report_key(input, wacom->tool[0], range); /* PEN or RUBBER */
3096*4882a593Smuzhiyun 		input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
3097*4882a593Smuzhiyun 	}
3098*4882a593Smuzhiyun 
3099*4882a593Smuzhiyun 	if (!range) {
3100*4882a593Smuzhiyun 		wacom->reporting_data = false;
3101*4882a593Smuzhiyun 	}
3102*4882a593Smuzhiyun 
3103*4882a593Smuzhiyun 	return 1;
3104*4882a593Smuzhiyun }
3105*4882a593Smuzhiyun 
wacom_bpt_irq(struct wacom_wac * wacom,size_t len)3106*4882a593Smuzhiyun static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
3107*4882a593Smuzhiyun {
3108*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->features;
3109*4882a593Smuzhiyun 
3110*4882a593Smuzhiyun 	if ((features->type == INTUOSHT2) &&
3111*4882a593Smuzhiyun 	    (features->device_type & WACOM_DEVICETYPE_PEN))
3112*4882a593Smuzhiyun 		return wacom_intuos_irq(wacom);
3113*4882a593Smuzhiyun 	else if (len == WACOM_PKGLEN_BBTOUCH)
3114*4882a593Smuzhiyun 		return wacom_bpt_touch(wacom);
3115*4882a593Smuzhiyun 	else if (len == WACOM_PKGLEN_BBTOUCH3)
3116*4882a593Smuzhiyun 		return wacom_bpt3_touch(wacom);
3117*4882a593Smuzhiyun 	else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN)
3118*4882a593Smuzhiyun 		return wacom_bpt_pen(wacom);
3119*4882a593Smuzhiyun 
3120*4882a593Smuzhiyun 	return 0;
3121*4882a593Smuzhiyun }
3122*4882a593Smuzhiyun 
wacom_bamboo_pad_pen_event(struct wacom_wac * wacom,unsigned char * data)3123*4882a593Smuzhiyun static void wacom_bamboo_pad_pen_event(struct wacom_wac *wacom,
3124*4882a593Smuzhiyun 		unsigned char *data)
3125*4882a593Smuzhiyun {
3126*4882a593Smuzhiyun 	unsigned char prefix;
3127*4882a593Smuzhiyun 
3128*4882a593Smuzhiyun 	/*
3129*4882a593Smuzhiyun 	 * We need to reroute the event from the debug interface to the
3130*4882a593Smuzhiyun 	 * pen interface.
3131*4882a593Smuzhiyun 	 * We need to add the report ID to the actual pen report, so we
3132*4882a593Smuzhiyun 	 * temporary overwrite the first byte to prevent having to kzalloc/kfree
3133*4882a593Smuzhiyun 	 * and memcpy the report.
3134*4882a593Smuzhiyun 	 */
3135*4882a593Smuzhiyun 	prefix = data[0];
3136*4882a593Smuzhiyun 	data[0] = WACOM_REPORT_BPAD_PEN;
3137*4882a593Smuzhiyun 
3138*4882a593Smuzhiyun 	/*
3139*4882a593Smuzhiyun 	 * actually reroute the event.
3140*4882a593Smuzhiyun 	 * No need to check if wacom->shared->pen is valid, hid_input_report()
3141*4882a593Smuzhiyun 	 * will check for us.
3142*4882a593Smuzhiyun 	 */
3143*4882a593Smuzhiyun 	hid_input_report(wacom->shared->pen, HID_INPUT_REPORT, data,
3144*4882a593Smuzhiyun 			 WACOM_PKGLEN_PENABLED, 1);
3145*4882a593Smuzhiyun 
3146*4882a593Smuzhiyun 	data[0] = prefix;
3147*4882a593Smuzhiyun }
3148*4882a593Smuzhiyun 
wacom_bamboo_pad_touch_event(struct wacom_wac * wacom,unsigned char * data)3149*4882a593Smuzhiyun static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
3150*4882a593Smuzhiyun 		unsigned char *data)
3151*4882a593Smuzhiyun {
3152*4882a593Smuzhiyun 	struct input_dev *input = wacom->touch_input;
3153*4882a593Smuzhiyun 	unsigned char *finger_data, prefix;
3154*4882a593Smuzhiyun 	unsigned id;
3155*4882a593Smuzhiyun 	int x, y;
3156*4882a593Smuzhiyun 	bool valid;
3157*4882a593Smuzhiyun 
3158*4882a593Smuzhiyun 	prefix = data[0];
3159*4882a593Smuzhiyun 
3160*4882a593Smuzhiyun 	for (id = 0; id < wacom->features.touch_max; id++) {
3161*4882a593Smuzhiyun 		valid = !!(prefix & BIT(id)) &&
3162*4882a593Smuzhiyun 			report_touch_events(wacom);
3163*4882a593Smuzhiyun 
3164*4882a593Smuzhiyun 		input_mt_slot(input, id);
3165*4882a593Smuzhiyun 		input_mt_report_slot_state(input, MT_TOOL_FINGER, valid);
3166*4882a593Smuzhiyun 
3167*4882a593Smuzhiyun 		if (!valid)
3168*4882a593Smuzhiyun 			continue;
3169*4882a593Smuzhiyun 
3170*4882a593Smuzhiyun 		finger_data = data + 1 + id * 3;
3171*4882a593Smuzhiyun 		x = finger_data[0] | ((finger_data[1] & 0x0f) << 8);
3172*4882a593Smuzhiyun 		y = (finger_data[2] << 4) | (finger_data[1] >> 4);
3173*4882a593Smuzhiyun 
3174*4882a593Smuzhiyun 		input_report_abs(input, ABS_MT_POSITION_X, x);
3175*4882a593Smuzhiyun 		input_report_abs(input, ABS_MT_POSITION_Y, y);
3176*4882a593Smuzhiyun 	}
3177*4882a593Smuzhiyun 
3178*4882a593Smuzhiyun 	input_mt_sync_frame(input);
3179*4882a593Smuzhiyun 
3180*4882a593Smuzhiyun 	input_report_key(input, BTN_LEFT, prefix & 0x40);
3181*4882a593Smuzhiyun 	input_report_key(input, BTN_RIGHT, prefix & 0x80);
3182*4882a593Smuzhiyun 
3183*4882a593Smuzhiyun 	/* keep touch state for pen event */
3184*4882a593Smuzhiyun 	wacom->shared->touch_down = !!prefix && report_touch_events(wacom);
3185*4882a593Smuzhiyun 
3186*4882a593Smuzhiyun 	return 1;
3187*4882a593Smuzhiyun }
3188*4882a593Smuzhiyun 
wacom_bamboo_pad_irq(struct wacom_wac * wacom,size_t len)3189*4882a593Smuzhiyun static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)
3190*4882a593Smuzhiyun {
3191*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun 	if (!((len == WACOM_PKGLEN_BPAD_TOUCH) ||
3194*4882a593Smuzhiyun 	      (len == WACOM_PKGLEN_BPAD_TOUCH_USB)) ||
3195*4882a593Smuzhiyun 	    (data[0] != WACOM_REPORT_BPAD_TOUCH))
3196*4882a593Smuzhiyun 		return 0;
3197*4882a593Smuzhiyun 
3198*4882a593Smuzhiyun 	if (data[1] & 0x01)
3199*4882a593Smuzhiyun 		wacom_bamboo_pad_pen_event(wacom, &data[1]);
3200*4882a593Smuzhiyun 
3201*4882a593Smuzhiyun 	if (data[1] & 0x02)
3202*4882a593Smuzhiyun 		return wacom_bamboo_pad_touch_event(wacom, &data[9]);
3203*4882a593Smuzhiyun 
3204*4882a593Smuzhiyun 	return 0;
3205*4882a593Smuzhiyun }
3206*4882a593Smuzhiyun 
wacom_wireless_irq(struct wacom_wac * wacom,size_t len)3207*4882a593Smuzhiyun static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
3208*4882a593Smuzhiyun {
3209*4882a593Smuzhiyun 	unsigned char *data = wacom->data;
3210*4882a593Smuzhiyun 	int connected;
3211*4882a593Smuzhiyun 
3212*4882a593Smuzhiyun 	if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL)
3213*4882a593Smuzhiyun 		return 0;
3214*4882a593Smuzhiyun 
3215*4882a593Smuzhiyun 	connected = data[1] & 0x01;
3216*4882a593Smuzhiyun 	if (connected) {
3217*4882a593Smuzhiyun 		int pid, battery, charging;
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun 		if ((wacom->shared->type == INTUOSHT ||
3220*4882a593Smuzhiyun 		    wacom->shared->type == INTUOSHT2) &&
3221*4882a593Smuzhiyun 		    wacom->shared->touch_input &&
3222*4882a593Smuzhiyun 		    wacom->shared->touch_max) {
3223*4882a593Smuzhiyun 			input_report_switch(wacom->shared->touch_input,
3224*4882a593Smuzhiyun 					SW_MUTE_DEVICE, data[5] & 0x40);
3225*4882a593Smuzhiyun 			input_sync(wacom->shared->touch_input);
3226*4882a593Smuzhiyun 		}
3227*4882a593Smuzhiyun 
3228*4882a593Smuzhiyun 		pid = get_unaligned_be16(&data[6]);
3229*4882a593Smuzhiyun 		battery = (data[5] & 0x3f) * 100 / 31;
3230*4882a593Smuzhiyun 		charging = !!(data[5] & 0x80);
3231*4882a593Smuzhiyun 		if (wacom->pid != pid) {
3232*4882a593Smuzhiyun 			wacom->pid = pid;
3233*4882a593Smuzhiyun 			wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
3234*4882a593Smuzhiyun 		}
3235*4882a593Smuzhiyun 
3236*4882a593Smuzhiyun 		wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
3237*4882a593Smuzhiyun 				     battery, charging, 1, 0);
3238*4882a593Smuzhiyun 
3239*4882a593Smuzhiyun 	} else if (wacom->pid != 0) {
3240*4882a593Smuzhiyun 		/* disconnected while previously connected */
3241*4882a593Smuzhiyun 		wacom->pid = 0;
3242*4882a593Smuzhiyun 		wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
3243*4882a593Smuzhiyun 		wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
3244*4882a593Smuzhiyun 	}
3245*4882a593Smuzhiyun 
3246*4882a593Smuzhiyun 	return 0;
3247*4882a593Smuzhiyun }
3248*4882a593Smuzhiyun 
wacom_status_irq(struct wacom_wac * wacom_wac,size_t len)3249*4882a593Smuzhiyun static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
3250*4882a593Smuzhiyun {
3251*4882a593Smuzhiyun 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
3252*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
3253*4882a593Smuzhiyun 	unsigned char *data = wacom_wac->data;
3254*4882a593Smuzhiyun 
3255*4882a593Smuzhiyun 	if (data[0] != WACOM_REPORT_USB)
3256*4882a593Smuzhiyun 		return 0;
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun 	if ((features->type == INTUOSHT ||
3259*4882a593Smuzhiyun 	    features->type == INTUOSHT2) &&
3260*4882a593Smuzhiyun 	    wacom_wac->shared->touch_input &&
3261*4882a593Smuzhiyun 	    features->touch_max) {
3262*4882a593Smuzhiyun 		input_report_switch(wacom_wac->shared->touch_input,
3263*4882a593Smuzhiyun 				    SW_MUTE_DEVICE, data[8] & 0x40);
3264*4882a593Smuzhiyun 		input_sync(wacom_wac->shared->touch_input);
3265*4882a593Smuzhiyun 	}
3266*4882a593Smuzhiyun 
3267*4882a593Smuzhiyun 	if (data[9] & 0x02) { /* wireless module is attached */
3268*4882a593Smuzhiyun 		int battery = (data[8] & 0x3f) * 100 / 31;
3269*4882a593Smuzhiyun 		bool charging = !!(data[8] & 0x80);
3270*4882a593Smuzhiyun 
3271*4882a593Smuzhiyun 		wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
3272*4882a593Smuzhiyun 				     battery, charging, battery || charging, 1);
3273*4882a593Smuzhiyun 
3274*4882a593Smuzhiyun 		if (!wacom->battery.battery &&
3275*4882a593Smuzhiyun 		    !(features->quirks & WACOM_QUIRK_BATTERY)) {
3276*4882a593Smuzhiyun 			features->quirks |= WACOM_QUIRK_BATTERY;
3277*4882a593Smuzhiyun 			wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
3278*4882a593Smuzhiyun 		}
3279*4882a593Smuzhiyun 	}
3280*4882a593Smuzhiyun 	else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
3281*4882a593Smuzhiyun 		 wacom->battery.battery) {
3282*4882a593Smuzhiyun 		features->quirks &= ~WACOM_QUIRK_BATTERY;
3283*4882a593Smuzhiyun 		wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
3284*4882a593Smuzhiyun 		wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
3285*4882a593Smuzhiyun 	}
3286*4882a593Smuzhiyun 	return 0;
3287*4882a593Smuzhiyun }
3288*4882a593Smuzhiyun 
wacom_wac_irq(struct wacom_wac * wacom_wac,size_t len)3289*4882a593Smuzhiyun void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
3290*4882a593Smuzhiyun {
3291*4882a593Smuzhiyun 	bool sync;
3292*4882a593Smuzhiyun 
3293*4882a593Smuzhiyun 	switch (wacom_wac->features.type) {
3294*4882a593Smuzhiyun 	case PENPARTNER:
3295*4882a593Smuzhiyun 		sync = wacom_penpartner_irq(wacom_wac);
3296*4882a593Smuzhiyun 		break;
3297*4882a593Smuzhiyun 
3298*4882a593Smuzhiyun 	case PL:
3299*4882a593Smuzhiyun 		sync = wacom_pl_irq(wacom_wac);
3300*4882a593Smuzhiyun 		break;
3301*4882a593Smuzhiyun 
3302*4882a593Smuzhiyun 	case WACOM_G4:
3303*4882a593Smuzhiyun 	case GRAPHIRE:
3304*4882a593Smuzhiyun 	case GRAPHIRE_BT:
3305*4882a593Smuzhiyun 	case WACOM_MO:
3306*4882a593Smuzhiyun 		sync = wacom_graphire_irq(wacom_wac);
3307*4882a593Smuzhiyun 		break;
3308*4882a593Smuzhiyun 
3309*4882a593Smuzhiyun 	case PTU:
3310*4882a593Smuzhiyun 		sync = wacom_ptu_irq(wacom_wac);
3311*4882a593Smuzhiyun 		break;
3312*4882a593Smuzhiyun 
3313*4882a593Smuzhiyun 	case DTU:
3314*4882a593Smuzhiyun 		sync = wacom_dtu_irq(wacom_wac);
3315*4882a593Smuzhiyun 		break;
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun 	case DTUS:
3318*4882a593Smuzhiyun 	case DTUSX:
3319*4882a593Smuzhiyun 		sync = wacom_dtus_irq(wacom_wac);
3320*4882a593Smuzhiyun 		break;
3321*4882a593Smuzhiyun 
3322*4882a593Smuzhiyun 	case INTUOS:
3323*4882a593Smuzhiyun 	case INTUOS3S:
3324*4882a593Smuzhiyun 	case INTUOS3:
3325*4882a593Smuzhiyun 	case INTUOS3L:
3326*4882a593Smuzhiyun 	case INTUOS4S:
3327*4882a593Smuzhiyun 	case INTUOS4:
3328*4882a593Smuzhiyun 	case INTUOS4L:
3329*4882a593Smuzhiyun 	case CINTIQ:
3330*4882a593Smuzhiyun 	case WACOM_BEE:
3331*4882a593Smuzhiyun 	case WACOM_13HD:
3332*4882a593Smuzhiyun 	case WACOM_21UX2:
3333*4882a593Smuzhiyun 	case WACOM_22HD:
3334*4882a593Smuzhiyun 	case WACOM_24HD:
3335*4882a593Smuzhiyun 	case WACOM_27QHD:
3336*4882a593Smuzhiyun 	case DTK:
3337*4882a593Smuzhiyun 	case CINTIQ_HYBRID:
3338*4882a593Smuzhiyun 	case CINTIQ_COMPANION_2:
3339*4882a593Smuzhiyun 		sync = wacom_intuos_irq(wacom_wac);
3340*4882a593Smuzhiyun 		break;
3341*4882a593Smuzhiyun 
3342*4882a593Smuzhiyun 	case INTUOS4WL:
3343*4882a593Smuzhiyun 		sync = wacom_intuos_bt_irq(wacom_wac, len);
3344*4882a593Smuzhiyun 		break;
3345*4882a593Smuzhiyun 
3346*4882a593Smuzhiyun 	case WACOM_24HDT:
3347*4882a593Smuzhiyun 	case WACOM_27QHDT:
3348*4882a593Smuzhiyun 		sync = wacom_24hdt_irq(wacom_wac);
3349*4882a593Smuzhiyun 		break;
3350*4882a593Smuzhiyun 
3351*4882a593Smuzhiyun 	case INTUOS5S:
3352*4882a593Smuzhiyun 	case INTUOS5:
3353*4882a593Smuzhiyun 	case INTUOS5L:
3354*4882a593Smuzhiyun 	case INTUOSPS:
3355*4882a593Smuzhiyun 	case INTUOSPM:
3356*4882a593Smuzhiyun 	case INTUOSPL:
3357*4882a593Smuzhiyun 		if (len == WACOM_PKGLEN_BBTOUCH3)
3358*4882a593Smuzhiyun 			sync = wacom_bpt3_touch(wacom_wac);
3359*4882a593Smuzhiyun 		else if (wacom_wac->data[0] == WACOM_REPORT_USB)
3360*4882a593Smuzhiyun 			sync = wacom_status_irq(wacom_wac, len);
3361*4882a593Smuzhiyun 		else
3362*4882a593Smuzhiyun 			sync = wacom_intuos_irq(wacom_wac);
3363*4882a593Smuzhiyun 		break;
3364*4882a593Smuzhiyun 
3365*4882a593Smuzhiyun 	case INTUOSP2_BT:
3366*4882a593Smuzhiyun 	case INTUOSP2S_BT:
3367*4882a593Smuzhiyun 	case INTUOSHT3_BT:
3368*4882a593Smuzhiyun 		sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
3369*4882a593Smuzhiyun 		break;
3370*4882a593Smuzhiyun 
3371*4882a593Smuzhiyun 	case TABLETPC:
3372*4882a593Smuzhiyun 	case TABLETPCE:
3373*4882a593Smuzhiyun 	case TABLETPC2FG:
3374*4882a593Smuzhiyun 	case MTSCREEN:
3375*4882a593Smuzhiyun 	case MTTPC:
3376*4882a593Smuzhiyun 	case MTTPC_B:
3377*4882a593Smuzhiyun 		sync = wacom_tpc_irq(wacom_wac, len);
3378*4882a593Smuzhiyun 		break;
3379*4882a593Smuzhiyun 
3380*4882a593Smuzhiyun 	case BAMBOO_PT:
3381*4882a593Smuzhiyun 	case BAMBOO_PEN:
3382*4882a593Smuzhiyun 	case BAMBOO_TOUCH:
3383*4882a593Smuzhiyun 	case INTUOSHT:
3384*4882a593Smuzhiyun 	case INTUOSHT2:
3385*4882a593Smuzhiyun 		if (wacom_wac->data[0] == WACOM_REPORT_USB)
3386*4882a593Smuzhiyun 			sync = wacom_status_irq(wacom_wac, len);
3387*4882a593Smuzhiyun 		else
3388*4882a593Smuzhiyun 			sync = wacom_bpt_irq(wacom_wac, len);
3389*4882a593Smuzhiyun 		break;
3390*4882a593Smuzhiyun 
3391*4882a593Smuzhiyun 	case BAMBOO_PAD:
3392*4882a593Smuzhiyun 		sync = wacom_bamboo_pad_irq(wacom_wac, len);
3393*4882a593Smuzhiyun 		break;
3394*4882a593Smuzhiyun 
3395*4882a593Smuzhiyun 	case WIRELESS:
3396*4882a593Smuzhiyun 		sync = wacom_wireless_irq(wacom_wac, len);
3397*4882a593Smuzhiyun 		break;
3398*4882a593Smuzhiyun 
3399*4882a593Smuzhiyun 	case REMOTE:
3400*4882a593Smuzhiyun 		sync = false;
3401*4882a593Smuzhiyun 		if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
3402*4882a593Smuzhiyun 			wacom_remote_status_irq(wacom_wac, len);
3403*4882a593Smuzhiyun 		else
3404*4882a593Smuzhiyun 			sync = wacom_remote_irq(wacom_wac, len);
3405*4882a593Smuzhiyun 		break;
3406*4882a593Smuzhiyun 
3407*4882a593Smuzhiyun 	default:
3408*4882a593Smuzhiyun 		sync = false;
3409*4882a593Smuzhiyun 		break;
3410*4882a593Smuzhiyun 	}
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun 	if (sync) {
3413*4882a593Smuzhiyun 		if (wacom_wac->pen_input)
3414*4882a593Smuzhiyun 			input_sync(wacom_wac->pen_input);
3415*4882a593Smuzhiyun 		if (wacom_wac->touch_input)
3416*4882a593Smuzhiyun 			input_sync(wacom_wac->touch_input);
3417*4882a593Smuzhiyun 		if (wacom_wac->pad_input)
3418*4882a593Smuzhiyun 			input_sync(wacom_wac->pad_input);
3419*4882a593Smuzhiyun 	}
3420*4882a593Smuzhiyun }
3421*4882a593Smuzhiyun 
wacom_setup_basic_pro_pen(struct wacom_wac * wacom_wac)3422*4882a593Smuzhiyun static void wacom_setup_basic_pro_pen(struct wacom_wac *wacom_wac)
3423*4882a593Smuzhiyun {
3424*4882a593Smuzhiyun 	struct input_dev *input_dev = wacom_wac->pen_input;
3425*4882a593Smuzhiyun 
3426*4882a593Smuzhiyun 	input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
3427*4882a593Smuzhiyun 
3428*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3429*4882a593Smuzhiyun 	__set_bit(BTN_STYLUS, input_dev->keybit);
3430*4882a593Smuzhiyun 	__set_bit(BTN_STYLUS2, input_dev->keybit);
3431*4882a593Smuzhiyun 
3432*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_DISTANCE,
3433*4882a593Smuzhiyun 			     0, wacom_wac->features.distance_max, wacom_wac->features.distance_fuzz, 0);
3434*4882a593Smuzhiyun }
3435*4882a593Smuzhiyun 
wacom_setup_cintiq(struct wacom_wac * wacom_wac)3436*4882a593Smuzhiyun static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
3437*4882a593Smuzhiyun {
3438*4882a593Smuzhiyun 	struct input_dev *input_dev = wacom_wac->pen_input;
3439*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
3440*4882a593Smuzhiyun 
3441*4882a593Smuzhiyun 	wacom_setup_basic_pro_pen(wacom_wac);
3442*4882a593Smuzhiyun 
3443*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3444*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
3445*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
3446*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
3447*4882a593Smuzhiyun 
3448*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
3449*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, features->tilt_fuzz, 0);
3450*4882a593Smuzhiyun 	input_abs_set_res(input_dev, ABS_TILT_X, 57);
3451*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_TILT_Y, -64, 63, features->tilt_fuzz, 0);
3452*4882a593Smuzhiyun 	input_abs_set_res(input_dev, ABS_TILT_Y, 57);
3453*4882a593Smuzhiyun }
3454*4882a593Smuzhiyun 
wacom_setup_intuos(struct wacom_wac * wacom_wac)3455*4882a593Smuzhiyun static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
3456*4882a593Smuzhiyun {
3457*4882a593Smuzhiyun 	struct input_dev *input_dev = wacom_wac->pen_input;
3458*4882a593Smuzhiyun 
3459*4882a593Smuzhiyun 	input_set_capability(input_dev, EV_REL, REL_WHEEL);
3460*4882a593Smuzhiyun 
3461*4882a593Smuzhiyun 	wacom_setup_cintiq(wacom_wac);
3462*4882a593Smuzhiyun 
3463*4882a593Smuzhiyun 	__set_bit(BTN_LEFT, input_dev->keybit);
3464*4882a593Smuzhiyun 	__set_bit(BTN_RIGHT, input_dev->keybit);
3465*4882a593Smuzhiyun 	__set_bit(BTN_MIDDLE, input_dev->keybit);
3466*4882a593Smuzhiyun 	__set_bit(BTN_SIDE, input_dev->keybit);
3467*4882a593Smuzhiyun 	__set_bit(BTN_EXTRA, input_dev->keybit);
3468*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
3469*4882a593Smuzhiyun 	__set_bit(BTN_TOOL_LENS, input_dev->keybit);
3470*4882a593Smuzhiyun 
3471*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
3472*4882a593Smuzhiyun 	input_abs_set_res(input_dev, ABS_RZ, 287);
3473*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
3474*4882a593Smuzhiyun }
3475*4882a593Smuzhiyun 
wacom_setup_device_quirks(struct wacom * wacom)3476*4882a593Smuzhiyun void wacom_setup_device_quirks(struct wacom *wacom)
3477*4882a593Smuzhiyun {
3478*4882a593Smuzhiyun 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
3479*4882a593Smuzhiyun 	struct wacom_features *features = &wacom->wacom_wac.features;
3480*4882a593Smuzhiyun 
3481*4882a593Smuzhiyun 	/* The pen and pad share the same interface on most devices */
3482*4882a593Smuzhiyun 	if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
3483*4882a593Smuzhiyun 	    features->type == DTUS ||
3484*4882a593Smuzhiyun 	    (features->type >= INTUOS3S && features->type <= WACOM_MO)) {
3485*4882a593Smuzhiyun 		if (features->device_type & WACOM_DEVICETYPE_PEN)
3486*4882a593Smuzhiyun 			features->device_type |= WACOM_DEVICETYPE_PAD;
3487*4882a593Smuzhiyun 	}
3488*4882a593Smuzhiyun 
3489*4882a593Smuzhiyun 	/* touch device found but size is not defined. use default */
3490*4882a593Smuzhiyun 	if (features->device_type & WACOM_DEVICETYPE_TOUCH && !features->x_max) {
3491*4882a593Smuzhiyun 		features->x_max = 1023;
3492*4882a593Smuzhiyun 		features->y_max = 1023;
3493*4882a593Smuzhiyun 	}
3494*4882a593Smuzhiyun 
3495*4882a593Smuzhiyun 	/*
3496*4882a593Smuzhiyun 	 * Intuos5/Pro and Bamboo 3rd gen have no useful data about its
3497*4882a593Smuzhiyun 	 * touch interface in its HID descriptor. If this is the touch
3498*4882a593Smuzhiyun 	 * interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the
3499*4882a593Smuzhiyun 	 * tablet values.
3500*4882a593Smuzhiyun 	 */
3501*4882a593Smuzhiyun 	if ((features->type >= INTUOS5S && features->type <= INTUOSPL) ||
3502*4882a593Smuzhiyun 		(features->type >= INTUOSHT && features->type <= BAMBOO_PT)) {
3503*4882a593Smuzhiyun 		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
3504*4882a593Smuzhiyun 			if (features->touch_max)
3505*4882a593Smuzhiyun 				features->device_type |= WACOM_DEVICETYPE_TOUCH;
3506*4882a593Smuzhiyun 			if (features->type >= INTUOSHT && features->type <= BAMBOO_PT)
3507*4882a593Smuzhiyun 				features->device_type |= WACOM_DEVICETYPE_PAD;
3508*4882a593Smuzhiyun 
3509*4882a593Smuzhiyun 			if (features->type == INTUOSHT2) {
3510*4882a593Smuzhiyun 				features->x_max = features->x_max / 10;
3511*4882a593Smuzhiyun 				features->y_max = features->y_max / 10;
3512*4882a593Smuzhiyun 			}
3513*4882a593Smuzhiyun 			else {
3514*4882a593Smuzhiyun 				features->x_max = 4096;
3515*4882a593Smuzhiyun 				features->y_max = 4096;
3516*4882a593Smuzhiyun 			}
3517*4882a593Smuzhiyun 		}
3518*4882a593Smuzhiyun 		else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) {
3519*4882a593Smuzhiyun 			features->device_type |= WACOM_DEVICETYPE_PAD;
3520*4882a593Smuzhiyun 		}
3521*4882a593Smuzhiyun 	}
3522*4882a593Smuzhiyun 
3523*4882a593Smuzhiyun 	/*
3524*4882a593Smuzhiyun 	 * Hack for the Bamboo One:
3525*4882a593Smuzhiyun 	 * the device presents a PAD/Touch interface as most Bamboos and even
3526*4882a593Smuzhiyun 	 * sends ghosts PAD data on it. However, later, we must disable this
3527*4882a593Smuzhiyun 	 * ghost interface, and we can not detect it unless we set it here
3528*4882a593Smuzhiyun 	 * to WACOM_DEVICETYPE_PAD or WACOM_DEVICETYPE_TOUCH.
3529*4882a593Smuzhiyun 	 */
3530*4882a593Smuzhiyun 	if (features->type == BAMBOO_PEN &&
3531*4882a593Smuzhiyun 	    features->pktlen == WACOM_PKGLEN_BBTOUCH3)
3532*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
3533*4882a593Smuzhiyun 
3534*4882a593Smuzhiyun 	/*
3535*4882a593Smuzhiyun 	 * Raw Wacom-mode pen and touch events both come from interface
3536*4882a593Smuzhiyun 	 * 0, whose HID descriptor has an application usage of 0xFF0D
3537*4882a593Smuzhiyun 	 * (i.e., WACOM_HID_WD_DIGITIZER). We route pen packets back
3538*4882a593Smuzhiyun 	 * out through the HID_GENERIC device created for interface 1,
3539*4882a593Smuzhiyun 	 * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH.
3540*4882a593Smuzhiyun 	 */
3541*4882a593Smuzhiyun 	if (features->type == BAMBOO_PAD)
3542*4882a593Smuzhiyun 		features->device_type = WACOM_DEVICETYPE_TOUCH;
3543*4882a593Smuzhiyun 
3544*4882a593Smuzhiyun 	if (features->type == REMOTE)
3545*4882a593Smuzhiyun 		features->device_type = WACOM_DEVICETYPE_PAD;
3546*4882a593Smuzhiyun 
3547*4882a593Smuzhiyun 	if (features->type == INTUOSP2_BT ||
3548*4882a593Smuzhiyun 	    features->type == INTUOSP2S_BT) {
3549*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PEN |
3550*4882a593Smuzhiyun 					 WACOM_DEVICETYPE_PAD |
3551*4882a593Smuzhiyun 					 WACOM_DEVICETYPE_TOUCH;
3552*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_BATTERY;
3553*4882a593Smuzhiyun 	}
3554*4882a593Smuzhiyun 
3555*4882a593Smuzhiyun 	if (features->type == INTUOSHT3_BT) {
3556*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PEN |
3557*4882a593Smuzhiyun 					 WACOM_DEVICETYPE_PAD;
3558*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_BATTERY;
3559*4882a593Smuzhiyun 	}
3560*4882a593Smuzhiyun 
3561*4882a593Smuzhiyun 	switch (features->type) {
3562*4882a593Smuzhiyun 	case PL:
3563*4882a593Smuzhiyun 	case DTU:
3564*4882a593Smuzhiyun 	case DTUS:
3565*4882a593Smuzhiyun 	case DTUSX:
3566*4882a593Smuzhiyun 	case WACOM_21UX2:
3567*4882a593Smuzhiyun 	case WACOM_22HD:
3568*4882a593Smuzhiyun 	case DTK:
3569*4882a593Smuzhiyun 	case WACOM_24HD:
3570*4882a593Smuzhiyun 	case WACOM_27QHD:
3571*4882a593Smuzhiyun 	case CINTIQ_HYBRID:
3572*4882a593Smuzhiyun 	case CINTIQ_COMPANION_2:
3573*4882a593Smuzhiyun 	case CINTIQ:
3574*4882a593Smuzhiyun 	case WACOM_BEE:
3575*4882a593Smuzhiyun 	case WACOM_13HD:
3576*4882a593Smuzhiyun 	case WACOM_24HDT:
3577*4882a593Smuzhiyun 	case WACOM_27QHDT:
3578*4882a593Smuzhiyun 	case TABLETPC:
3579*4882a593Smuzhiyun 	case TABLETPCE:
3580*4882a593Smuzhiyun 	case TABLETPC2FG:
3581*4882a593Smuzhiyun 	case MTSCREEN:
3582*4882a593Smuzhiyun 	case MTTPC:
3583*4882a593Smuzhiyun 	case MTTPC_B:
3584*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_DIRECT;
3585*4882a593Smuzhiyun 		break;
3586*4882a593Smuzhiyun 	}
3587*4882a593Smuzhiyun 
3588*4882a593Smuzhiyun 	if (wacom->hdev->bus == BUS_BLUETOOTH)
3589*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_BATTERY;
3590*4882a593Smuzhiyun 
3591*4882a593Smuzhiyun 	/* quirk for bamboo touch with 2 low res touches */
3592*4882a593Smuzhiyun 	if ((features->type == BAMBOO_PT || features->type == BAMBOO_TOUCH) &&
3593*4882a593Smuzhiyun 	    features->pktlen == WACOM_PKGLEN_BBTOUCH) {
3594*4882a593Smuzhiyun 		features->x_max <<= 5;
3595*4882a593Smuzhiyun 		features->y_max <<= 5;
3596*4882a593Smuzhiyun 		features->x_fuzz <<= 5;
3597*4882a593Smuzhiyun 		features->y_fuzz <<= 5;
3598*4882a593Smuzhiyun 		features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
3599*4882a593Smuzhiyun 	}
3600*4882a593Smuzhiyun 
3601*4882a593Smuzhiyun 	if (features->type == WIRELESS) {
3602*4882a593Smuzhiyun 		if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) {
3603*4882a593Smuzhiyun 			features->quirks |= WACOM_QUIRK_BATTERY;
3604*4882a593Smuzhiyun 		}
3605*4882a593Smuzhiyun 	}
3606*4882a593Smuzhiyun 
3607*4882a593Smuzhiyun 	if (features->type == REMOTE)
3608*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
3609*4882a593Smuzhiyun 
3610*4882a593Smuzhiyun 	/* HID descriptor for DTK-2451 / DTH-2452 claims to report lots
3611*4882a593Smuzhiyun 	 * of things it shouldn't. Lets fix up the damage...
3612*4882a593Smuzhiyun 	 */
3613*4882a593Smuzhiyun 	if (wacom->hdev->product == 0x382 || wacom->hdev->product == 0x37d) {
3614*4882a593Smuzhiyun 		features->quirks &= ~WACOM_QUIRK_TOOLSERIAL;
3615*4882a593Smuzhiyun 		__clear_bit(BTN_TOOL_BRUSH, wacom_wac->pen_input->keybit);
3616*4882a593Smuzhiyun 		__clear_bit(BTN_TOOL_PENCIL, wacom_wac->pen_input->keybit);
3617*4882a593Smuzhiyun 		__clear_bit(BTN_TOOL_AIRBRUSH, wacom_wac->pen_input->keybit);
3618*4882a593Smuzhiyun 		__clear_bit(ABS_Z, wacom_wac->pen_input->absbit);
3619*4882a593Smuzhiyun 		__clear_bit(ABS_DISTANCE, wacom_wac->pen_input->absbit);
3620*4882a593Smuzhiyun 		__clear_bit(ABS_TILT_X, wacom_wac->pen_input->absbit);
3621*4882a593Smuzhiyun 		__clear_bit(ABS_TILT_Y, wacom_wac->pen_input->absbit);
3622*4882a593Smuzhiyun 		__clear_bit(ABS_WHEEL, wacom_wac->pen_input->absbit);
3623*4882a593Smuzhiyun 		__clear_bit(ABS_MISC, wacom_wac->pen_input->absbit);
3624*4882a593Smuzhiyun 		__clear_bit(MSC_SERIAL, wacom_wac->pen_input->mscbit);
3625*4882a593Smuzhiyun 		__clear_bit(EV_MSC, wacom_wac->pen_input->evbit);
3626*4882a593Smuzhiyun 	}
3627*4882a593Smuzhiyun }
3628*4882a593Smuzhiyun 
wacom_setup_pen_input_capabilities(struct input_dev * input_dev,struct wacom_wac * wacom_wac)3629*4882a593Smuzhiyun int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
3630*4882a593Smuzhiyun 				   struct wacom_wac *wacom_wac)
3631*4882a593Smuzhiyun {
3632*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
3633*4882a593Smuzhiyun 
3634*4882a593Smuzhiyun 	if (!(features->device_type & WACOM_DEVICETYPE_PEN))
3635*4882a593Smuzhiyun 		return -ENODEV;
3636*4882a593Smuzhiyun 
3637*4882a593Smuzhiyun 	if (features->device_type & WACOM_DEVICETYPE_DIRECT)
3638*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
3639*4882a593Smuzhiyun 	else
3640*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
3641*4882a593Smuzhiyun 
3642*4882a593Smuzhiyun 	if (features->type == HID_GENERIC) {
3643*4882a593Smuzhiyun 		/* setup has already been done; apply otherwise-undetectible quirks */
3644*4882a593Smuzhiyun 		input_set_capability(input_dev, EV_KEY, BTN_STYLUS3);
3645*4882a593Smuzhiyun 		return 0;
3646*4882a593Smuzhiyun 	}
3647*4882a593Smuzhiyun 
3648*4882a593Smuzhiyun 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
3649*4882a593Smuzhiyun 	__set_bit(BTN_TOUCH, input_dev->keybit);
3650*4882a593Smuzhiyun 	__set_bit(ABS_MISC, input_dev->absbit);
3651*4882a593Smuzhiyun 
3652*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_X, 0 + features->offset_left,
3653*4882a593Smuzhiyun 			     features->x_max - features->offset_right,
3654*4882a593Smuzhiyun 			     features->x_fuzz, 0);
3655*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_Y, 0 + features->offset_top,
3656*4882a593Smuzhiyun 			     features->y_max - features->offset_bottom,
3657*4882a593Smuzhiyun 			     features->y_fuzz, 0);
3658*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_PRESSURE, 0,
3659*4882a593Smuzhiyun 		features->pressure_max, features->pressure_fuzz, 0);
3660*4882a593Smuzhiyun 
3661*4882a593Smuzhiyun 	/* penabled devices have fixed resolution for each model */
3662*4882a593Smuzhiyun 	input_abs_set_res(input_dev, ABS_X, features->x_resolution);
3663*4882a593Smuzhiyun 	input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
3664*4882a593Smuzhiyun 
3665*4882a593Smuzhiyun 	switch (features->type) {
3666*4882a593Smuzhiyun 	case GRAPHIRE_BT:
3667*4882a593Smuzhiyun 		__clear_bit(ABS_MISC, input_dev->absbit);
3668*4882a593Smuzhiyun 		fallthrough;
3669*4882a593Smuzhiyun 
3670*4882a593Smuzhiyun 	case WACOM_MO:
3671*4882a593Smuzhiyun 	case WACOM_G4:
3672*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_DISTANCE, 0,
3673*4882a593Smuzhiyun 					      features->distance_max,
3674*4882a593Smuzhiyun 					      features->distance_fuzz, 0);
3675*4882a593Smuzhiyun 		fallthrough;
3676*4882a593Smuzhiyun 
3677*4882a593Smuzhiyun 	case GRAPHIRE:
3678*4882a593Smuzhiyun 		input_set_capability(input_dev, EV_REL, REL_WHEEL);
3679*4882a593Smuzhiyun 
3680*4882a593Smuzhiyun 		__set_bit(BTN_LEFT, input_dev->keybit);
3681*4882a593Smuzhiyun 		__set_bit(BTN_RIGHT, input_dev->keybit);
3682*4882a593Smuzhiyun 		__set_bit(BTN_MIDDLE, input_dev->keybit);
3683*4882a593Smuzhiyun 
3684*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3685*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3686*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
3687*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS, input_dev->keybit);
3688*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS2, input_dev->keybit);
3689*4882a593Smuzhiyun 		break;
3690*4882a593Smuzhiyun 
3691*4882a593Smuzhiyun 	case WACOM_27QHD:
3692*4882a593Smuzhiyun 	case WACOM_24HD:
3693*4882a593Smuzhiyun 	case DTK:
3694*4882a593Smuzhiyun 	case WACOM_22HD:
3695*4882a593Smuzhiyun 	case WACOM_21UX2:
3696*4882a593Smuzhiyun 	case WACOM_BEE:
3697*4882a593Smuzhiyun 	case CINTIQ:
3698*4882a593Smuzhiyun 	case WACOM_13HD:
3699*4882a593Smuzhiyun 	case CINTIQ_HYBRID:
3700*4882a593Smuzhiyun 	case CINTIQ_COMPANION_2:
3701*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
3702*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_Z, 287);
3703*4882a593Smuzhiyun 		wacom_setup_cintiq(wacom_wac);
3704*4882a593Smuzhiyun 		break;
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun 	case INTUOS3:
3707*4882a593Smuzhiyun 	case INTUOS3L:
3708*4882a593Smuzhiyun 	case INTUOS3S:
3709*4882a593Smuzhiyun 	case INTUOS4:
3710*4882a593Smuzhiyun 	case INTUOS4WL:
3711*4882a593Smuzhiyun 	case INTUOS4L:
3712*4882a593Smuzhiyun 	case INTUOS4S:
3713*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
3714*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_Z, 287);
3715*4882a593Smuzhiyun 		fallthrough;
3716*4882a593Smuzhiyun 
3717*4882a593Smuzhiyun 	case INTUOS:
3718*4882a593Smuzhiyun 		wacom_setup_intuos(wacom_wac);
3719*4882a593Smuzhiyun 		break;
3720*4882a593Smuzhiyun 
3721*4882a593Smuzhiyun 	case INTUOS5:
3722*4882a593Smuzhiyun 	case INTUOS5L:
3723*4882a593Smuzhiyun 	case INTUOSPM:
3724*4882a593Smuzhiyun 	case INTUOSPL:
3725*4882a593Smuzhiyun 	case INTUOS5S:
3726*4882a593Smuzhiyun 	case INTUOSPS:
3727*4882a593Smuzhiyun 	case INTUOSP2_BT:
3728*4882a593Smuzhiyun 	case INTUOSP2S_BT:
3729*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_DISTANCE, 0,
3730*4882a593Smuzhiyun 				      features->distance_max,
3731*4882a593Smuzhiyun 				      features->distance_fuzz, 0);
3732*4882a593Smuzhiyun 
3733*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
3734*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_Z, 287);
3735*4882a593Smuzhiyun 
3736*4882a593Smuzhiyun 		wacom_setup_intuos(wacom_wac);
3737*4882a593Smuzhiyun 		break;
3738*4882a593Smuzhiyun 
3739*4882a593Smuzhiyun 	case WACOM_24HDT:
3740*4882a593Smuzhiyun 	case WACOM_27QHDT:
3741*4882a593Smuzhiyun 	case MTSCREEN:
3742*4882a593Smuzhiyun 	case MTTPC:
3743*4882a593Smuzhiyun 	case MTTPC_B:
3744*4882a593Smuzhiyun 	case TABLETPC2FG:
3745*4882a593Smuzhiyun 	case TABLETPC:
3746*4882a593Smuzhiyun 	case TABLETPCE:
3747*4882a593Smuzhiyun 		__clear_bit(ABS_MISC, input_dev->absbit);
3748*4882a593Smuzhiyun 		fallthrough;
3749*4882a593Smuzhiyun 
3750*4882a593Smuzhiyun 	case DTUS:
3751*4882a593Smuzhiyun 	case DTUSX:
3752*4882a593Smuzhiyun 	case PL:
3753*4882a593Smuzhiyun 	case DTU:
3754*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3755*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3756*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS, input_dev->keybit);
3757*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS2, input_dev->keybit);
3758*4882a593Smuzhiyun 		break;
3759*4882a593Smuzhiyun 
3760*4882a593Smuzhiyun 	case PTU:
3761*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS2, input_dev->keybit);
3762*4882a593Smuzhiyun 		fallthrough;
3763*4882a593Smuzhiyun 
3764*4882a593Smuzhiyun 	case PENPARTNER:
3765*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3766*4882a593Smuzhiyun 		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3767*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS, input_dev->keybit);
3768*4882a593Smuzhiyun 		break;
3769*4882a593Smuzhiyun 
3770*4882a593Smuzhiyun 	case INTUOSHT:
3771*4882a593Smuzhiyun 	case BAMBOO_PT:
3772*4882a593Smuzhiyun 	case BAMBOO_PEN:
3773*4882a593Smuzhiyun 	case INTUOSHT2:
3774*4882a593Smuzhiyun 	case INTUOSHT3_BT:
3775*4882a593Smuzhiyun 		if (features->type == INTUOSHT2 ||
3776*4882a593Smuzhiyun 		    features->type == INTUOSHT3_BT) {
3777*4882a593Smuzhiyun 			wacom_setup_basic_pro_pen(wacom_wac);
3778*4882a593Smuzhiyun 		} else {
3779*4882a593Smuzhiyun 			__clear_bit(ABS_MISC, input_dev->absbit);
3780*4882a593Smuzhiyun 			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3781*4882a593Smuzhiyun 			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3782*4882a593Smuzhiyun 			__set_bit(BTN_STYLUS, input_dev->keybit);
3783*4882a593Smuzhiyun 			__set_bit(BTN_STYLUS2, input_dev->keybit);
3784*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
3785*4882a593Smuzhiyun 				      features->distance_max,
3786*4882a593Smuzhiyun 				      features->distance_fuzz, 0);
3787*4882a593Smuzhiyun 		}
3788*4882a593Smuzhiyun 		break;
3789*4882a593Smuzhiyun 	case BAMBOO_PAD:
3790*4882a593Smuzhiyun 		__clear_bit(ABS_MISC, input_dev->absbit);
3791*4882a593Smuzhiyun 		break;
3792*4882a593Smuzhiyun 	}
3793*4882a593Smuzhiyun 	return 0;
3794*4882a593Smuzhiyun }
3795*4882a593Smuzhiyun 
wacom_setup_touch_input_capabilities(struct input_dev * input_dev,struct wacom_wac * wacom_wac)3796*4882a593Smuzhiyun int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
3797*4882a593Smuzhiyun 					 struct wacom_wac *wacom_wac)
3798*4882a593Smuzhiyun {
3799*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
3800*4882a593Smuzhiyun 
3801*4882a593Smuzhiyun 	if (!(features->device_type & WACOM_DEVICETYPE_TOUCH))
3802*4882a593Smuzhiyun 		return -ENODEV;
3803*4882a593Smuzhiyun 
3804*4882a593Smuzhiyun 	if (features->device_type & WACOM_DEVICETYPE_DIRECT)
3805*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
3806*4882a593Smuzhiyun 	else
3807*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun 	if (features->type == HID_GENERIC)
3810*4882a593Smuzhiyun 		/* setup has already been done */
3811*4882a593Smuzhiyun 		return 0;
3812*4882a593Smuzhiyun 
3813*4882a593Smuzhiyun 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
3814*4882a593Smuzhiyun 	__set_bit(BTN_TOUCH, input_dev->keybit);
3815*4882a593Smuzhiyun 
3816*4882a593Smuzhiyun 	if (features->touch_max == 1) {
3817*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_X, 0,
3818*4882a593Smuzhiyun 			features->x_max, features->x_fuzz, 0);
3819*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Y, 0,
3820*4882a593Smuzhiyun 			features->y_max, features->y_fuzz, 0);
3821*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_X,
3822*4882a593Smuzhiyun 				  features->x_resolution);
3823*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_Y,
3824*4882a593Smuzhiyun 				  features->y_resolution);
3825*4882a593Smuzhiyun 	}
3826*4882a593Smuzhiyun 	else if (features->touch_max > 1) {
3827*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
3828*4882a593Smuzhiyun 			features->x_max, features->x_fuzz, 0);
3829*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
3830*4882a593Smuzhiyun 			features->y_max, features->y_fuzz, 0);
3831*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_MT_POSITION_X,
3832*4882a593Smuzhiyun 				  features->x_resolution);
3833*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
3834*4882a593Smuzhiyun 				  features->y_resolution);
3835*4882a593Smuzhiyun 	}
3836*4882a593Smuzhiyun 
3837*4882a593Smuzhiyun 	switch (features->type) {
3838*4882a593Smuzhiyun 	case INTUOSP2_BT:
3839*4882a593Smuzhiyun 	case INTUOSP2S_BT:
3840*4882a593Smuzhiyun 		input_dev->evbit[0] |= BIT_MASK(EV_SW);
3841*4882a593Smuzhiyun 		__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
3842*4882a593Smuzhiyun 
3843*4882a593Smuzhiyun 		if (wacom_wac->shared->touch->product == 0x361) {
3844*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
3845*4882a593Smuzhiyun 					     0, 12440, 4, 0);
3846*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
3847*4882a593Smuzhiyun 					     0, 8640, 4, 0);
3848*4882a593Smuzhiyun 		}
3849*4882a593Smuzhiyun 		else if (wacom_wac->shared->touch->product == 0x360) {
3850*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
3851*4882a593Smuzhiyun 					     0, 8960, 4, 0);
3852*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
3853*4882a593Smuzhiyun 					     0, 5920, 4, 0);
3854*4882a593Smuzhiyun 		}
3855*4882a593Smuzhiyun 		else if (wacom_wac->shared->touch->product == 0x393) {
3856*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
3857*4882a593Smuzhiyun 					     0, 6400, 4, 0);
3858*4882a593Smuzhiyun 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
3859*4882a593Smuzhiyun 					     0, 4000, 4, 0);
3860*4882a593Smuzhiyun 		}
3861*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
3862*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
3863*4882a593Smuzhiyun 
3864*4882a593Smuzhiyun 		fallthrough;
3865*4882a593Smuzhiyun 
3866*4882a593Smuzhiyun 	case INTUOS5:
3867*4882a593Smuzhiyun 	case INTUOS5L:
3868*4882a593Smuzhiyun 	case INTUOSPM:
3869*4882a593Smuzhiyun 	case INTUOSPL:
3870*4882a593Smuzhiyun 	case INTUOS5S:
3871*4882a593Smuzhiyun 	case INTUOSPS:
3872*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
3873*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0);
3874*4882a593Smuzhiyun 		input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
3875*4882a593Smuzhiyun 		break;
3876*4882a593Smuzhiyun 
3877*4882a593Smuzhiyun 	case WACOM_24HDT:
3878*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
3879*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0);
3880*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0);
3881*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
3882*4882a593Smuzhiyun 		fallthrough;
3883*4882a593Smuzhiyun 
3884*4882a593Smuzhiyun 	case WACOM_27QHDT:
3885*4882a593Smuzhiyun 		if (wacom_wac->shared->touch->product == 0x32C ||
3886*4882a593Smuzhiyun 		    wacom_wac->shared->touch->product == 0xF6) {
3887*4882a593Smuzhiyun 			input_dev->evbit[0] |= BIT_MASK(EV_SW);
3888*4882a593Smuzhiyun 			__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
3889*4882a593Smuzhiyun 			wacom_wac->has_mute_touch_switch = true;
3890*4882a593Smuzhiyun 		}
3891*4882a593Smuzhiyun 		fallthrough;
3892*4882a593Smuzhiyun 
3893*4882a593Smuzhiyun 	case MTSCREEN:
3894*4882a593Smuzhiyun 	case MTTPC:
3895*4882a593Smuzhiyun 	case MTTPC_B:
3896*4882a593Smuzhiyun 	case TABLETPC2FG:
3897*4882a593Smuzhiyun 		input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT);
3898*4882a593Smuzhiyun 		fallthrough;
3899*4882a593Smuzhiyun 
3900*4882a593Smuzhiyun 	case TABLETPC:
3901*4882a593Smuzhiyun 	case TABLETPCE:
3902*4882a593Smuzhiyun 		break;
3903*4882a593Smuzhiyun 
3904*4882a593Smuzhiyun 	case INTUOSHT:
3905*4882a593Smuzhiyun 	case INTUOSHT2:
3906*4882a593Smuzhiyun 		input_dev->evbit[0] |= BIT_MASK(EV_SW);
3907*4882a593Smuzhiyun 		__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
3908*4882a593Smuzhiyun 		fallthrough;
3909*4882a593Smuzhiyun 
3910*4882a593Smuzhiyun 	case BAMBOO_PT:
3911*4882a593Smuzhiyun 	case BAMBOO_TOUCH:
3912*4882a593Smuzhiyun 		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
3913*4882a593Smuzhiyun 			input_set_abs_params(input_dev,
3914*4882a593Smuzhiyun 				     ABS_MT_TOUCH_MAJOR,
3915*4882a593Smuzhiyun 				     0, features->x_max, 0, 0);
3916*4882a593Smuzhiyun 			input_set_abs_params(input_dev,
3917*4882a593Smuzhiyun 				     ABS_MT_TOUCH_MINOR,
3918*4882a593Smuzhiyun 				     0, features->y_max, 0, 0);
3919*4882a593Smuzhiyun 		}
3920*4882a593Smuzhiyun 		input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
3921*4882a593Smuzhiyun 		break;
3922*4882a593Smuzhiyun 
3923*4882a593Smuzhiyun 	case BAMBOO_PAD:
3924*4882a593Smuzhiyun 		input_mt_init_slots(input_dev, features->touch_max,
3925*4882a593Smuzhiyun 				    INPUT_MT_POINTER);
3926*4882a593Smuzhiyun 		__set_bit(BTN_LEFT, input_dev->keybit);
3927*4882a593Smuzhiyun 		__set_bit(BTN_RIGHT, input_dev->keybit);
3928*4882a593Smuzhiyun 		break;
3929*4882a593Smuzhiyun 	}
3930*4882a593Smuzhiyun 	return 0;
3931*4882a593Smuzhiyun }
3932*4882a593Smuzhiyun 
wacom_numbered_button_to_key(int n)3933*4882a593Smuzhiyun static int wacom_numbered_button_to_key(int n)
3934*4882a593Smuzhiyun {
3935*4882a593Smuzhiyun 	if (n < 10)
3936*4882a593Smuzhiyun 		return BTN_0 + n;
3937*4882a593Smuzhiyun 	else if (n < 16)
3938*4882a593Smuzhiyun 		return BTN_A + (n-10);
3939*4882a593Smuzhiyun 	else if (n < 18)
3940*4882a593Smuzhiyun 		return BTN_BASE + (n-16);
3941*4882a593Smuzhiyun 	else
3942*4882a593Smuzhiyun 		return 0;
3943*4882a593Smuzhiyun }
3944*4882a593Smuzhiyun 
wacom_setup_numbered_buttons(struct input_dev * input_dev,int button_count)3945*4882a593Smuzhiyun static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
3946*4882a593Smuzhiyun 				int button_count)
3947*4882a593Smuzhiyun {
3948*4882a593Smuzhiyun 	int i;
3949*4882a593Smuzhiyun 
3950*4882a593Smuzhiyun 	for (i = 0; i < button_count; i++) {
3951*4882a593Smuzhiyun 		int key = wacom_numbered_button_to_key(i);
3952*4882a593Smuzhiyun 
3953*4882a593Smuzhiyun 		if (key)
3954*4882a593Smuzhiyun 			__set_bit(key, input_dev->keybit);
3955*4882a593Smuzhiyun 	}
3956*4882a593Smuzhiyun }
3957*4882a593Smuzhiyun 
wacom_24hd_update_leds(struct wacom * wacom,int mask,int group)3958*4882a593Smuzhiyun static void wacom_24hd_update_leds(struct wacom *wacom, int mask, int group)
3959*4882a593Smuzhiyun {
3960*4882a593Smuzhiyun 	struct wacom_led *led;
3961*4882a593Smuzhiyun 	int i;
3962*4882a593Smuzhiyun 	bool updated = false;
3963*4882a593Smuzhiyun 
3964*4882a593Smuzhiyun 	/*
3965*4882a593Smuzhiyun 	 * 24HD has LED group 1 to the left and LED group 0 to the right.
3966*4882a593Smuzhiyun 	 * So group 0 matches the second half of the buttons and thus the mask
3967*4882a593Smuzhiyun 	 * needs to be shifted.
3968*4882a593Smuzhiyun 	 */
3969*4882a593Smuzhiyun 	if (group == 0)
3970*4882a593Smuzhiyun 		mask >>= 8;
3971*4882a593Smuzhiyun 
3972*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
3973*4882a593Smuzhiyun 		led = wacom_led_find(wacom, group, i);
3974*4882a593Smuzhiyun 		if (!led) {
3975*4882a593Smuzhiyun 			hid_err(wacom->hdev, "can't find LED %d in group %d\n",
3976*4882a593Smuzhiyun 				i, group);
3977*4882a593Smuzhiyun 			continue;
3978*4882a593Smuzhiyun 		}
3979*4882a593Smuzhiyun 		if (!updated && mask & BIT(i)) {
3980*4882a593Smuzhiyun 			led->held = true;
3981*4882a593Smuzhiyun 			led_trigger_event(&led->trigger, LED_FULL);
3982*4882a593Smuzhiyun 		} else {
3983*4882a593Smuzhiyun 			led->held = false;
3984*4882a593Smuzhiyun 		}
3985*4882a593Smuzhiyun 	}
3986*4882a593Smuzhiyun }
3987*4882a593Smuzhiyun 
wacom_is_led_toggled(struct wacom * wacom,int button_count,int mask,int group)3988*4882a593Smuzhiyun static bool wacom_is_led_toggled(struct wacom *wacom, int button_count,
3989*4882a593Smuzhiyun 				 int mask, int group)
3990*4882a593Smuzhiyun {
3991*4882a593Smuzhiyun 	int group_button;
3992*4882a593Smuzhiyun 
3993*4882a593Smuzhiyun 	/*
3994*4882a593Smuzhiyun 	 * 21UX2 has LED group 1 to the left and LED group 0
3995*4882a593Smuzhiyun 	 * to the right. We need to reverse the group to match this
3996*4882a593Smuzhiyun 	 * historical behavior.
3997*4882a593Smuzhiyun 	 */
3998*4882a593Smuzhiyun 	if (wacom->wacom_wac.features.type == WACOM_21UX2)
3999*4882a593Smuzhiyun 		group = 1 - group;
4000*4882a593Smuzhiyun 
4001*4882a593Smuzhiyun 	group_button = group * (button_count/wacom->led.count);
4002*4882a593Smuzhiyun 
4003*4882a593Smuzhiyun 	if (wacom->wacom_wac.features.type == INTUOSP2_BT)
4004*4882a593Smuzhiyun 		group_button = 8;
4005*4882a593Smuzhiyun 
4006*4882a593Smuzhiyun 	return mask & (1 << group_button);
4007*4882a593Smuzhiyun }
4008*4882a593Smuzhiyun 
wacom_update_led(struct wacom * wacom,int button_count,int mask,int group)4009*4882a593Smuzhiyun static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
4010*4882a593Smuzhiyun 			     int group)
4011*4882a593Smuzhiyun {
4012*4882a593Smuzhiyun 	struct wacom_led *led, *next_led;
4013*4882a593Smuzhiyun 	int cur;
4014*4882a593Smuzhiyun 	bool pressed;
4015*4882a593Smuzhiyun 
4016*4882a593Smuzhiyun 	if (wacom->wacom_wac.features.type == WACOM_24HD)
4017*4882a593Smuzhiyun 		return wacom_24hd_update_leds(wacom, mask, group);
4018*4882a593Smuzhiyun 
4019*4882a593Smuzhiyun 	pressed = wacom_is_led_toggled(wacom, button_count, mask, group);
4020*4882a593Smuzhiyun 	cur = wacom->led.groups[group].select;
4021*4882a593Smuzhiyun 
4022*4882a593Smuzhiyun 	led = wacom_led_find(wacom, group, cur);
4023*4882a593Smuzhiyun 	if (!led) {
4024*4882a593Smuzhiyun 		hid_err(wacom->hdev, "can't find current LED %d in group %d\n",
4025*4882a593Smuzhiyun 			cur, group);
4026*4882a593Smuzhiyun 		return;
4027*4882a593Smuzhiyun 	}
4028*4882a593Smuzhiyun 
4029*4882a593Smuzhiyun 	if (!pressed) {
4030*4882a593Smuzhiyun 		led->held = false;
4031*4882a593Smuzhiyun 		return;
4032*4882a593Smuzhiyun 	}
4033*4882a593Smuzhiyun 
4034*4882a593Smuzhiyun 	if (led->held && pressed)
4035*4882a593Smuzhiyun 		return;
4036*4882a593Smuzhiyun 
4037*4882a593Smuzhiyun 	next_led = wacom_led_next(wacom, led);
4038*4882a593Smuzhiyun 	if (!next_led) {
4039*4882a593Smuzhiyun 		hid_err(wacom->hdev, "can't find next LED in group %d\n",
4040*4882a593Smuzhiyun 			group);
4041*4882a593Smuzhiyun 		return;
4042*4882a593Smuzhiyun 	}
4043*4882a593Smuzhiyun 	if (next_led == led)
4044*4882a593Smuzhiyun 		return;
4045*4882a593Smuzhiyun 
4046*4882a593Smuzhiyun 	next_led->held = true;
4047*4882a593Smuzhiyun 	led_trigger_event(&next_led->trigger,
4048*4882a593Smuzhiyun 			  wacom_leds_brightness_get(next_led));
4049*4882a593Smuzhiyun }
4050*4882a593Smuzhiyun 
wacom_report_numbered_buttons(struct input_dev * input_dev,int button_count,int mask)4051*4882a593Smuzhiyun static void wacom_report_numbered_buttons(struct input_dev *input_dev,
4052*4882a593Smuzhiyun 				int button_count, int mask)
4053*4882a593Smuzhiyun {
4054*4882a593Smuzhiyun 	struct wacom *wacom = input_get_drvdata(input_dev);
4055*4882a593Smuzhiyun 	int i;
4056*4882a593Smuzhiyun 
4057*4882a593Smuzhiyun 	for (i = 0; i < wacom->led.count; i++)
4058*4882a593Smuzhiyun 		wacom_update_led(wacom,  button_count, mask, i);
4059*4882a593Smuzhiyun 
4060*4882a593Smuzhiyun 	for (i = 0; i < button_count; i++) {
4061*4882a593Smuzhiyun 		int key = wacom_numbered_button_to_key(i);
4062*4882a593Smuzhiyun 
4063*4882a593Smuzhiyun 		if (key)
4064*4882a593Smuzhiyun 			input_report_key(input_dev, key, mask & (1 << i));
4065*4882a593Smuzhiyun 	}
4066*4882a593Smuzhiyun }
4067*4882a593Smuzhiyun 
wacom_setup_pad_input_capabilities(struct input_dev * input_dev,struct wacom_wac * wacom_wac)4068*4882a593Smuzhiyun int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
4069*4882a593Smuzhiyun 				   struct wacom_wac *wacom_wac)
4070*4882a593Smuzhiyun {
4071*4882a593Smuzhiyun 	struct wacom_features *features = &wacom_wac->features;
4072*4882a593Smuzhiyun 
4073*4882a593Smuzhiyun 	if ((features->type == HID_GENERIC) && features->numbered_buttons > 0)
4074*4882a593Smuzhiyun 		features->device_type |= WACOM_DEVICETYPE_PAD;
4075*4882a593Smuzhiyun 
4076*4882a593Smuzhiyun 	if (!(features->device_type & WACOM_DEVICETYPE_PAD))
4077*4882a593Smuzhiyun 		return -ENODEV;
4078*4882a593Smuzhiyun 
4079*4882a593Smuzhiyun 	if (features->type == REMOTE && input_dev == wacom_wac->pad_input)
4080*4882a593Smuzhiyun 		return -ENODEV;
4081*4882a593Smuzhiyun 
4082*4882a593Smuzhiyun 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
4083*4882a593Smuzhiyun 
4084*4882a593Smuzhiyun 	/* kept for making legacy xf86-input-wacom working with the wheels */
4085*4882a593Smuzhiyun 	__set_bit(ABS_MISC, input_dev->absbit);
4086*4882a593Smuzhiyun 
4087*4882a593Smuzhiyun 	/* kept for making legacy xf86-input-wacom accepting the pad */
4088*4882a593Smuzhiyun 	if (!(input_dev->absinfo && (input_dev->absinfo[ABS_X].minimum ||
4089*4882a593Smuzhiyun 	      input_dev->absinfo[ABS_X].maximum)))
4090*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
4091*4882a593Smuzhiyun 	if (!(input_dev->absinfo && (input_dev->absinfo[ABS_Y].minimum ||
4092*4882a593Smuzhiyun 	      input_dev->absinfo[ABS_Y].maximum)))
4093*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
4094*4882a593Smuzhiyun 
4095*4882a593Smuzhiyun 	/* kept for making udev and libwacom accepting the pad */
4096*4882a593Smuzhiyun 	__set_bit(BTN_STYLUS, input_dev->keybit);
4097*4882a593Smuzhiyun 
4098*4882a593Smuzhiyun 	wacom_setup_numbered_buttons(input_dev, features->numbered_buttons);
4099*4882a593Smuzhiyun 
4100*4882a593Smuzhiyun 	switch (features->type) {
4101*4882a593Smuzhiyun 
4102*4882a593Smuzhiyun 	case CINTIQ_HYBRID:
4103*4882a593Smuzhiyun 	case CINTIQ_COMPANION_2:
4104*4882a593Smuzhiyun 	case DTK:
4105*4882a593Smuzhiyun 	case DTUS:
4106*4882a593Smuzhiyun 	case GRAPHIRE_BT:
4107*4882a593Smuzhiyun 		break;
4108*4882a593Smuzhiyun 
4109*4882a593Smuzhiyun 	case WACOM_MO:
4110*4882a593Smuzhiyun 		__set_bit(BTN_BACK, input_dev->keybit);
4111*4882a593Smuzhiyun 		__set_bit(BTN_LEFT, input_dev->keybit);
4112*4882a593Smuzhiyun 		__set_bit(BTN_FORWARD, input_dev->keybit);
4113*4882a593Smuzhiyun 		__set_bit(BTN_RIGHT, input_dev->keybit);
4114*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4115*4882a593Smuzhiyun 		break;
4116*4882a593Smuzhiyun 
4117*4882a593Smuzhiyun 	case WACOM_G4:
4118*4882a593Smuzhiyun 		__set_bit(BTN_BACK, input_dev->keybit);
4119*4882a593Smuzhiyun 		__set_bit(BTN_FORWARD, input_dev->keybit);
4120*4882a593Smuzhiyun 		input_set_capability(input_dev, EV_REL, REL_WHEEL);
4121*4882a593Smuzhiyun 		break;
4122*4882a593Smuzhiyun 
4123*4882a593Smuzhiyun 	case WACOM_24HD:
4124*4882a593Smuzhiyun 		__set_bit(KEY_PROG1, input_dev->keybit);
4125*4882a593Smuzhiyun 		__set_bit(KEY_PROG2, input_dev->keybit);
4126*4882a593Smuzhiyun 		__set_bit(KEY_PROG3, input_dev->keybit);
4127*4882a593Smuzhiyun 
4128*4882a593Smuzhiyun 		__set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
4129*4882a593Smuzhiyun 		__set_bit(KEY_INFO, input_dev->keybit);
4130*4882a593Smuzhiyun 
4131*4882a593Smuzhiyun 		if (!features->oPid)
4132*4882a593Smuzhiyun 			__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
4133*4882a593Smuzhiyun 
4134*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4135*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
4136*4882a593Smuzhiyun 		break;
4137*4882a593Smuzhiyun 
4138*4882a593Smuzhiyun 	case WACOM_27QHD:
4139*4882a593Smuzhiyun 		__set_bit(KEY_PROG1, input_dev->keybit);
4140*4882a593Smuzhiyun 		__set_bit(KEY_PROG2, input_dev->keybit);
4141*4882a593Smuzhiyun 		__set_bit(KEY_PROG3, input_dev->keybit);
4142*4882a593Smuzhiyun 
4143*4882a593Smuzhiyun 		__set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
4144*4882a593Smuzhiyun 		__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
4145*4882a593Smuzhiyun 
4146*4882a593Smuzhiyun 		if (!features->oPid)
4147*4882a593Smuzhiyun 			__set_bit(KEY_CONTROLPANEL, input_dev->keybit);
4148*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0);
4149*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
4150*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0);
4151*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_Y, 1024);
4152*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0);
4153*4882a593Smuzhiyun 		input_abs_set_res(input_dev, ABS_Z, 1024);
4154*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
4155*4882a593Smuzhiyun 		break;
4156*4882a593Smuzhiyun 
4157*4882a593Smuzhiyun 	case WACOM_22HD:
4158*4882a593Smuzhiyun 		__set_bit(KEY_PROG1, input_dev->keybit);
4159*4882a593Smuzhiyun 		__set_bit(KEY_PROG2, input_dev->keybit);
4160*4882a593Smuzhiyun 		__set_bit(KEY_PROG3, input_dev->keybit);
4161*4882a593Smuzhiyun 
4162*4882a593Smuzhiyun 		__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
4163*4882a593Smuzhiyun 		__set_bit(KEY_INFO, input_dev->keybit);
4164*4882a593Smuzhiyun 		fallthrough;
4165*4882a593Smuzhiyun 
4166*4882a593Smuzhiyun 	case WACOM_21UX2:
4167*4882a593Smuzhiyun 	case WACOM_BEE:
4168*4882a593Smuzhiyun 	case CINTIQ:
4169*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
4170*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
4171*4882a593Smuzhiyun 		break;
4172*4882a593Smuzhiyun 
4173*4882a593Smuzhiyun 	case WACOM_13HD:
4174*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4175*4882a593Smuzhiyun 		break;
4176*4882a593Smuzhiyun 
4177*4882a593Smuzhiyun 	case INTUOS3:
4178*4882a593Smuzhiyun 	case INTUOS3L:
4179*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
4180*4882a593Smuzhiyun 		fallthrough;
4181*4882a593Smuzhiyun 
4182*4882a593Smuzhiyun 	case INTUOS3S:
4183*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
4184*4882a593Smuzhiyun 		break;
4185*4882a593Smuzhiyun 
4186*4882a593Smuzhiyun 	case INTUOS5:
4187*4882a593Smuzhiyun 	case INTUOS5L:
4188*4882a593Smuzhiyun 	case INTUOSPM:
4189*4882a593Smuzhiyun 	case INTUOSPL:
4190*4882a593Smuzhiyun 	case INTUOS5S:
4191*4882a593Smuzhiyun 	case INTUOSPS:
4192*4882a593Smuzhiyun 	case INTUOSP2_BT:
4193*4882a593Smuzhiyun 	case INTUOSP2S_BT:
4194*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4195*4882a593Smuzhiyun 		break;
4196*4882a593Smuzhiyun 
4197*4882a593Smuzhiyun 	case INTUOS4WL:
4198*4882a593Smuzhiyun 		/*
4199*4882a593Smuzhiyun 		 * For Bluetooth devices, the udev rule does not work correctly
4200*4882a593Smuzhiyun 		 * for pads unless we add a stylus capability, which forces
4201*4882a593Smuzhiyun 		 * ID_INPUT_TABLET to be set.
4202*4882a593Smuzhiyun 		 */
4203*4882a593Smuzhiyun 		__set_bit(BTN_STYLUS, input_dev->keybit);
4204*4882a593Smuzhiyun 		fallthrough;
4205*4882a593Smuzhiyun 
4206*4882a593Smuzhiyun 	case INTUOS4:
4207*4882a593Smuzhiyun 	case INTUOS4L:
4208*4882a593Smuzhiyun 	case INTUOS4S:
4209*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4210*4882a593Smuzhiyun 		break;
4211*4882a593Smuzhiyun 
4212*4882a593Smuzhiyun 	case INTUOSHT:
4213*4882a593Smuzhiyun 	case BAMBOO_PT:
4214*4882a593Smuzhiyun 	case BAMBOO_TOUCH:
4215*4882a593Smuzhiyun 	case INTUOSHT2:
4216*4882a593Smuzhiyun 		__clear_bit(ABS_MISC, input_dev->absbit);
4217*4882a593Smuzhiyun 
4218*4882a593Smuzhiyun 		__set_bit(BTN_LEFT, input_dev->keybit);
4219*4882a593Smuzhiyun 		__set_bit(BTN_FORWARD, input_dev->keybit);
4220*4882a593Smuzhiyun 		__set_bit(BTN_BACK, input_dev->keybit);
4221*4882a593Smuzhiyun 		__set_bit(BTN_RIGHT, input_dev->keybit);
4222*4882a593Smuzhiyun 
4223*4882a593Smuzhiyun 		break;
4224*4882a593Smuzhiyun 
4225*4882a593Smuzhiyun 	case REMOTE:
4226*4882a593Smuzhiyun 		input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
4227*4882a593Smuzhiyun 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4228*4882a593Smuzhiyun 		break;
4229*4882a593Smuzhiyun 
4230*4882a593Smuzhiyun 	case INTUOSHT3_BT:
4231*4882a593Smuzhiyun 	case HID_GENERIC:
4232*4882a593Smuzhiyun 		break;
4233*4882a593Smuzhiyun 
4234*4882a593Smuzhiyun 	default:
4235*4882a593Smuzhiyun 		/* no pad supported */
4236*4882a593Smuzhiyun 		return -ENODEV;
4237*4882a593Smuzhiyun 	}
4238*4882a593Smuzhiyun 	return 0;
4239*4882a593Smuzhiyun }
4240*4882a593Smuzhiyun 
4241*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x00 =
4242*4882a593Smuzhiyun 	{ "Wacom Penpartner", 5040, 3780, 255, 0,
4243*4882a593Smuzhiyun 	  PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
4244*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x10 =
4245*4882a593Smuzhiyun 	{ "Wacom Graphire", 10206, 7422, 511, 63,
4246*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4247*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x81 =
4248*4882a593Smuzhiyun 	{ "Wacom Graphire BT", 16704, 12064, 511, 32,
4249*4882a593Smuzhiyun 	  GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES, 2 };
4250*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x11 =
4251*4882a593Smuzhiyun 	{ "Wacom Graphire2 4x5", 10206, 7422, 511, 63,
4252*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4253*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x12 =
4254*4882a593Smuzhiyun 	{ "Wacom Graphire2 5x7", 13918, 10206, 511, 63,
4255*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4256*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x13 =
4257*4882a593Smuzhiyun 	{ "Wacom Graphire3", 10208, 7424, 511, 63,
4258*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4259*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x14 =
4260*4882a593Smuzhiyun 	{ "Wacom Graphire3 6x8", 16704, 12064, 511, 63,
4261*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4262*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x15 =
4263*4882a593Smuzhiyun 	{ "Wacom Graphire4 4x5", 10208, 7424, 511, 63,
4264*4882a593Smuzhiyun 	  WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4265*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x16 =
4266*4882a593Smuzhiyun 	{ "Wacom Graphire4 6x8", 16704, 12064, 511, 63,
4267*4882a593Smuzhiyun 	  WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4268*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x17 =
4269*4882a593Smuzhiyun 	{ "Wacom BambooFun 4x5", 14760, 9225, 511, 63,
4270*4882a593Smuzhiyun 	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4271*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x18 =
4272*4882a593Smuzhiyun 	{ "Wacom BambooFun 6x8", 21648, 13530, 511, 63,
4273*4882a593Smuzhiyun 	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4274*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x19 =
4275*4882a593Smuzhiyun 	{ "Wacom Bamboo1 Medium", 16704, 12064, 511, 63,
4276*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4277*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x60 =
4278*4882a593Smuzhiyun 	{ "Wacom Volito", 5104, 3712, 511, 63,
4279*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4280*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x61 =
4281*4882a593Smuzhiyun 	{ "Wacom PenStation2", 3250, 2320, 255, 63,
4282*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4283*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x62 =
4284*4882a593Smuzhiyun 	{ "Wacom Volito2 4x5", 5104, 3712, 511, 63,
4285*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4286*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x63 =
4287*4882a593Smuzhiyun 	{ "Wacom Volito2 2x3", 3248, 2320, 511, 63,
4288*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4289*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x64 =
4290*4882a593Smuzhiyun 	{ "Wacom PenPartner2", 3250, 2320, 511, 63,
4291*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4292*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x65 =
4293*4882a593Smuzhiyun 	{ "Wacom Bamboo", 14760, 9225, 511, 63,
4294*4882a593Smuzhiyun 	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4295*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x69 =
4296*4882a593Smuzhiyun 	{ "Wacom Bamboo1", 5104, 3712, 511, 63,
4297*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
4298*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x6A =
4299*4882a593Smuzhiyun 	{ "Wacom Bamboo1 4x6", 14760, 9225, 1023, 63,
4300*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4301*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x6B =
4302*4882a593Smuzhiyun 	{ "Wacom Bamboo1 5x8", 21648, 13530, 1023, 63,
4303*4882a593Smuzhiyun 	  GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4304*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x20 =
4305*4882a593Smuzhiyun 	{ "Wacom Intuos 4x5", 12700, 10600, 1023, 31,
4306*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4307*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x21 =
4308*4882a593Smuzhiyun 	{ "Wacom Intuos 6x8", 20320, 16240, 1023, 31,
4309*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4310*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x22 =
4311*4882a593Smuzhiyun 	{ "Wacom Intuos 9x12", 30480, 24060, 1023, 31,
4312*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4313*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x23 =
4314*4882a593Smuzhiyun 	{ "Wacom Intuos 12x12", 30480, 31680, 1023, 31,
4315*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4316*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x24 =
4317*4882a593Smuzhiyun 	{ "Wacom Intuos 12x18", 45720, 31680, 1023, 31,
4318*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4319*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x30 =
4320*4882a593Smuzhiyun 	{ "Wacom PL400", 5408, 4056, 255, 0,
4321*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4322*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x31 =
4323*4882a593Smuzhiyun 	{ "Wacom PL500", 6144, 4608, 255, 0,
4324*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4325*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x32 =
4326*4882a593Smuzhiyun 	{ "Wacom PL600", 6126, 4604, 255, 0,
4327*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4328*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x33 =
4329*4882a593Smuzhiyun 	{ "Wacom PL600SX", 6260, 5016, 255, 0,
4330*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4331*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x34 =
4332*4882a593Smuzhiyun 	{ "Wacom PL550", 6144, 4608, 511, 0,
4333*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4334*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x35 =
4335*4882a593Smuzhiyun 	{ "Wacom PL800", 7220, 5780, 511, 0,
4336*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4337*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x37 =
4338*4882a593Smuzhiyun 	{ "Wacom PL700", 6758, 5406, 511, 0,
4339*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4340*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x38 =
4341*4882a593Smuzhiyun 	{ "Wacom PL510", 6282, 4762, 511, 0,
4342*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4343*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x39 =
4344*4882a593Smuzhiyun 	{ "Wacom DTU710", 34080, 27660, 511, 0,
4345*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4346*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xC4 =
4347*4882a593Smuzhiyun 	{ "Wacom DTF521", 6282, 4762, 511, 0,
4348*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4349*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xC0 =
4350*4882a593Smuzhiyun 	{ "Wacom DTF720", 6858, 5506, 511, 0,
4351*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4352*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xC2 =
4353*4882a593Smuzhiyun 	{ "Wacom DTF720a", 6858, 5506, 511, 0,
4354*4882a593Smuzhiyun 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4355*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x03 =
4356*4882a593Smuzhiyun 	{ "Wacom Cintiq Partner", 20480, 15360, 511, 0,
4357*4882a593Smuzhiyun 	  PTU, WACOM_PL_RES, WACOM_PL_RES };
4358*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x41 =
4359*4882a593Smuzhiyun 	{ "Wacom Intuos2 4x5", 12700, 10600, 1023, 31,
4360*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4361*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x42 =
4362*4882a593Smuzhiyun 	{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
4363*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4364*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x43 =
4365*4882a593Smuzhiyun 	{ "Wacom Intuos2 9x12", 30480, 24060, 1023, 31,
4366*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4367*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x44 =
4368*4882a593Smuzhiyun 	{ "Wacom Intuos2 12x12", 30480, 31680, 1023, 31,
4369*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4370*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x45 =
4371*4882a593Smuzhiyun 	{ "Wacom Intuos2 12x18", 45720, 31680, 1023, 31,
4372*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4373*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB0 =
4374*4882a593Smuzhiyun 	{ "Wacom Intuos3 4x5", 25400, 20320, 1023, 63,
4375*4882a593Smuzhiyun 	  INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 };
4376*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB1 =
4377*4882a593Smuzhiyun 	{ "Wacom Intuos3 6x8", 40640, 30480, 1023, 63,
4378*4882a593Smuzhiyun 	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4379*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB2 =
4380*4882a593Smuzhiyun 	{ "Wacom Intuos3 9x12", 60960, 45720, 1023, 63,
4381*4882a593Smuzhiyun 	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4382*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB3 =
4383*4882a593Smuzhiyun 	{ "Wacom Intuos3 12x12", 60960, 60960, 1023, 63,
4384*4882a593Smuzhiyun 	  INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4385*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB4 =
4386*4882a593Smuzhiyun 	{ "Wacom Intuos3 12x19", 97536, 60960, 1023, 63,
4387*4882a593Smuzhiyun 	  INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4388*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB5 =
4389*4882a593Smuzhiyun 	{ "Wacom Intuos3 6x11", 54204, 31750, 1023, 63,
4390*4882a593Smuzhiyun 	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4391*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB7 =
4392*4882a593Smuzhiyun 	{ "Wacom Intuos3 4x6", 31496, 19685, 1023, 63,
4393*4882a593Smuzhiyun 	  INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 };
4394*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB8 =
4395*4882a593Smuzhiyun 	{ "Wacom Intuos4 4x6", 31496, 19685, 2047, 63,
4396*4882a593Smuzhiyun 	  INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 };
4397*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xB9 =
4398*4882a593Smuzhiyun 	{ "Wacom Intuos4 6x9", 44704, 27940, 2047, 63,
4399*4882a593Smuzhiyun 	  INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4400*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xBA =
4401*4882a593Smuzhiyun 	{ "Wacom Intuos4 8x13", 65024, 40640, 2047, 63,
4402*4882a593Smuzhiyun 	  INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4403*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xBB =
4404*4882a593Smuzhiyun 	{ "Wacom Intuos4 12x19", 97536, 60960, 2047, 63,
4405*4882a593Smuzhiyun 	  INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4406*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xBC =
4407*4882a593Smuzhiyun 	{ "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
4408*4882a593Smuzhiyun 	  INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4409*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xBD =
4410*4882a593Smuzhiyun 	{ "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
4411*4882a593Smuzhiyun 	  INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4412*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x26 =
4413*4882a593Smuzhiyun 	{ "Wacom Intuos5 touch S", 31496, 19685, 2047, 63,
4414*4882a593Smuzhiyun 	  INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 };
4415*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x27 =
4416*4882a593Smuzhiyun 	{ "Wacom Intuos5 touch M", 44704, 27940, 2047, 63,
4417*4882a593Smuzhiyun 	  INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 };
4418*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x28 =
4419*4882a593Smuzhiyun 	{ "Wacom Intuos5 touch L", 65024, 40640, 2047, 63,
4420*4882a593Smuzhiyun 	  INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 };
4421*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x29 =
4422*4882a593Smuzhiyun 	{ "Wacom Intuos5 S", 31496, 19685, 2047, 63,
4423*4882a593Smuzhiyun 	  INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 };
4424*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x2A =
4425*4882a593Smuzhiyun 	{ "Wacom Intuos5 M", 44704, 27940, 2047, 63,
4426*4882a593Smuzhiyun 	  INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4427*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x314 =
4428*4882a593Smuzhiyun 	{ "Wacom Intuos Pro S", 31496, 19685, 2047, 63,
4429*4882a593Smuzhiyun 	  INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16,
4430*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4431*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x315 =
4432*4882a593Smuzhiyun 	{ "Wacom Intuos Pro M", 44704, 27940, 2047, 63,
4433*4882a593Smuzhiyun 	  INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16,
4434*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4435*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x317 =
4436*4882a593Smuzhiyun 	{ "Wacom Intuos Pro L", 65024, 40640, 2047, 63,
4437*4882a593Smuzhiyun 	  INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16,
4438*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4439*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xF4 =
4440*4882a593Smuzhiyun 	{ "Wacom Cintiq 24HD", 104480, 65600, 2047, 63,
4441*4882a593Smuzhiyun 	  WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16,
4442*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4443*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4444*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xF8 =
4445*4882a593Smuzhiyun 	{ "Wacom Cintiq 24HD touch", 104480, 65600, 2047, 63, /* Pen */
4446*4882a593Smuzhiyun 	  WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16,
4447*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4448*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4449*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
4450*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xF6 =
4451*4882a593Smuzhiyun 	{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
4452*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
4453*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4454*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x32A =
4455*4882a593Smuzhiyun 	{ "Wacom Cintiq 27QHD", 120140, 67920, 2047, 63,
4456*4882a593Smuzhiyun 	  WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0,
4457*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4458*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4459*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x32B =
4460*4882a593Smuzhiyun 	{ "Wacom Cintiq 27QHD touch", 120140, 67920, 2047, 63,
4461*4882a593Smuzhiyun 	  WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0,
4462*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4463*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4464*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C };
4465*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x32C =
4466*4882a593Smuzhiyun 	{ "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT,
4467*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 };
4468*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x3F =
4469*4882a593Smuzhiyun 	{ "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
4470*4882a593Smuzhiyun 	  CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4471*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xC5 =
4472*4882a593Smuzhiyun 	{ "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63,
4473*4882a593Smuzhiyun 	  WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 };
4474*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xC6 =
4475*4882a593Smuzhiyun 	{ "Wacom Cintiq 12WX", 53020, 33440, 1023, 63,
4476*4882a593Smuzhiyun 	  WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 };
4477*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x304 =
4478*4882a593Smuzhiyun 	{ "Wacom Cintiq 13HD", 59552, 33848, 1023, 63,
4479*4882a593Smuzhiyun 	  WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4480*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4481*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4482*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x333 =
4483*4882a593Smuzhiyun 	{ "Wacom Cintiq 13HD touch", 59552, 33848, 2047, 63,
4484*4882a593Smuzhiyun 	  WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4485*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4486*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4487*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 };
4488*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x335 =
4489*4882a593Smuzhiyun 	{ "Wacom Cintiq 13HD touch", .type = WACOM_24HDT, /* Touch */
4490*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x333, .touch_max = 10,
4491*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4492*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xC7 =
4493*4882a593Smuzhiyun 	{ "Wacom DTU1931", 37832, 30305, 511, 0,
4494*4882a593Smuzhiyun 	  PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4495*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xCE =
4496*4882a593Smuzhiyun 	{ "Wacom DTU2231", 47864, 27011, 511, 0,
4497*4882a593Smuzhiyun 	  DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4498*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBMOUSE };
4499*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xF0 =
4500*4882a593Smuzhiyun 	{ "Wacom DTU1631", 34623, 19553, 511, 0,
4501*4882a593Smuzhiyun 	  DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4502*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xFB =
4503*4882a593Smuzhiyun 	{ "Wacom DTU1031", 22096, 13960, 511, 0,
4504*4882a593Smuzhiyun 	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
4505*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4506*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4507*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x32F =
4508*4882a593Smuzhiyun 	{ "Wacom DTU1031X", 22672, 12928, 511, 0,
4509*4882a593Smuzhiyun 	  DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0,
4510*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4511*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4512*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x336 =
4513*4882a593Smuzhiyun 	{ "Wacom DTU1141", 23672, 13403, 1023, 0,
4514*4882a593Smuzhiyun 	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
4515*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4516*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4517*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x57 =
4518*4882a593Smuzhiyun 	{ "Wacom DTK2241", 95840, 54260, 2047, 63,
4519*4882a593Smuzhiyun 	  DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
4520*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4521*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4522*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x59 = /* Pen */
4523*4882a593Smuzhiyun 	{ "Wacom DTH2242", 95840, 54260, 2047, 63,
4524*4882a593Smuzhiyun 	  DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
4525*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4526*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4527*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
4528*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x5D = /* Touch */
4529*4882a593Smuzhiyun 	{ "Wacom DTH2242",       .type = WACOM_24HDT,
4530*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10,
4531*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4532*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xCC =
4533*4882a593Smuzhiyun 	{ "Wacom Cintiq 21UX2", 87200, 65600, 2047, 63,
4534*4882a593Smuzhiyun 	  WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
4535*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4536*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4537*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xFA =
4538*4882a593Smuzhiyun 	{ "Wacom Cintiq 22HD", 95840, 54260, 2047, 63,
4539*4882a593Smuzhiyun 	  WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
4540*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4541*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4542*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x5B =
4543*4882a593Smuzhiyun 	{ "Wacom Cintiq 22HDT", 95840, 54260, 2047, 63,
4544*4882a593Smuzhiyun 	  WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
4545*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4546*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4547*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
4548*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x5E =
4549*4882a593Smuzhiyun 	{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
4550*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10,
4551*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4552*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x90 =
4553*4882a593Smuzhiyun 	{ "Wacom ISDv4 90", 26202, 16325, 255, 0,
4554*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4555*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x93 =
4556*4882a593Smuzhiyun 	{ "Wacom ISDv4 93", 26202, 16325, 255, 0,
4557*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4558*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x97 =
4559*4882a593Smuzhiyun 	{ "Wacom ISDv4 97", 26202, 16325, 511, 0,
4560*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4561*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x9A =
4562*4882a593Smuzhiyun 	{ "Wacom ISDv4 9A", 26202, 16325, 255, 0,
4563*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4564*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x9F =
4565*4882a593Smuzhiyun 	{ "Wacom ISDv4 9F", 26202, 16325, 255, 0,
4566*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4567*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xE2 =
4568*4882a593Smuzhiyun 	{ "Wacom ISDv4 E2", 26202, 16325, 255, 0,
4569*4882a593Smuzhiyun 	  TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4570*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xE3 =
4571*4882a593Smuzhiyun 	{ "Wacom ISDv4 E3", 26202, 16325, 255, 0,
4572*4882a593Smuzhiyun 	  TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4573*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xE5 =
4574*4882a593Smuzhiyun 	{ "Wacom ISDv4 E5", 26202, 16325, 255, 0,
4575*4882a593Smuzhiyun 	  MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4576*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xE6 =
4577*4882a593Smuzhiyun 	{ "Wacom ISDv4 E6", 27760, 15694, 255, 0,
4578*4882a593Smuzhiyun 	  TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4579*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xEC =
4580*4882a593Smuzhiyun 	{ "Wacom ISDv4 EC", 25710, 14500, 255, 0,
4581*4882a593Smuzhiyun 	  TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4582*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xED =
4583*4882a593Smuzhiyun 	{ "Wacom ISDv4 ED", 26202, 16325, 255, 0,
4584*4882a593Smuzhiyun 	  TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4585*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xEF =
4586*4882a593Smuzhiyun 	{ "Wacom ISDv4 EF", 26202, 16325, 255, 0,
4587*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4588*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x100 =
4589*4882a593Smuzhiyun 	{ "Wacom ISDv4 100", 26202, 16325, 255, 0,
4590*4882a593Smuzhiyun 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4591*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x101 =
4592*4882a593Smuzhiyun 	{ "Wacom ISDv4 101", 26202, 16325, 255, 0,
4593*4882a593Smuzhiyun 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4594*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x10D =
4595*4882a593Smuzhiyun 	{ "Wacom ISDv4 10D", 26202, 16325, 255, 0,
4596*4882a593Smuzhiyun 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4597*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x10E =
4598*4882a593Smuzhiyun 	{ "Wacom ISDv4 10E", 27760, 15694, 255, 0,
4599*4882a593Smuzhiyun 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4600*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x10F =
4601*4882a593Smuzhiyun 	{ "Wacom ISDv4 10F", 27760, 15694, 255, 0,
4602*4882a593Smuzhiyun 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4603*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x116 =
4604*4882a593Smuzhiyun 	{ "Wacom ISDv4 116", 26202, 16325, 255, 0,
4605*4882a593Smuzhiyun 	  TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4606*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x12C =
4607*4882a593Smuzhiyun 	{ "Wacom ISDv4 12C", 27848, 15752, 2047, 0,
4608*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4609*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x4001 =
4610*4882a593Smuzhiyun 	{ "Wacom ISDv4 4001", 26202, 16325, 255, 0,
4611*4882a593Smuzhiyun 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4612*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x4004 =
4613*4882a593Smuzhiyun 	{ "Wacom ISDv4 4004", 11060, 6220, 255, 0,
4614*4882a593Smuzhiyun 	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4615*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x5000 =
4616*4882a593Smuzhiyun 	{ "Wacom ISDv4 5000", 27848, 15752, 1023, 0,
4617*4882a593Smuzhiyun 	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4618*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x5002 =
4619*4882a593Smuzhiyun 	{ "Wacom ISDv4 5002", 29576, 16724, 1023, 0,
4620*4882a593Smuzhiyun 	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4621*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x47 =
4622*4882a593Smuzhiyun 	{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
4623*4882a593Smuzhiyun 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4624*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x84 =
4625*4882a593Smuzhiyun 	{ "Wacom Wireless Receiver", .type = WIRELESS, .touch_max = 16 };
4626*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD0 =
4627*4882a593Smuzhiyun 	{ "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
4628*4882a593Smuzhiyun 	  BAMBOO_TOUCH, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4629*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD1 =
4630*4882a593Smuzhiyun 	{ "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
4631*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4632*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD2 =
4633*4882a593Smuzhiyun 	{ "Wacom Bamboo Craft", 14720, 9200, 1023, 31,
4634*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4635*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD3 =
4636*4882a593Smuzhiyun 	{ "Wacom Bamboo 2FG 6x8", 21648, 13700, 1023, 31,
4637*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4638*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD4 =
4639*4882a593Smuzhiyun 	{ "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
4640*4882a593Smuzhiyun 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4641*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD5 =
4642*4882a593Smuzhiyun 	{ "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
4643*4882a593Smuzhiyun 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4644*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD6 =
4645*4882a593Smuzhiyun 	{ "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
4646*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4647*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD7 =
4648*4882a593Smuzhiyun 	{ "Wacom BambooPT 2FG Small", 14720, 9200, 1023, 31,
4649*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4650*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xD8 =
4651*4882a593Smuzhiyun 	{ "Wacom Bamboo Comic 2FG", 21648, 13700, 1023, 31,
4652*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4653*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xDA =
4654*4882a593Smuzhiyun 	{ "Wacom Bamboo 2FG 4x5 SE", 14720, 9200, 1023, 31,
4655*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4656*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xDB =
4657*4882a593Smuzhiyun 	{ "Wacom Bamboo 2FG 6x8 SE", 21648, 13700, 1023, 31,
4658*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4659*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xDD =
4660*4882a593Smuzhiyun         { "Wacom Bamboo Connect", 14720, 9200, 1023, 31,
4661*4882a593Smuzhiyun           BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4662*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xDE =
4663*4882a593Smuzhiyun         { "Wacom Bamboo 16FG 4x5", 14720, 9200, 1023, 31,
4664*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
4665*4882a593Smuzhiyun static const struct wacom_features wacom_features_0xDF =
4666*4882a593Smuzhiyun         { "Wacom Bamboo 16FG 6x8", 21648, 13700, 1023, 31,
4667*4882a593Smuzhiyun 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
4668*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x300 =
4669*4882a593Smuzhiyun 	{ "Wacom Bamboo One S", 14720, 9225, 1023, 31,
4670*4882a593Smuzhiyun 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4671*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x301 =
4672*4882a593Smuzhiyun 	{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
4673*4882a593Smuzhiyun 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4674*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x302 =
4675*4882a593Smuzhiyun 	{ "Wacom Intuos PT S", 15200, 9500, 1023, 31,
4676*4882a593Smuzhiyun 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4677*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4678*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x303 =
4679*4882a593Smuzhiyun 	{ "Wacom Intuos PT M", 21600, 13500, 1023, 31,
4680*4882a593Smuzhiyun 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4681*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4682*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x30E =
4683*4882a593Smuzhiyun 	{ "Wacom Intuos S", 15200, 9500, 1023, 31,
4684*4882a593Smuzhiyun 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4685*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4686*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x6004 =
4687*4882a593Smuzhiyun 	{ "ISD-V4", 12800, 8000, 255, 0,
4688*4882a593Smuzhiyun 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4689*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x307 =
4690*4882a593Smuzhiyun 	{ "Wacom ISDv5 307", 59552, 33848, 2047, 63,
4691*4882a593Smuzhiyun 	  CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4692*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4693*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4694*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
4695*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x309 =
4696*4882a593Smuzhiyun 	{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
4697*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10,
4698*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4699*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x30A =
4700*4882a593Smuzhiyun 	{ "Wacom ISDv5 30A", 59552, 33848, 2047, 63,
4701*4882a593Smuzhiyun 	  CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4702*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4703*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4704*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C };
4705*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x30C =
4706*4882a593Smuzhiyun 	{ "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */
4707*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10,
4708*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4709*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x318 =
4710*4882a593Smuzhiyun 	{ "Wacom USB Bamboo PAD", 4095, 4095, /* Touch */
4711*4882a593Smuzhiyun 	  .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
4712*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x319 =
4713*4882a593Smuzhiyun 	{ "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
4714*4882a593Smuzhiyun 	  .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
4715*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x325 =
4716*4882a593Smuzhiyun 	{ "Wacom ISDv5 325", 59552, 33848, 2047, 63,
4717*4882a593Smuzhiyun 	  CINTIQ_COMPANION_2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 11,
4718*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4719*4882a593Smuzhiyun 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4720*4882a593Smuzhiyun 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x326 };
4721*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x326 = /* Touch */
4722*4882a593Smuzhiyun 	{ "Wacom ISDv5 326", .type = HID_GENERIC, .oVid = USB_VENDOR_ID_WACOM,
4723*4882a593Smuzhiyun 	  .oPid = 0x325 };
4724*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x323 =
4725*4882a593Smuzhiyun 	{ "Wacom Intuos P M", 21600, 13500, 1023, 31,
4726*4882a593Smuzhiyun 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4727*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4728*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x331 =
4729*4882a593Smuzhiyun 	{ "Wacom Express Key Remote", .type = REMOTE,
4730*4882a593Smuzhiyun 	  .numbered_buttons = 18, .check_for_hid_type = true,
4731*4882a593Smuzhiyun 	  .hid_type = HID_TYPE_USBNONE };
4732*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x33B =
4733*4882a593Smuzhiyun 	{ "Wacom Intuos S 2", 15200, 9500, 2047, 63,
4734*4882a593Smuzhiyun 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4735*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4736*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x33C =
4737*4882a593Smuzhiyun 	{ "Wacom Intuos PT S 2", 15200, 9500, 2047, 63,
4738*4882a593Smuzhiyun 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4739*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4740*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x33D =
4741*4882a593Smuzhiyun 	{ "Wacom Intuos P M 2", 21600, 13500, 2047, 63,
4742*4882a593Smuzhiyun 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4743*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4744*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x33E =
4745*4882a593Smuzhiyun 	{ "Wacom Intuos PT M 2", 21600, 13500, 2047, 63,
4746*4882a593Smuzhiyun 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4747*4882a593Smuzhiyun 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4748*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x343 =
4749*4882a593Smuzhiyun 	{ "Wacom DTK1651", 34816, 19759, 1023, 0,
4750*4882a593Smuzhiyun 	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
4751*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4752*4882a593Smuzhiyun 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4753*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x360 =
4754*4882a593Smuzhiyun 	{ "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
4755*4882a593Smuzhiyun 	  INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
4756*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x361 =
4757*4882a593Smuzhiyun 	{ "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
4758*4882a593Smuzhiyun 	  INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
4759*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x377 =
4760*4882a593Smuzhiyun 	{ "Wacom Intuos BT S", 15200, 9500, 4095, 63,
4761*4882a593Smuzhiyun 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
4762*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x379 =
4763*4882a593Smuzhiyun 	{ "Wacom Intuos BT M", 21600, 13500, 4095, 63,
4764*4882a593Smuzhiyun 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
4765*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x37A =
4766*4882a593Smuzhiyun 	{ "Wacom One by Wacom S", 15200, 9500, 2047, 63,
4767*4882a593Smuzhiyun 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4768*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x37B =
4769*4882a593Smuzhiyun 	{ "Wacom One by Wacom M", 21600, 13500, 2047, 63,
4770*4882a593Smuzhiyun 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4771*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x393 =
4772*4882a593Smuzhiyun 	{ "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
4773*4882a593Smuzhiyun 	  INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
4774*4882a593Smuzhiyun 	  .touch_max = 10 };
4775*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x3c6 =
4776*4882a593Smuzhiyun 	{ "Wacom Intuos BT S", 15200, 9500, 4095, 63,
4777*4882a593Smuzhiyun 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
4778*4882a593Smuzhiyun static const struct wacom_features wacom_features_0x3c8 =
4779*4882a593Smuzhiyun 	{ "Wacom Intuos BT M", 21600, 13500, 4095, 63,
4780*4882a593Smuzhiyun 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
4781*4882a593Smuzhiyun 
4782*4882a593Smuzhiyun static const struct wacom_features wacom_features_HID_ANY_ID =
4783*4882a593Smuzhiyun 	{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
4784*4882a593Smuzhiyun 
4785*4882a593Smuzhiyun #define USB_DEVICE_WACOM(prod)						\
4786*4882a593Smuzhiyun 	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4787*4882a593Smuzhiyun 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4788*4882a593Smuzhiyun 
4789*4882a593Smuzhiyun #define BT_DEVICE_WACOM(prod)						\
4790*4882a593Smuzhiyun 	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4791*4882a593Smuzhiyun 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4792*4882a593Smuzhiyun 
4793*4882a593Smuzhiyun #define I2C_DEVICE_WACOM(prod)						\
4794*4882a593Smuzhiyun 	HID_DEVICE(BUS_I2C, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4795*4882a593Smuzhiyun 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4796*4882a593Smuzhiyun 
4797*4882a593Smuzhiyun #define USB_DEVICE_LENOVO(prod)					\
4798*4882a593Smuzhiyun 	HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),			\
4799*4882a593Smuzhiyun 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4800*4882a593Smuzhiyun 
4801*4882a593Smuzhiyun const struct hid_device_id wacom_ids[] = {
4802*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x00) },
4803*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x03) },
4804*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x10) },
4805*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x11) },
4806*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x12) },
4807*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x13) },
4808*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x14) },
4809*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x15) },
4810*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x16) },
4811*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x17) },
4812*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x18) },
4813*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x19) },
4814*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x20) },
4815*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x21) },
4816*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x22) },
4817*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x23) },
4818*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x24) },
4819*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x26) },
4820*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x27) },
4821*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x28) },
4822*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x29) },
4823*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x2A) },
4824*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x30) },
4825*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x31) },
4826*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x32) },
4827*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x33) },
4828*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x34) },
4829*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x35) },
4830*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x37) },
4831*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x38) },
4832*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x39) },
4833*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x3F) },
4834*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x41) },
4835*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x42) },
4836*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x43) },
4837*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x44) },
4838*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x45) },
4839*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x47) },
4840*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x57) },
4841*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x59) },
4842*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x5B) },
4843*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x5D) },
4844*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x5E) },
4845*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x60) },
4846*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x61) },
4847*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x62) },
4848*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x63) },
4849*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x64) },
4850*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x65) },
4851*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x69) },
4852*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x6A) },
4853*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x6B) },
4854*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x81) },
4855*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x84) },
4856*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x90) },
4857*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x93) },
4858*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x97) },
4859*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x9A) },
4860*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x9F) },
4861*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB0) },
4862*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB1) },
4863*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB2) },
4864*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB3) },
4865*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB4) },
4866*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB5) },
4867*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB7) },
4868*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB8) },
4869*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xB9) },
4870*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xBA) },
4871*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xBB) },
4872*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xBC) },
4873*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0xBD) },
4874*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xC0) },
4875*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xC2) },
4876*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xC4) },
4877*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xC5) },
4878*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xC6) },
4879*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xC7) },
4880*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xCC) },
4881*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xCE) },
4882*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD0) },
4883*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD1) },
4884*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD2) },
4885*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD3) },
4886*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD4) },
4887*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD5) },
4888*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD6) },
4889*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD7) },
4890*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xD8) },
4891*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xDA) },
4892*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xDB) },
4893*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xDD) },
4894*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xDE) },
4895*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xDF) },
4896*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xE2) },
4897*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xE3) },
4898*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xE5) },
4899*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xE6) },
4900*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xEC) },
4901*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xED) },
4902*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xEF) },
4903*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xF0) },
4904*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xF4) },
4905*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xF6) },
4906*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xF8) },
4907*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xFA) },
4908*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0xFB) },
4909*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x100) },
4910*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x101) },
4911*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x10D) },
4912*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x10E) },
4913*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x10F) },
4914*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x116) },
4915*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x12C) },
4916*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x300) },
4917*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x301) },
4918*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x302) },
4919*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x303) },
4920*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x304) },
4921*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x307) },
4922*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x309) },
4923*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x30A) },
4924*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x30C) },
4925*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x30E) },
4926*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x314) },
4927*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x315) },
4928*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x317) },
4929*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x318) },
4930*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x319) },
4931*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x323) },
4932*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x325) },
4933*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x326) },
4934*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x32A) },
4935*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x32B) },
4936*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x32C) },
4937*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x32F) },
4938*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x331) },
4939*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x333) },
4940*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x335) },
4941*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x336) },
4942*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x33B) },
4943*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x33C) },
4944*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x33D) },
4945*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x33E) },
4946*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x343) },
4947*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x360) },
4948*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x361) },
4949*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x377) },
4950*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x379) },
4951*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x37A) },
4952*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x37B) },
4953*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x393) },
4954*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x3c6) },
4955*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(0x3c8) },
4956*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x4001) },
4957*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x4004) },
4958*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x5000) },
4959*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(0x5002) },
4960*4882a593Smuzhiyun 	{ USB_DEVICE_LENOVO(0x6004) },
4961*4882a593Smuzhiyun 
4962*4882a593Smuzhiyun 	{ USB_DEVICE_WACOM(HID_ANY_ID) },
4963*4882a593Smuzhiyun 	{ I2C_DEVICE_WACOM(HID_ANY_ID) },
4964*4882a593Smuzhiyun 	{ BT_DEVICE_WACOM(HID_ANY_ID) },
4965*4882a593Smuzhiyun 	{ }
4966*4882a593Smuzhiyun };
4967*4882a593Smuzhiyun MODULE_DEVICE_TABLE(hid, wacom_ids);
4968