xref: /openbmc/linux/drivers/hid/wacom_wac.c (revision 360823a09426347ea8f232b0b0b5156d0aed0302)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2471d1714SBenjamin Tissoires /*
3471d1714SBenjamin Tissoires  *  USB Wacom tablet support - Wacom specific code
4471d1714SBenjamin Tissoires  */
5471d1714SBenjamin Tissoires 
6471d1714SBenjamin Tissoires #include "wacom_wac.h"
7471d1714SBenjamin Tissoires #include "wacom.h"
8471d1714SBenjamin Tissoires #include <linux/input/mt.h>
994b17905SJason Gerecke #include <linux/jiffies.h>
10471d1714SBenjamin Tissoires 
11471d1714SBenjamin Tissoires /* resolution for penabled devices */
12471d1714SBenjamin Tissoires #define WACOM_PL_RES		20
13471d1714SBenjamin Tissoires #define WACOM_PENPRTN_RES	40
14471d1714SBenjamin Tissoires #define WACOM_VOLITO_RES	50
15471d1714SBenjamin Tissoires #define WACOM_GRAPHIRE_RES	80
16471d1714SBenjamin Tissoires #define WACOM_INTUOS_RES	100
17471d1714SBenjamin Tissoires #define WACOM_INTUOS3_RES	200
18471d1714SBenjamin Tissoires 
19fa770340SPing Cheng /* Newer Cintiq and DTU have an offset between tablet and screen areas */
20fa770340SPing Cheng #define WACOM_DTU_OFFSET	200
21fa770340SPing Cheng #define WACOM_CINTIQ_OFFSET	400
22fa770340SPing Cheng 
23387142bbSBenjamin Tissoires /*
24387142bbSBenjamin Tissoires  * Scale factor relating reported contact size to logical contact area.
25471d1714SBenjamin Tissoires  * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
26471d1714SBenjamin Tissoires  */
27471d1714SBenjamin Tissoires #define WACOM_CONTACT_AREA_SCALE 2607
28471d1714SBenjamin Tissoires 
291924e05eSPing Cheng static bool touch_arbitration = 1;
301924e05eSPing Cheng module_param(touch_arbitration, bool, 0644);
311924e05eSPing Cheng MODULE_PARM_DESC(touch_arbitration, " on (Y) off (N)");
321924e05eSPing Cheng 
33c7f0522aSJason Gerecke static void wacom_report_numbered_buttons(struct input_dev *input_dev,
34c7f0522aSJason Gerecke 				int button_count, int mask);
35c7f0522aSJason Gerecke 
365922e613SJason Gerecke static int wacom_numbered_button_to_key(int n);
375922e613SJason Gerecke 
3810c55cacSAaron Armstrong Skomra static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
3910c55cacSAaron Armstrong Skomra 			     int group);
4094b17905SJason Gerecke 
wacom_force_proxout(struct wacom_wac * wacom_wac)4194b17905SJason Gerecke static void wacom_force_proxout(struct wacom_wac *wacom_wac)
4294b17905SJason Gerecke {
4394b17905SJason Gerecke 	struct input_dev *input = wacom_wac->pen_input;
4494b17905SJason Gerecke 
4594b17905SJason Gerecke 	wacom_wac->shared->stylus_in_proximity = 0;
4694b17905SJason Gerecke 
4794b17905SJason Gerecke 	input_report_key(input, BTN_TOUCH, 0);
4894b17905SJason Gerecke 	input_report_key(input, BTN_STYLUS, 0);
4994b17905SJason Gerecke 	input_report_key(input, BTN_STYLUS2, 0);
5094b17905SJason Gerecke 	input_report_key(input, BTN_STYLUS3, 0);
5194b17905SJason Gerecke 	input_report_key(input, wacom_wac->tool[0], 0);
5294b17905SJason Gerecke 	if (wacom_wac->serial[0]) {
5394b17905SJason Gerecke 		input_report_abs(input, ABS_MISC, 0);
5494b17905SJason Gerecke 	}
5594b17905SJason Gerecke 	input_report_abs(input, ABS_PRESSURE, 0);
5694b17905SJason Gerecke 
5794b17905SJason Gerecke 	wacom_wac->tool[0] = 0;
5894b17905SJason Gerecke 	wacom_wac->id[0] = 0;
5994b17905SJason Gerecke 	wacom_wac->serial[0] = 0;
6094b17905SJason Gerecke 
6194b17905SJason Gerecke 	input_sync(input);
6294b17905SJason Gerecke }
6394b17905SJason Gerecke 
wacom_idleprox_timeout(struct timer_list * list)6494b17905SJason Gerecke void wacom_idleprox_timeout(struct timer_list *list)
6594b17905SJason Gerecke {
6694b17905SJason Gerecke 	struct wacom *wacom = from_timer(wacom, list, idleprox_timer);
6794b17905SJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
6894b17905SJason Gerecke 
6994b17905SJason Gerecke 	if (!wacom_wac->hid_data.sense_state) {
7094b17905SJason Gerecke 		return;
7194b17905SJason Gerecke 	}
7294b17905SJason Gerecke 
7394b17905SJason Gerecke 	hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__);
7494b17905SJason Gerecke 	wacom_force_proxout(wacom_wac);
7594b17905SJason Gerecke }
7694b17905SJason Gerecke 
77387142bbSBenjamin Tissoires /*
78387142bbSBenjamin Tissoires  * Percent of battery capacity for Graphire.
79387142bbSBenjamin Tissoires  * 8th value means AC online and show 100% capacity.
80387142bbSBenjamin Tissoires  */
81387142bbSBenjamin Tissoires static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
82387142bbSBenjamin Tissoires 
8381af7e61SBenjamin Tissoires /*
8481af7e61SBenjamin Tissoires  * Percent of battery capacity for Intuos4 WL, AC has a separate bit.
8581af7e61SBenjamin Tissoires  */
8681af7e61SBenjamin Tissoires static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
8781af7e61SBenjamin Tissoires 
__wacom_notify_battery(struct wacom_battery * battery,int bat_status,int bat_capacity,bool bat_charging,bool bat_connected,bool ps_connected)8859d69bc8SBenjamin Tissoires static void __wacom_notify_battery(struct wacom_battery *battery,
8916e45989SJason Gerecke 				   int bat_status, int bat_capacity,
9016e45989SJason Gerecke 				   bool bat_charging, bool bat_connected,
9116e45989SJason Gerecke 				   bool ps_connected)
9259d69bc8SBenjamin Tissoires {
9316e45989SJason Gerecke 	bool changed = battery->bat_status       != bat_status    ||
9416e45989SJason Gerecke 		       battery->battery_capacity != bat_capacity  ||
9559d69bc8SBenjamin Tissoires 		       battery->bat_charging     != bat_charging  ||
9659d69bc8SBenjamin Tissoires 		       battery->bat_connected    != bat_connected ||
9759d69bc8SBenjamin Tissoires 		       battery->ps_connected     != ps_connected;
9859d69bc8SBenjamin Tissoires 
9959d69bc8SBenjamin Tissoires 	if (changed) {
10016e45989SJason Gerecke 		battery->bat_status = bat_status;
10159d69bc8SBenjamin Tissoires 		battery->battery_capacity = bat_capacity;
10259d69bc8SBenjamin Tissoires 		battery->bat_charging = bat_charging;
10359d69bc8SBenjamin Tissoires 		battery->bat_connected = bat_connected;
10459d69bc8SBenjamin Tissoires 		battery->ps_connected = ps_connected;
10559d69bc8SBenjamin Tissoires 
10659d69bc8SBenjamin Tissoires 		if (battery->battery)
10759d69bc8SBenjamin Tissoires 			power_supply_changed(battery->battery);
10859d69bc8SBenjamin Tissoires 	}
10959d69bc8SBenjamin Tissoires }
11059d69bc8SBenjamin Tissoires 
wacom_notify_battery(struct wacom_wac * wacom_wac,int bat_status,int bat_capacity,bool bat_charging,bool bat_connected,bool ps_connected)111953f2c5fSJason Gerecke static void wacom_notify_battery(struct wacom_wac *wacom_wac,
11216e45989SJason Gerecke 	int bat_status, int bat_capacity, bool bat_charging,
11316e45989SJason Gerecke 	bool bat_connected, bool ps_connected)
114953f2c5fSJason Gerecke {
115953f2c5fSJason Gerecke 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
1167fc68653SJason Gerecke 	bool bat_initialized = wacom->battery.battery;
1177fc68653SJason Gerecke 	bool has_quirk = wacom_wac->features.quirks & WACOM_QUIRK_BATTERY;
1187fc68653SJason Gerecke 
1197fc68653SJason Gerecke 	if (bat_initialized != has_quirk)
1207fc68653SJason Gerecke 		wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
121953f2c5fSJason Gerecke 
12216e45989SJason Gerecke 	__wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
12316e45989SJason Gerecke 			       bat_charging, bat_connected, ps_connected);
124953f2c5fSJason Gerecke }
125953f2c5fSJason Gerecke 
wacom_penpartner_irq(struct wacom_wac * wacom)126471d1714SBenjamin Tissoires static int wacom_penpartner_irq(struct wacom_wac *wacom)
127471d1714SBenjamin Tissoires {
128471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
1292a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
130471d1714SBenjamin Tissoires 
131471d1714SBenjamin Tissoires 	switch (data[0]) {
132471d1714SBenjamin Tissoires 	case 1:
133471d1714SBenjamin Tissoires 		if (data[5] & 0x80) {
134471d1714SBenjamin Tissoires 			wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
135471d1714SBenjamin Tissoires 			wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
136471d1714SBenjamin Tissoires 			input_report_key(input, wacom->tool[0], 1);
137471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
138471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
139471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
140471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
141471d1714SBenjamin Tissoires 			input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127));
142471d1714SBenjamin Tissoires 			input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
143471d1714SBenjamin Tissoires 		} else {
144471d1714SBenjamin Tissoires 			input_report_key(input, wacom->tool[0], 0);
145471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MISC, 0); /* report tool id */
146471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_PRESSURE, -1);
147471d1714SBenjamin Tissoires 			input_report_key(input, BTN_TOUCH, 0);
148471d1714SBenjamin Tissoires 		}
149471d1714SBenjamin Tissoires 		break;
150471d1714SBenjamin Tissoires 
151471d1714SBenjamin Tissoires 	case 2:
152471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOOL_PEN, 1);
153471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
154471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
155471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
156471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
157471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
158471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
159471d1714SBenjamin Tissoires 		break;
160471d1714SBenjamin Tissoires 
161471d1714SBenjamin Tissoires 	default:
162471d1714SBenjamin Tissoires 		dev_dbg(input->dev.parent,
163471d1714SBenjamin Tissoires 			"%s: received unknown report #%d\n", __func__, data[0]);
164471d1714SBenjamin Tissoires 		return 0;
165471d1714SBenjamin Tissoires         }
166471d1714SBenjamin Tissoires 
167471d1714SBenjamin Tissoires 	return 1;
168471d1714SBenjamin Tissoires }
169471d1714SBenjamin Tissoires 
wacom_pl_irq(struct wacom_wac * wacom)170471d1714SBenjamin Tissoires static int wacom_pl_irq(struct wacom_wac *wacom)
171471d1714SBenjamin Tissoires {
172471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
173471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
1742a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
175471d1714SBenjamin Tissoires 	int prox, pressure;
176471d1714SBenjamin Tissoires 
177471d1714SBenjamin Tissoires 	if (data[0] != WACOM_REPORT_PENABLED) {
178471d1714SBenjamin Tissoires 		dev_dbg(input->dev.parent,
179471d1714SBenjamin Tissoires 			"%s: received unknown report #%d\n", __func__, data[0]);
180471d1714SBenjamin Tissoires 		return 0;
181471d1714SBenjamin Tissoires 	}
182471d1714SBenjamin Tissoires 
183471d1714SBenjamin Tissoires 	prox = data[1] & 0x40;
184471d1714SBenjamin Tissoires 
185025bcc15SJason Gerecke 	if (!wacom->id[0]) {
186025bcc15SJason Gerecke 		if ((data[0] & 0x10) || (data[4] & 0x20)) {
187025bcc15SJason Gerecke 			wacom->tool[0] = BTN_TOOL_RUBBER;
188471d1714SBenjamin Tissoires 			wacom->id[0] = ERASER_DEVICE_ID;
189025bcc15SJason Gerecke 		}
190025bcc15SJason Gerecke 		else {
191025bcc15SJason Gerecke 			wacom->tool[0] = BTN_TOOL_PEN;
192025bcc15SJason Gerecke 			wacom->id[0] = STYLUS_DEVICE_ID;
193025bcc15SJason Gerecke 		}
194025bcc15SJason Gerecke 	}
195025bcc15SJason Gerecke 
196025bcc15SJason Gerecke 	/* If the eraser is in prox, STYLUS2 is always set. If we
197025bcc15SJason Gerecke 	 * mis-detected the type and notice that STYLUS2 isn't set
198025bcc15SJason Gerecke 	 * then force the eraser out of prox and let the pen in.
199025bcc15SJason Gerecke 	 */
200025bcc15SJason Gerecke 	if (wacom->tool[0] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
201025bcc15SJason Gerecke 		input_report_key(input, BTN_TOOL_RUBBER, 0);
202025bcc15SJason Gerecke 		input_report_abs(input, ABS_MISC, 0);
203025bcc15SJason Gerecke 		input_sync(input);
204025bcc15SJason Gerecke 		wacom->tool[0] = BTN_TOOL_PEN;
205025bcc15SJason Gerecke 		wacom->id[0] = STYLUS_DEVICE_ID;
206025bcc15SJason Gerecke 	}
207025bcc15SJason Gerecke 
208282e4637SJason Gerecke 	if (prox) {
209471d1714SBenjamin Tissoires 		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
210471d1714SBenjamin Tissoires 		if (features->pressure_max > 255)
211471d1714SBenjamin Tissoires 			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
212471d1714SBenjamin Tissoires 		pressure += (features->pressure_max + 1) / 2;
213471d1714SBenjamin Tissoires 
214471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
215471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
216471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_PRESSURE, pressure);
217471d1714SBenjamin Tissoires 
218471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, data[4] & 0x08);
219471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS, data[4] & 0x10);
220471d1714SBenjamin Tissoires 		/* Only allow the stylus2 button to be reported for the pen tool. */
221025bcc15SJason Gerecke 		input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
222282e4637SJason Gerecke 	}
223471d1714SBenjamin Tissoires 
224025bcc15SJason Gerecke 	if (!prox)
225025bcc15SJason Gerecke 		wacom->id[0] = 0;
226025bcc15SJason Gerecke 	input_report_key(input, wacom->tool[0], prox);
227025bcc15SJason Gerecke 	input_report_abs(input, ABS_MISC, wacom->id[0]);
228471d1714SBenjamin Tissoires 	return 1;
229471d1714SBenjamin Tissoires }
230471d1714SBenjamin Tissoires 
wacom_ptu_irq(struct wacom_wac * wacom)231471d1714SBenjamin Tissoires static int wacom_ptu_irq(struct wacom_wac *wacom)
232471d1714SBenjamin Tissoires {
233471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
2342a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
235471d1714SBenjamin Tissoires 
236471d1714SBenjamin Tissoires 	if (data[0] != WACOM_REPORT_PENABLED) {
237471d1714SBenjamin Tissoires 		dev_dbg(input->dev.parent,
238471d1714SBenjamin Tissoires 			"%s: received unknown report #%d\n", __func__, data[0]);
239471d1714SBenjamin Tissoires 		return 0;
240471d1714SBenjamin Tissoires 	}
241471d1714SBenjamin Tissoires 
242471d1714SBenjamin Tissoires 	if (data[1] & 0x04) {
243471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOOL_RUBBER, data[1] & 0x20);
244471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, data[1] & 0x08);
245471d1714SBenjamin Tissoires 		wacom->id[0] = ERASER_DEVICE_ID;
246471d1714SBenjamin Tissoires 	} else {
247471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOOL_PEN, data[1] & 0x20);
248471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, data[1] & 0x01);
249471d1714SBenjamin Tissoires 		wacom->id[0] = STYLUS_DEVICE_ID;
250471d1714SBenjamin Tissoires 	}
251471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
252471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
253471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
254471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6]));
255471d1714SBenjamin Tissoires 	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
256471d1714SBenjamin Tissoires 	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
257471d1714SBenjamin Tissoires 	return 1;
258471d1714SBenjamin Tissoires }
259471d1714SBenjamin Tissoires 
wacom_dtu_irq(struct wacom_wac * wacom)260471d1714SBenjamin Tissoires static int wacom_dtu_irq(struct wacom_wac *wacom)
261471d1714SBenjamin Tissoires {
262471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
2632a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
264471d1714SBenjamin Tissoires 	int prox = data[1] & 0x20;
265471d1714SBenjamin Tissoires 
266471d1714SBenjamin Tissoires 	dev_dbg(input->dev.parent,
267471d1714SBenjamin Tissoires 		"%s: received report #%d", __func__, data[0]);
268471d1714SBenjamin Tissoires 
269471d1714SBenjamin Tissoires 	if (prox) {
270471d1714SBenjamin Tissoires 		/* Going into proximity select tool */
271471d1714SBenjamin Tissoires 		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
272471d1714SBenjamin Tissoires 		if (wacom->tool[0] == BTN_TOOL_PEN)
273471d1714SBenjamin Tissoires 			wacom->id[0] = STYLUS_DEVICE_ID;
274471d1714SBenjamin Tissoires 		else
275471d1714SBenjamin Tissoires 			wacom->id[0] = ERASER_DEVICE_ID;
276471d1714SBenjamin Tissoires 	}
277471d1714SBenjamin Tissoires 	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
278471d1714SBenjamin Tissoires 	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
279471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
280471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
281471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x01) << 8) | data[6]);
282471d1714SBenjamin Tissoires 	input_report_key(input, BTN_TOUCH, data[1] & 0x05);
283471d1714SBenjamin Tissoires 	if (!prox) /* out-prox */
284471d1714SBenjamin Tissoires 		wacom->id[0] = 0;
285471d1714SBenjamin Tissoires 	input_report_key(input, wacom->tool[0], prox);
286471d1714SBenjamin Tissoires 	input_report_abs(input, ABS_MISC, wacom->id[0]);
287471d1714SBenjamin Tissoires 	return 1;
288471d1714SBenjamin Tissoires }
289471d1714SBenjamin Tissoires 
wacom_dtus_irq(struct wacom_wac * wacom)290471d1714SBenjamin Tissoires static int wacom_dtus_irq(struct wacom_wac *wacom)
291471d1714SBenjamin Tissoires {
292073b50bcSJason Gerecke 	unsigned char *data = wacom->data;
2932a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
294471d1714SBenjamin Tissoires 	unsigned short prox, pressure = 0;
295471d1714SBenjamin Tissoires 
296471d1714SBenjamin Tissoires 	if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) {
297471d1714SBenjamin Tissoires 		dev_dbg(input->dev.parent,
298471d1714SBenjamin Tissoires 			"%s: received unknown report #%d", __func__, data[0]);
299471d1714SBenjamin Tissoires 		return 0;
300471d1714SBenjamin Tissoires 	} else if (data[0] == WACOM_REPORT_DTUSPAD) {
301471d1714SBenjamin Tissoires 		input = wacom->pad_input;
302471d1714SBenjamin Tissoires 		input_report_key(input, BTN_0, (data[1] & 0x01));
303471d1714SBenjamin Tissoires 		input_report_key(input, BTN_1, (data[1] & 0x02));
304471d1714SBenjamin Tissoires 		input_report_key(input, BTN_2, (data[1] & 0x04));
305471d1714SBenjamin Tissoires 		input_report_key(input, BTN_3, (data[1] & 0x08));
306471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MISC,
307471d1714SBenjamin Tissoires 				 data[1] & 0x0f ? PAD_DEVICE_ID : 0);
308471d1714SBenjamin Tissoires 		return 1;
309471d1714SBenjamin Tissoires 	} else {
310471d1714SBenjamin Tissoires 		prox = data[1] & 0x80;
311471d1714SBenjamin Tissoires 		if (prox) {
312471d1714SBenjamin Tissoires 			switch ((data[1] >> 3) & 3) {
313471d1714SBenjamin Tissoires 			case 1: /* Rubber */
314471d1714SBenjamin Tissoires 				wacom->tool[0] = BTN_TOOL_RUBBER;
315471d1714SBenjamin Tissoires 				wacom->id[0] = ERASER_DEVICE_ID;
316471d1714SBenjamin Tissoires 				break;
317471d1714SBenjamin Tissoires 
318471d1714SBenjamin Tissoires 			case 2: /* Pen */
319471d1714SBenjamin Tissoires 				wacom->tool[0] = BTN_TOOL_PEN;
320471d1714SBenjamin Tissoires 				wacom->id[0] = STYLUS_DEVICE_ID;
321471d1714SBenjamin Tissoires 				break;
322471d1714SBenjamin Tissoires 			}
323471d1714SBenjamin Tissoires 		}
324471d1714SBenjamin Tissoires 
325471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS, data[1] & 0x20);
326471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS2, data[1] & 0x40);
327471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_X, get_unaligned_be16(&data[3]));
328471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5]));
329471d1714SBenjamin Tissoires 		pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff);
330471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_PRESSURE, pressure);
331471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, pressure > 10);
332471d1714SBenjamin Tissoires 
333471d1714SBenjamin Tissoires 		if (!prox) /* out-prox */
334471d1714SBenjamin Tissoires 			wacom->id[0] = 0;
335471d1714SBenjamin Tissoires 		input_report_key(input, wacom->tool[0], prox);
336471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MISC, wacom->id[0]);
337471d1714SBenjamin Tissoires 		return 1;
338471d1714SBenjamin Tissoires 	}
339471d1714SBenjamin Tissoires }
340471d1714SBenjamin Tissoires 
wacom_graphire_irq(struct wacom_wac * wacom)341471d1714SBenjamin Tissoires static int wacom_graphire_irq(struct wacom_wac *wacom)
342471d1714SBenjamin Tissoires {
343471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
344471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
3452a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
346471d1714SBenjamin Tissoires 	struct input_dev *pad_input = wacom->pad_input;
347387142bbSBenjamin Tissoires 	int battery_capacity, ps_connected;
348471d1714SBenjamin Tissoires 	int prox;
349471d1714SBenjamin Tissoires 	int rw = 0;
350471d1714SBenjamin Tissoires 	int retval = 0;
351471d1714SBenjamin Tissoires 
352387142bbSBenjamin Tissoires 	if (features->type == GRAPHIRE_BT) {
353387142bbSBenjamin Tissoires 		if (data[0] != WACOM_REPORT_PENABLED_BT) {
354387142bbSBenjamin Tissoires 			dev_dbg(input->dev.parent,
355387142bbSBenjamin Tissoires 				"%s: received unknown report #%d\n", __func__,
356387142bbSBenjamin Tissoires 				data[0]);
357387142bbSBenjamin Tissoires 			goto exit;
358387142bbSBenjamin Tissoires 		}
359387142bbSBenjamin Tissoires 	} else if (data[0] != WACOM_REPORT_PENABLED) {
360471d1714SBenjamin Tissoires 		dev_dbg(input->dev.parent,
361471d1714SBenjamin Tissoires 			"%s: received unknown report #%d\n", __func__, data[0]);
362471d1714SBenjamin Tissoires 		goto exit;
363471d1714SBenjamin Tissoires 	}
364471d1714SBenjamin Tissoires 
365471d1714SBenjamin Tissoires 	prox = data[1] & 0x80;
366471d1714SBenjamin Tissoires 	if (prox || wacom->id[0]) {
367471d1714SBenjamin Tissoires 		if (prox) {
368471d1714SBenjamin Tissoires 			switch ((data[1] >> 5) & 3) {
369471d1714SBenjamin Tissoires 
370471d1714SBenjamin Tissoires 			case 0:	/* Pen */
371471d1714SBenjamin Tissoires 				wacom->tool[0] = BTN_TOOL_PEN;
372471d1714SBenjamin Tissoires 				wacom->id[0] = STYLUS_DEVICE_ID;
373471d1714SBenjamin Tissoires 				break;
374471d1714SBenjamin Tissoires 
375471d1714SBenjamin Tissoires 			case 1: /* Rubber */
376471d1714SBenjamin Tissoires 				wacom->tool[0] = BTN_TOOL_RUBBER;
377471d1714SBenjamin Tissoires 				wacom->id[0] = ERASER_DEVICE_ID;
378471d1714SBenjamin Tissoires 				break;
379471d1714SBenjamin Tissoires 
380471d1714SBenjamin Tissoires 			case 2: /* Mouse with wheel */
381471d1714SBenjamin Tissoires 				input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
382df561f66SGustavo A. R. Silva 				fallthrough;
383471d1714SBenjamin Tissoires 
384471d1714SBenjamin Tissoires 			case 3: /* Mouse without wheel */
385471d1714SBenjamin Tissoires 				wacom->tool[0] = BTN_TOOL_MOUSE;
386471d1714SBenjamin Tissoires 				wacom->id[0] = CURSOR_DEVICE_ID;
387471d1714SBenjamin Tissoires 				break;
388471d1714SBenjamin Tissoires 			}
389471d1714SBenjamin Tissoires 		}
390471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
391471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
392471d1714SBenjamin Tissoires 		if (wacom->tool[0] != BTN_TOOL_MOUSE) {
393387142bbSBenjamin Tissoires 			if (features->type == GRAPHIRE_BT)
394387142bbSBenjamin Tissoires 				input_report_abs(input, ABS_PRESSURE, data[6] |
395387142bbSBenjamin Tissoires 					(((__u16) (data[1] & 0x08)) << 5));
396387142bbSBenjamin Tissoires 			else
397387142bbSBenjamin Tissoires 				input_report_abs(input, ABS_PRESSURE, data[6] |
398387142bbSBenjamin Tissoires 					((data[7] & 0x03) << 8));
399471d1714SBenjamin Tissoires 			input_report_key(input, BTN_TOUCH, data[1] & 0x01);
400471d1714SBenjamin Tissoires 			input_report_key(input, BTN_STYLUS, data[1] & 0x02);
401471d1714SBenjamin Tissoires 			input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
402471d1714SBenjamin Tissoires 		} else {
403471d1714SBenjamin Tissoires 			input_report_key(input, BTN_LEFT, data[1] & 0x01);
404471d1714SBenjamin Tissoires 			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
405471d1714SBenjamin Tissoires 			if (features->type == WACOM_G4 ||
406471d1714SBenjamin Tissoires 					features->type == WACOM_MO) {
407471d1714SBenjamin Tissoires 				input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f);
408471d1714SBenjamin Tissoires 				rw = (data[7] & 0x04) - (data[7] & 0x03);
409387142bbSBenjamin Tissoires 			} else if (features->type == GRAPHIRE_BT) {
410387142bbSBenjamin Tissoires 				/* Compute distance between mouse and tablet */
411387142bbSBenjamin Tissoires 				rw = 44 - (data[6] >> 2);
412387142bbSBenjamin Tissoires 				rw = clamp_val(rw, 0, 31);
413387142bbSBenjamin Tissoires 				input_report_abs(input, ABS_DISTANCE, rw);
414387142bbSBenjamin Tissoires 				if (((data[1] >> 5) & 3) == 2) {
415387142bbSBenjamin Tissoires 					/* Mouse with wheel */
416387142bbSBenjamin Tissoires 					input_report_key(input, BTN_MIDDLE,
417387142bbSBenjamin Tissoires 							data[1] & 0x04);
418387142bbSBenjamin Tissoires 					rw = (data[6] & 0x01) ? -1 :
419387142bbSBenjamin Tissoires 						(data[6] & 0x02) ? 1 : 0;
420387142bbSBenjamin Tissoires 				} else {
421387142bbSBenjamin Tissoires 					rw = 0;
422387142bbSBenjamin Tissoires 				}
423471d1714SBenjamin Tissoires 			} else {
424471d1714SBenjamin Tissoires 				input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f);
425471d1714SBenjamin Tissoires 				rw = -(signed char)data[6];
426471d1714SBenjamin Tissoires 			}
427471d1714SBenjamin Tissoires 			input_report_rel(input, REL_WHEEL, rw);
428471d1714SBenjamin Tissoires 		}
429471d1714SBenjamin Tissoires 
430471d1714SBenjamin Tissoires 		if (!prox)
431471d1714SBenjamin Tissoires 			wacom->id[0] = 0;
432471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
433471d1714SBenjamin Tissoires 		input_report_key(input, wacom->tool[0], prox);
434471d1714SBenjamin Tissoires 		input_sync(input); /* sync last event */
435471d1714SBenjamin Tissoires 	}
436471d1714SBenjamin Tissoires 
437471d1714SBenjamin Tissoires 	/* send pad data */
438471d1714SBenjamin Tissoires 	switch (features->type) {
439471d1714SBenjamin Tissoires 	case WACOM_G4:
440471d1714SBenjamin Tissoires 		prox = data[7] & 0xf8;
441471d1714SBenjamin Tissoires 		if (prox || wacom->id[1]) {
442471d1714SBenjamin Tissoires 			wacom->id[1] = PAD_DEVICE_ID;
443471d1714SBenjamin Tissoires 			input_report_key(pad_input, BTN_BACK, (data[7] & 0x40));
444471d1714SBenjamin Tissoires 			input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x80));
445471d1714SBenjamin Tissoires 			rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
446471d1714SBenjamin Tissoires 			input_report_rel(pad_input, REL_WHEEL, rw);
447471d1714SBenjamin Tissoires 			if (!prox)
448471d1714SBenjamin Tissoires 				wacom->id[1] = 0;
449471d1714SBenjamin Tissoires 			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
450471d1714SBenjamin Tissoires 			retval = 1;
451471d1714SBenjamin Tissoires 		}
452471d1714SBenjamin Tissoires 		break;
453471d1714SBenjamin Tissoires 
454471d1714SBenjamin Tissoires 	case WACOM_MO:
455471d1714SBenjamin Tissoires 		prox = (data[7] & 0xf8) || data[8];
456471d1714SBenjamin Tissoires 		if (prox || wacom->id[1]) {
457471d1714SBenjamin Tissoires 			wacom->id[1] = PAD_DEVICE_ID;
458471d1714SBenjamin Tissoires 			input_report_key(pad_input, BTN_BACK, (data[7] & 0x08));
459471d1714SBenjamin Tissoires 			input_report_key(pad_input, BTN_LEFT, (data[7] & 0x20));
460471d1714SBenjamin Tissoires 			input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x10));
461471d1714SBenjamin Tissoires 			input_report_key(pad_input, BTN_RIGHT, (data[7] & 0x40));
462471d1714SBenjamin Tissoires 			input_report_abs(pad_input, ABS_WHEEL, (data[8] & 0x7f));
463471d1714SBenjamin Tissoires 			if (!prox)
464471d1714SBenjamin Tissoires 				wacom->id[1] = 0;
465471d1714SBenjamin Tissoires 			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
466471d1714SBenjamin Tissoires 			retval = 1;
467471d1714SBenjamin Tissoires 		}
468471d1714SBenjamin Tissoires 		break;
469387142bbSBenjamin Tissoires 	case GRAPHIRE_BT:
470387142bbSBenjamin Tissoires 		prox = data[7] & 0x03;
471387142bbSBenjamin Tissoires 		if (prox || wacom->id[1]) {
472387142bbSBenjamin Tissoires 			wacom->id[1] = PAD_DEVICE_ID;
473387142bbSBenjamin Tissoires 			input_report_key(pad_input, BTN_0, (data[7] & 0x02));
474387142bbSBenjamin Tissoires 			input_report_key(pad_input, BTN_1, (data[7] & 0x01));
475387142bbSBenjamin Tissoires 			if (!prox)
476387142bbSBenjamin Tissoires 				wacom->id[1] = 0;
477387142bbSBenjamin Tissoires 			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
478387142bbSBenjamin Tissoires 			retval = 1;
479387142bbSBenjamin Tissoires 		}
480387142bbSBenjamin Tissoires 		break;
481387142bbSBenjamin Tissoires 	}
482387142bbSBenjamin Tissoires 
483387142bbSBenjamin Tissoires 	/* Store current battery capacity and power supply state */
484387142bbSBenjamin Tissoires 	if (features->type == GRAPHIRE_BT) {
485387142bbSBenjamin Tissoires 		rw = (data[7] >> 2 & 0x07);
486387142bbSBenjamin Tissoires 		battery_capacity = batcap_gr[rw];
487387142bbSBenjamin Tissoires 		ps_connected = rw == 7;
48816e45989SJason Gerecke 		wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
48916e45989SJason Gerecke 				     battery_capacity, ps_connected, 1,
49016e45989SJason Gerecke 				     ps_connected);
491471d1714SBenjamin Tissoires 	}
492471d1714SBenjamin Tissoires exit:
493471d1714SBenjamin Tissoires 	return retval;
494471d1714SBenjamin Tissoires }
495471d1714SBenjamin Tissoires 
wacom_intuos_schedule_prox_event(struct wacom_wac * wacom_wac)4965fcad167SBenjamin Tissoires static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
4975fcad167SBenjamin Tissoires {
4985fcad167SBenjamin Tissoires 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
4990bbfe28aSJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
5005fcad167SBenjamin Tissoires 	struct hid_report *r;
5015fcad167SBenjamin Tissoires 	struct hid_report_enum *re;
5025fcad167SBenjamin Tissoires 
5035fcad167SBenjamin Tissoires 	re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]);
5040bbfe28aSJason Gerecke 	if (features->type == INTUOSHT2)
5050bbfe28aSJason Gerecke 		r = re->report_id_hash[WACOM_REPORT_INTUOSHT2_ID];
5060bbfe28aSJason Gerecke 	else
50706109993SJason Gerecke 		r = re->report_id_hash[WACOM_REPORT_INTUOS_ID1];
5085fcad167SBenjamin Tissoires 	if (r) {
5095fcad167SBenjamin Tissoires 		hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
5105fcad167SBenjamin Tissoires 	}
5115fcad167SBenjamin Tissoires }
5125fcad167SBenjamin Tissoires 
wacom_intuos_pad(struct wacom_wac * wacom)513fb013a01SJason Gerecke static int wacom_intuos_pad(struct wacom_wac *wacom)
514fb013a01SJason Gerecke {
515fb013a01SJason Gerecke 	struct wacom_features *features = &wacom->features;
516fb013a01SJason Gerecke 	unsigned char *data = wacom->data;
517fb013a01SJason Gerecke 	struct input_dev *input = wacom->pad_input;
518c7f0522aSJason Gerecke 	int i;
519c7f0522aSJason Gerecke 	int buttons = 0, nbuttons = features->numbered_buttons;
520c7f0522aSJason Gerecke 	int keys = 0, nkeys = 0;
521c7f0522aSJason Gerecke 	int ring1 = 0, ring2 = 0;
522c7f0522aSJason Gerecke 	int strip1 = 0, strip2 = 0;
523c7f0522aSJason Gerecke 	bool prox = false;
524670e9092SAaron Armstrong Skomra 	bool wrench = false, keyboard = false, mute_touch = false, menu = false,
525670e9092SAaron Armstrong Skomra 	     info = false;
526fb013a01SJason Gerecke 
527fb013a01SJason Gerecke 	/* pad packets. Works as a second tool and is always in prox */
528fb013a01SJason Gerecke 	if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
529fb013a01SJason Gerecke 	      data[0] == WACOM_REPORT_CINTIQPAD))
530fb013a01SJason Gerecke 		return 0;
531fb013a01SJason Gerecke 
532fb013a01SJason Gerecke 	if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
533c7f0522aSJason Gerecke 		buttons = (data[3] << 1) | (data[2] & 0x01);
534c7f0522aSJason Gerecke 		ring1 = data[1];
535fb013a01SJason Gerecke 	} else if (features->type == DTK) {
536c7f0522aSJason Gerecke 		buttons = data[6];
537fb013a01SJason Gerecke 	} else if (features->type == WACOM_13HD) {
538c7f0522aSJason Gerecke 		buttons = (data[4] << 1) | (data[3] & 0x01);
539fb013a01SJason Gerecke 	} else if (features->type == WACOM_24HD) {
540c7f0522aSJason Gerecke 		buttons = (data[8] << 8) | data[6];
541c7f0522aSJason Gerecke 		ring1 = data[1];
542c7f0522aSJason Gerecke 		ring2 = data[2];
543fb013a01SJason Gerecke 
544fb013a01SJason Gerecke 		/*
545fb013a01SJason Gerecke 		 * Three "buttons" are available on the 24HD which are
546fb013a01SJason Gerecke 		 * physically implemented as a touchstrip. Each button
547fb013a01SJason Gerecke 		 * is approximately 3 bits wide with a 2 bit spacing.
548fb013a01SJason Gerecke 		 * The raw touchstrip bits are stored at:
549fb013a01SJason Gerecke 		 *    ((data[3] & 0x1f) << 8) | data[4])
550fb013a01SJason Gerecke 		 */
551c7f0522aSJason Gerecke 		nkeys = 3;
552c7f0522aSJason Gerecke 		keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
553c7f0522aSJason Gerecke 		       ((data[4] & 0xE0) ? 1<<1 : 0) |
554c7f0522aSJason Gerecke 		       ((data[4] & 0x07) ? 1<<0 : 0);
555670e9092SAaron Armstrong Skomra 		keyboard = !!(data[4] & 0xE0);
556670e9092SAaron Armstrong Skomra 		info = !!(data[3] & 0x1C);
557670e9092SAaron Armstrong Skomra 
558670e9092SAaron Armstrong Skomra 		if (features->oPid) {
559670e9092SAaron Armstrong Skomra 			mute_touch = !!(data[4] & 0x07);
560670e9092SAaron Armstrong Skomra 			if (mute_touch)
561670e9092SAaron Armstrong Skomra 				wacom->shared->is_touch_on =
562670e9092SAaron Armstrong Skomra 					!wacom->shared->is_touch_on;
563670e9092SAaron Armstrong Skomra 		} else {
564670e9092SAaron Armstrong Skomra 			wrench = !!(data[4] & 0x07);
565670e9092SAaron Armstrong Skomra 		}
566fb013a01SJason Gerecke 	} else if (features->type == WACOM_27QHD) {
567c7f0522aSJason Gerecke 		nkeys = 3;
568c7f0522aSJason Gerecke 		keys = data[2] & 0x07;
569fb013a01SJason Gerecke 
570670e9092SAaron Armstrong Skomra 		wrench = !!(data[2] & 0x01);
571670e9092SAaron Armstrong Skomra 		keyboard = !!(data[2] & 0x02);
572670e9092SAaron Armstrong Skomra 
573670e9092SAaron Armstrong Skomra 		if (features->oPid) {
574670e9092SAaron Armstrong Skomra 			mute_touch = !!(data[2] & 0x04);
575670e9092SAaron Armstrong Skomra 			if (mute_touch)
576670e9092SAaron Armstrong Skomra 				wacom->shared->is_touch_on =
577670e9092SAaron Armstrong Skomra 					!wacom->shared->is_touch_on;
578670e9092SAaron Armstrong Skomra 		} else {
579670e9092SAaron Armstrong Skomra 			menu = !!(data[2] & 0x04);
580670e9092SAaron Armstrong Skomra 		}
581fb013a01SJason Gerecke 		input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
582fb013a01SJason Gerecke 		input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
583fb013a01SJason Gerecke 		input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
584fb013a01SJason Gerecke 	} else if (features->type == CINTIQ_HYBRID) {
585fb013a01SJason Gerecke 		/*
586fb013a01SJason Gerecke 		 * Do not send hardware buttons under Android. They
587fb013a01SJason Gerecke 		 * are already sent to the system through GPIO (and
588fb013a01SJason Gerecke 		 * have different meaning).
589c7f0522aSJason Gerecke 		 *
590c7f0522aSJason Gerecke 		 * d-pad right  -> data[4] & 0x10
591c7f0522aSJason Gerecke 		 * d-pad up     -> data[4] & 0x20
592c7f0522aSJason Gerecke 		 * d-pad left   -> data[4] & 0x40
593c7f0522aSJason Gerecke 		 * d-pad down   -> data[4] & 0x80
594c7f0522aSJason Gerecke 		 * d-pad center -> data[3] & 0x01
595fb013a01SJason Gerecke 		 */
596c7f0522aSJason Gerecke 		buttons = (data[4] << 1) | (data[3] & 0x01);
597fb013a01SJason Gerecke 	} else if (features->type == CINTIQ_COMPANION_2) {
598693c3dabSAaron Armstrong Skomra 		/* d-pad right  -> data[2] & 0x10
599693c3dabSAaron Armstrong Skomra 		 * d-pad up     -> data[2] & 0x20
600693c3dabSAaron Armstrong Skomra 		 * d-pad left   -> data[2] & 0x40
601693c3dabSAaron Armstrong Skomra 		 * d-pad down   -> data[2] & 0x80
602693c3dabSAaron Armstrong Skomra 		 * d-pad center -> data[1] & 0x01
603c7f0522aSJason Gerecke 		 */
6040402b6b7SJason Gerecke 		buttons = ((data[2] >> 4) << 7) |
605693c3dabSAaron Armstrong Skomra 		          ((data[1] & 0x04) << 4) |
606c7f0522aSJason Gerecke 		          ((data[2] & 0x0F) << 2) |
607c7f0522aSJason Gerecke 		          (data[1] & 0x03);
608fb013a01SJason Gerecke 	} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
609fb013a01SJason Gerecke 		/*
610fb013a01SJason Gerecke 		 * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
611fb013a01SJason Gerecke 		 * addition to the mechanical switch. Switch data is
612fb013a01SJason Gerecke 		 * stored in data[4], capacitive data in data[5].
613c7f0522aSJason Gerecke 		 *
614c7f0522aSJason Gerecke 		 * Touch ring mode switch (data[3]) has no capacitive sensor
615fb013a01SJason Gerecke 		 */
616c7f0522aSJason Gerecke 		buttons = (data[4] << 1) | (data[3] & 0x01);
617c7f0522aSJason Gerecke 		ring1 = data[2];
618fb013a01SJason Gerecke 	} else {
619fb013a01SJason Gerecke 		if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
620c7f0522aSJason Gerecke 			buttons = (data[8] << 10) | ((data[7] & 0x01) << 9) |
621c7f0522aSJason Gerecke 			          (data[6] << 1) | (data[5] & 0x01);
622fb013a01SJason Gerecke 
623fb013a01SJason Gerecke 			if (features->type == WACOM_22HD) {
624c7f0522aSJason Gerecke 				nkeys = 3;
625c7f0522aSJason Gerecke 				keys = data[9] & 0x07;
626670e9092SAaron Armstrong Skomra 
627670e9092SAaron Armstrong Skomra 				info = !!(data[9] & 0x01);
628670e9092SAaron Armstrong Skomra 				wrench = !!(data[9] & 0x02);
629fb013a01SJason Gerecke 			}
630fb013a01SJason Gerecke 		} else {
631ce06760bSPing Cheng 			buttons = ((data[6] & 0x10) << 5)  |
632ce06760bSPing Cheng 			          ((data[5] & 0x10) << 4)  |
633c7f0522aSJason Gerecke 			          ((data[6] & 0x0F) << 4)  |
634c7f0522aSJason Gerecke 			          (data[5] & 0x0F);
635fb013a01SJason Gerecke 		}
636f73d08d0SJason Gerecke 		strip1 = ((data[1] & 0x1f) << 8) | data[2];
637f73d08d0SJason Gerecke 		strip2 = ((data[3] & 0x1f) << 8) | data[4];
638c7f0522aSJason Gerecke 	}
639fb013a01SJason Gerecke 
640073b50bcSJason Gerecke 	prox = (buttons & ~(~0U << nbuttons)) | (keys & ~(~0U << nkeys)) |
6418f9cfdd3SDan Carpenter 	       (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
642c7f0522aSJason Gerecke 
643c7f0522aSJason Gerecke 	wacom_report_numbered_buttons(input, nbuttons, buttons);
644c7f0522aSJason Gerecke 
645c7f0522aSJason Gerecke 	for (i = 0; i < nkeys; i++)
646c7f0522aSJason Gerecke 		input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
647c7f0522aSJason Gerecke 
648670e9092SAaron Armstrong Skomra 	input_report_key(input, KEY_BUTTONCONFIG, wrench);
649670e9092SAaron Armstrong Skomra 	input_report_key(input, KEY_ONSCREEN_KEYBOARD, keyboard);
650670e9092SAaron Armstrong Skomra 	input_report_key(input, KEY_CONTROLPANEL, menu);
651670e9092SAaron Armstrong Skomra 	input_report_key(input, KEY_INFO, info);
652670e9092SAaron Armstrong Skomra 
653670e9092SAaron Armstrong Skomra 	if (wacom->shared && wacom->shared->touch_input) {
654670e9092SAaron Armstrong Skomra 		input_report_switch(wacom->shared->touch_input,
655670e9092SAaron Armstrong Skomra 				    SW_MUTE_DEVICE,
656670e9092SAaron Armstrong Skomra 				    !wacom->shared->is_touch_on);
657670e9092SAaron Armstrong Skomra 		input_sync(wacom->shared->touch_input);
658670e9092SAaron Armstrong Skomra 	}
659670e9092SAaron Armstrong Skomra 
660c7f0522aSJason Gerecke 	input_report_abs(input, ABS_RX, strip1);
66103a0dc54SJason Gerecke 	input_report_abs(input, ABS_RY, strip2);
662c7f0522aSJason Gerecke 
663aaae03e4SJason Gerecke 	input_report_abs(input, ABS_WHEEL,    (ring1 & 0x80) ? (ring1 & 0x7f) : 0);
664aaae03e4SJason Gerecke 	input_report_abs(input, ABS_THROTTLE, (ring2 & 0x80) ? (ring2 & 0x7f) : 0);
665c7f0522aSJason Gerecke 
666c7f0522aSJason Gerecke 	input_report_key(input, wacom->tool[1], prox ? 1 : 0);
667c7f0522aSJason Gerecke 	input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
668c7f0522aSJason Gerecke 
669c7f0522aSJason Gerecke 	input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
670c7f0522aSJason Gerecke 
671fb013a01SJason Gerecke 	return 1;
672fb013a01SJason Gerecke }
673fb013a01SJason Gerecke 
wacom_intuos_id_mangle(int tool_id)67482527da3SJason Gerecke static int wacom_intuos_id_mangle(int tool_id)
67582527da3SJason Gerecke {
67682527da3SJason Gerecke 	return (tool_id & ~0xFFF) << 4 | (tool_id & 0xFFF);
67782527da3SJason Gerecke }
67882527da3SJason Gerecke 
wacom_is_art_pen(int tool_id)6797ccced33SPing Cheng static bool wacom_is_art_pen(int tool_id)
6807ccced33SPing Cheng {
6817ccced33SPing Cheng 	bool is_art_pen = false;
6827ccced33SPing Cheng 
6837ccced33SPing Cheng 	switch (tool_id) {
6847ccced33SPing Cheng 	case 0x885:	/* Intuos3 Marker Pen */
6857ccced33SPing Cheng 	case 0x804:	/* Intuos4/5 13HD/24HD Marker Pen */
6867ccced33SPing Cheng 	case 0x10804:	/* Intuos4/5 13HD/24HD Art Pen */
6877ccced33SPing Cheng 		is_art_pen = true;
6887ccced33SPing Cheng 		break;
6897ccced33SPing Cheng 	}
6907ccced33SPing Cheng 	return is_art_pen;
6917ccced33SPing Cheng }
6927ccced33SPing Cheng 
wacom_intuos_get_tool_type(int tool_id)6937e129783SBenjamin Tissoires static int wacom_intuos_get_tool_type(int tool_id)
6947e129783SBenjamin Tissoires {
6957ccced33SPing Cheng 	int tool_type = BTN_TOOL_PEN;
6967ccced33SPing Cheng 
6977ccced33SPing Cheng 	if (wacom_is_art_pen(tool_id))
6987ccced33SPing Cheng 		return tool_type;
6997e129783SBenjamin Tissoires 
7007e129783SBenjamin Tissoires 	switch (tool_id) {
7017e129783SBenjamin Tissoires 	case 0x812: /* Inking pen */
7027e129783SBenjamin Tissoires 	case 0x801: /* Intuos3 Inking pen */
70382527da3SJason Gerecke 	case 0x12802: /* Intuos4/5 Inking Pen */
7047e129783SBenjamin Tissoires 	case 0x012:
7057e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_PENCIL;
7067e129783SBenjamin Tissoires 		break;
7077e129783SBenjamin Tissoires 
7087e129783SBenjamin Tissoires 	case 0x822: /* Pen */
7097e129783SBenjamin Tissoires 	case 0x842:
7107e129783SBenjamin Tissoires 	case 0x852:
7117e129783SBenjamin Tissoires 	case 0x823: /* Intuos3 Grip Pen */
7127e129783SBenjamin Tissoires 	case 0x813: /* Intuos3 Classic Pen */
7137e129783SBenjamin Tissoires 	case 0x802: /* Intuos4/5 13HD/24HD General Pen */
7147e129783SBenjamin Tissoires 	case 0x8e2: /* IntuosHT2 pen */
7157e129783SBenjamin Tissoires 	case 0x022:
716bfdc750cSPing Cheng 	case 0x200: /* Pro Pen 3 */
7174e6e7d72SJason Gerecke 	case 0x10842: /* MobileStudio Pro Pro Pen slim */
71882527da3SJason Gerecke 	case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */
71982527da3SJason Gerecke 	case 0x16802: /* Cintiq 13HD Pro Pen */
72082527da3SJason Gerecke 	case 0x18802: /* DTH2242 Pen */
72182527da3SJason Gerecke 	case 0x10802: /* Intuos4/5 13HD/24HD General Pen */
72292566c0fSTatsunosuke Tobita 	case 0x8842: /* Intuos Pro and Cintiq Pro 3D Pen */
7237e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_PEN;
7247e129783SBenjamin Tissoires 		break;
7257e129783SBenjamin Tissoires 
7267e129783SBenjamin Tissoires 	case 0x832: /* Stroke pen */
7277e129783SBenjamin Tissoires 	case 0x032:
7287e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_BRUSH;
7297e129783SBenjamin Tissoires 		break;
7307e129783SBenjamin Tissoires 
7317e129783SBenjamin Tissoires 	case 0x007: /* Mouse 4D and 2D */
7327e129783SBenjamin Tissoires 	case 0x09c:
7337e129783SBenjamin Tissoires 	case 0x094:
7347e129783SBenjamin Tissoires 	case 0x017: /* Intuos3 2D Mouse */
7357e129783SBenjamin Tissoires 	case 0x806: /* Intuos4 Mouse */
7367e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_MOUSE;
7377e129783SBenjamin Tissoires 		break;
7387e129783SBenjamin Tissoires 
7397e129783SBenjamin Tissoires 	case 0x096: /* Lens cursor */
7407e129783SBenjamin Tissoires 	case 0x097: /* Intuos3 Lens cursor */
7417e129783SBenjamin Tissoires 	case 0x006: /* Intuos4 Lens cursor */
7427e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_LENS;
7437e129783SBenjamin Tissoires 		break;
7447e129783SBenjamin Tissoires 
7457e129783SBenjamin Tissoires 	case 0x82a: /* Eraser */
7469ce9a123SJason Gerecke 	case 0x84a:
7477e129783SBenjamin Tissoires 	case 0x85a:
7487e129783SBenjamin Tissoires 	case 0x91a:
7497e129783SBenjamin Tissoires 	case 0xd1a:
7507e129783SBenjamin Tissoires 	case 0x0fa:
7517e129783SBenjamin Tissoires 	case 0x82b: /* Intuos3 Grip Pen Eraser */
7527e129783SBenjamin Tissoires 	case 0x81b: /* Intuos3 Classic Pen Eraser */
7537e129783SBenjamin Tissoires 	case 0x91b: /* Intuos3 Airbrush Eraser */
7547e129783SBenjamin Tissoires 	case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
7557e129783SBenjamin Tissoires 	case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
7567e129783SBenjamin Tissoires 	case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
75782527da3SJason Gerecke 	case 0x1480a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
75882527da3SJason Gerecke 	case 0x1090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
75982527da3SJason Gerecke 	case 0x1080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
7604e6e7d72SJason Gerecke 	case 0x1084a: /* MobileStudio Pro Pro Pen slim Eraser */
76182527da3SJason Gerecke 	case 0x1680a: /* Cintiq 13HD Pro Pen Eraser */
76282527da3SJason Gerecke 	case 0x1880a: /* DTH2242 Eraser */
76382527da3SJason Gerecke 	case 0x1080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
7647e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_RUBBER;
7657e129783SBenjamin Tissoires 		break;
7667e129783SBenjamin Tissoires 
7677e129783SBenjamin Tissoires 	case 0xd12:
7687e129783SBenjamin Tissoires 	case 0x912:
7697e129783SBenjamin Tissoires 	case 0x112:
7707e129783SBenjamin Tissoires 	case 0x913: /* Intuos3 Airbrush */
7717e129783SBenjamin Tissoires 	case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
77282527da3SJason Gerecke 	case 0x10902: /* Intuos4/5 13HD/24HD Airbrush */
7737e129783SBenjamin Tissoires 		tool_type = BTN_TOOL_AIRBRUSH;
7747e129783SBenjamin Tissoires 		break;
7757e129783SBenjamin Tissoires 	}
7767e129783SBenjamin Tissoires 	return tool_type;
7777e129783SBenjamin Tissoires }
7787e129783SBenjamin Tissoires 
wacom_exit_report(struct wacom_wac * wacom)779619d3a29SAaron Armstrong Skomra static void wacom_exit_report(struct wacom_wac *wacom)
780619d3a29SAaron Armstrong Skomra {
781619d3a29SAaron Armstrong Skomra 	struct input_dev *input = wacom->pen_input;
782619d3a29SAaron Armstrong Skomra 	struct wacom_features *features = &wacom->features;
783619d3a29SAaron Armstrong Skomra 	unsigned char *data = wacom->data;
784619d3a29SAaron Armstrong Skomra 	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
785619d3a29SAaron Armstrong Skomra 
786619d3a29SAaron Armstrong Skomra 	/*
787619d3a29SAaron Armstrong Skomra 	 * Reset all states otherwise we lose the initial states
788619d3a29SAaron Armstrong Skomra 	 * when in-prox next time
789619d3a29SAaron Armstrong Skomra 	 */
790619d3a29SAaron Armstrong Skomra 	input_report_abs(input, ABS_X, 0);
791619d3a29SAaron Armstrong Skomra 	input_report_abs(input, ABS_Y, 0);
792619d3a29SAaron Armstrong Skomra 	input_report_abs(input, ABS_DISTANCE, 0);
793619d3a29SAaron Armstrong Skomra 	input_report_abs(input, ABS_TILT_X, 0);
794619d3a29SAaron Armstrong Skomra 	input_report_abs(input, ABS_TILT_Y, 0);
795619d3a29SAaron Armstrong Skomra 	if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
796619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_LEFT, 0);
797619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_MIDDLE, 0);
798619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_RIGHT, 0);
799619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_SIDE, 0);
800619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_EXTRA, 0);
801619d3a29SAaron Armstrong Skomra 		input_report_abs(input, ABS_THROTTLE, 0);
802619d3a29SAaron Armstrong Skomra 		input_report_abs(input, ABS_RZ, 0);
803619d3a29SAaron Armstrong Skomra 	} else {
804619d3a29SAaron Armstrong Skomra 		input_report_abs(input, ABS_PRESSURE, 0);
805619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_STYLUS, 0);
806619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_STYLUS2, 0);
807619d3a29SAaron Armstrong Skomra 		input_report_key(input, BTN_TOUCH, 0);
808619d3a29SAaron Armstrong Skomra 		input_report_abs(input, ABS_WHEEL, 0);
809619d3a29SAaron Armstrong Skomra 		if (features->type >= INTUOS3S)
810619d3a29SAaron Armstrong Skomra 			input_report_abs(input, ABS_Z, 0);
811619d3a29SAaron Armstrong Skomra 	}
812619d3a29SAaron Armstrong Skomra 	input_report_key(input, wacom->tool[idx], 0);
813619d3a29SAaron Armstrong Skomra 	input_report_abs(input, ABS_MISC, 0); /* reset tool id */
814619d3a29SAaron Armstrong Skomra 	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
815619d3a29SAaron Armstrong Skomra 	wacom->id[idx] = 0;
816619d3a29SAaron Armstrong Skomra }
817619d3a29SAaron Armstrong Skomra 
wacom_intuos_inout(struct wacom_wac * wacom)818471d1714SBenjamin Tissoires static int wacom_intuos_inout(struct wacom_wac *wacom)
819471d1714SBenjamin Tissoires {
820471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
821471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
8222a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
8234750f5feSPing Cheng 	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
824471d1714SBenjamin Tissoires 
8254750f5feSPing Cheng 	if (!(((data[1] & 0xfc) == 0xc0) ||  /* in prox */
8264750f5feSPing Cheng 	    ((data[1] & 0xfe) == 0x20) ||    /* in range */
8274750f5feSPing Cheng 	    ((data[1] & 0xfe) == 0x80)))     /* out prox */
8284750f5feSPing Cheng 		return 0;
829471d1714SBenjamin Tissoires 
830471d1714SBenjamin Tissoires 	/* Enter report */
831471d1714SBenjamin Tissoires 	if ((data[1] & 0xfc) == 0xc0) {
832471d1714SBenjamin Tissoires 		/* serial number of the tool */
833bd249b91SNikita Zhandarovich 		wacom->serial[idx] = ((__u64)(data[3] & 0x0f) << 28) +
834471d1714SBenjamin Tissoires 			(data[4] << 20) + (data[5] << 12) +
835471d1714SBenjamin Tissoires 			(data[6] << 4) + (data[7] >> 4);
836471d1714SBenjamin Tissoires 
837471d1714SBenjamin Tissoires 		wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) |
83882527da3SJason Gerecke 		     ((data[7] & 0x0f) << 16) | ((data[8] & 0xf0) << 8);
839471d1714SBenjamin Tissoires 
8407e129783SBenjamin Tissoires 		wacom->tool[idx] = wacom_intuos_get_tool_type(wacom->id[idx]);
841471d1714SBenjamin Tissoires 
842eff6ca97SPing Cheng 		wacom->shared->stylus_in_proximity = true;
843471d1714SBenjamin Tissoires 		return 1;
844471d1714SBenjamin Tissoires 	}
845471d1714SBenjamin Tissoires 
846c1b03f55SPing Cheng 	/* in Range */
847c1b03f55SPing Cheng 	if ((data[1] & 0xfe) == 0x20) {
848526d6e7bSPing Cheng 		if (features->type != INTUOSHT2)
849b3bd7ef3SPing Cheng 			wacom->shared->stylus_in_proximity = true;
850486b908dSPing Cheng 
851b3bd7ef3SPing Cheng 		/* in Range while exiting */
852c1b03f55SPing Cheng 		if (wacom->reporting_data) {
853471d1714SBenjamin Tissoires 			input_report_key(input, BTN_TOUCH, 0);
854471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_PRESSURE, 0);
855471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
856b3bd7ef3SPing Cheng 			return 2;
857471d1714SBenjamin Tissoires 		}
858c1b03f55SPing Cheng 		return 1;
859c1b03f55SPing Cheng 	}
860471d1714SBenjamin Tissoires 
861471d1714SBenjamin Tissoires 	/* Exit report */
862471d1714SBenjamin Tissoires 	if ((data[1] & 0xfe) == 0x80) {
863471d1714SBenjamin Tissoires 		wacom->shared->stylus_in_proximity = false;
864b3bd7ef3SPing Cheng 		wacom->reporting_data = false;
865471d1714SBenjamin Tissoires 
866373a5356SPing Cheng 		/* don't report exit if we don't know the ID */
867373a5356SPing Cheng 		if (!wacom->id[idx])
868373a5356SPing Cheng 			return 1;
869373a5356SPing Cheng 
870619d3a29SAaron Armstrong Skomra 		wacom_exit_report(wacom);
871471d1714SBenjamin Tissoires 		return 2;
872471d1714SBenjamin Tissoires 	}
873373a5356SPing Cheng 
874471d1714SBenjamin Tissoires 	return 0;
875471d1714SBenjamin Tissoires }
876471d1714SBenjamin Tissoires 
touch_is_muted(struct wacom_wac * wacom_wac)8779d339fe4SJason Gerecke static inline bool touch_is_muted(struct wacom_wac *wacom_wac)
8789d339fe4SJason Gerecke {
8799d339fe4SJason Gerecke 	return wacom_wac->probe_complete &&
8809d339fe4SJason Gerecke 	       wacom_wac->shared->has_mute_touch_switch &&
8819d339fe4SJason Gerecke 	       !wacom_wac->shared->is_touch_on;
8829d339fe4SJason Gerecke }
8839d339fe4SJason Gerecke 
report_touch_events(struct wacom_wac * wacom)8841924e05eSPing Cheng static inline bool report_touch_events(struct wacom_wac *wacom)
8851924e05eSPing Cheng {
8861924e05eSPing Cheng 	return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
8871924e05eSPing Cheng }
8881924e05eSPing Cheng 
delay_pen_events(struct wacom_wac * wacom)8891924e05eSPing Cheng static inline bool delay_pen_events(struct wacom_wac *wacom)
8901924e05eSPing Cheng {
8911924e05eSPing Cheng 	return (wacom->shared->touch_down && touch_arbitration);
89272b236d6SAaron Skomra }
89372b236d6SAaron Skomra 
wacom_intuos_general(struct wacom_wac * wacom)89416e0a6a0SJason Gerecke static int wacom_intuos_general(struct wacom_wac *wacom)
895471d1714SBenjamin Tissoires {
896471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
897471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
8982a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
89916e0a6a0SJason Gerecke 	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
900a8a09c85SJason Gerecke 	unsigned char type = (data[1] >> 1) & 0x0F;
9015f33f430SJason Gerecke 	unsigned int x, y, distance, t;
902471d1714SBenjamin Tissoires 
90316e0a6a0SJason Gerecke 	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_CINTIQ &&
90416e0a6a0SJason Gerecke 		data[0] != WACOM_REPORT_INTUOS_PEN)
90516e0a6a0SJason Gerecke 		return 0;
90616e0a6a0SJason Gerecke 
9071924e05eSPing Cheng 	if (delay_pen_events(wacom))
908c1b03f55SPing Cheng 		return 1;
909c1b03f55SPing Cheng 
910599b0820SPing Cheng 	/* don't report events if we don't know the tool ID */
911599b0820SPing Cheng 	if (!wacom->id[idx]) {
912599b0820SPing Cheng 		/* but reschedule a read of the current tool */
913599b0820SPing Cheng 		wacom_intuos_schedule_prox_event(wacom);
914599b0820SPing Cheng 		return 1;
915599b0820SPing Cheng 	}
916599b0820SPing Cheng 
9174750f5feSPing Cheng 	/*
9184750f5feSPing Cheng 	 * don't report events for invalid data
9194750f5feSPing Cheng 	 */
9204750f5feSPing Cheng 	/* older I4 styli don't work with new Cintiqs */
92182527da3SJason Gerecke 	if ((!((wacom->id[idx] >> 16) & 0x01) &&
9224750f5feSPing Cheng 			(features->type == WACOM_21UX2)) ||
9234750f5feSPing Cheng 	    /* Only large Intuos support Lense Cursor */
9244750f5feSPing Cheng 	    (wacom->tool[idx] == BTN_TOOL_LENS &&
9254750f5feSPing Cheng 		(features->type == INTUOS3 ||
9264750f5feSPing Cheng 		 features->type == INTUOS3S ||
9274750f5feSPing Cheng 		 features->type == INTUOS4 ||
9284750f5feSPing Cheng 		 features->type == INTUOS4S ||
9294750f5feSPing Cheng 		 features->type == INTUOS5 ||
9304750f5feSPing Cheng 		 features->type == INTUOS5S ||
9314750f5feSPing Cheng 		 features->type == INTUOSPM ||
9324750f5feSPing Cheng 		 features->type == INTUOSPS)) ||
9334750f5feSPing Cheng 	   /* Cintiq doesn't send data when RDY bit isn't set */
9344750f5feSPing Cheng 	   (features->type == CINTIQ && !(data[1] & 0x40)))
9354750f5feSPing Cheng 		return 1;
9364750f5feSPing Cheng 
9375f33f430SJason Gerecke 	x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
9385f33f430SJason Gerecke 	y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1);
9395f33f430SJason Gerecke 	distance = data[9] >> 2;
9405f33f430SJason Gerecke 	if (features->type < INTUOS3S) {
9415f33f430SJason Gerecke 		x >>= 1;
9425f33f430SJason Gerecke 		y >>= 1;
9435f33f430SJason Gerecke 		distance >>= 1;
944471d1714SBenjamin Tissoires 	}
945b72fb1dcSJason Gerecke 	if (features->type == INTUOSHT2)
946b72fb1dcSJason Gerecke 		distance = features->distance_max - distance;
9475f33f430SJason Gerecke 	input_report_abs(input, ABS_X, x);
9485f33f430SJason Gerecke 	input_report_abs(input, ABS_Y, y);
9495f33f430SJason Gerecke 	input_report_abs(input, ABS_DISTANCE, distance);
95016e0a6a0SJason Gerecke 
951a8a09c85SJason Gerecke 	switch (type) {
952a8a09c85SJason Gerecke 	case 0x00:
953a8a09c85SJason Gerecke 	case 0x01:
954a8a09c85SJason Gerecke 	case 0x02:
955a8a09c85SJason Gerecke 	case 0x03:
956471d1714SBenjamin Tissoires 		/* general pen packet */
9575f33f430SJason Gerecke 		t = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1);
9585f33f430SJason Gerecke 		if (features->pressure_max < 2047)
9595f33f430SJason Gerecke 			t >>= 1;
960471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_PRESSURE, t);
961eda01dabSPing Cheng 		if (features->type != INTUOSHT2) {
962471d1714SBenjamin Tissoires 		    input_report_abs(input, ABS_TILT_X,
963ec5fc1c1SJason Gerecke 				 (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
964ec5fc1c1SJason Gerecke 		    input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
965eda01dabSPing Cheng 		}
966471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS, data[1] & 2);
967471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS2, data[1] & 4);
968471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, t > 10);
969a8a09c85SJason Gerecke 		break;
970471d1714SBenjamin Tissoires 
971a8a09c85SJason Gerecke 	case 0x0a:
972471d1714SBenjamin Tissoires 		/* airbrush second packet */
973471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_WHEEL,
974471d1714SBenjamin Tissoires 				(data[6] << 2) | ((data[7] >> 6) & 3));
975471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_TILT_X,
976ec5fc1c1SJason Gerecke 				 (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
977ec5fc1c1SJason Gerecke 		input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
978a8a09c85SJason Gerecke 		break;
979471d1714SBenjamin Tissoires 
980a8a09c85SJason Gerecke 	case 0x05:
981471d1714SBenjamin Tissoires 		/* Rotation packet */
982471d1714SBenjamin Tissoires 		if (features->type >= INTUOS3S) {
983471d1714SBenjamin Tissoires 			/* I3 marker pen rotation */
984471d1714SBenjamin Tissoires 			t = (data[6] << 3) | ((data[7] >> 5) & 7);
985471d1714SBenjamin Tissoires 			t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
986471d1714SBenjamin Tissoires 				((t-1) / 2 + 450)) : (450 - t / 2) ;
987471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_Z, t);
988471d1714SBenjamin Tissoires 		} else {
989571f572fSJason Gerecke 			/* 4D mouse 2nd packet */
990471d1714SBenjamin Tissoires 			t = (data[6] << 3) | ((data[7] >> 5) & 7);
991471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
992471d1714SBenjamin Tissoires 				((t - 1) / 2) : -t / 2);
993471d1714SBenjamin Tissoires 		}
994a8a09c85SJason Gerecke 		break;
995471d1714SBenjamin Tissoires 
996a8a09c85SJason Gerecke 	case 0x04:
997571f572fSJason Gerecke 		/* 4D mouse 1st packet */
998471d1714SBenjamin Tissoires 		input_report_key(input, BTN_LEFT,   data[8] & 0x01);
999471d1714SBenjamin Tissoires 		input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
1000471d1714SBenjamin Tissoires 		input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
1001471d1714SBenjamin Tissoires 
1002471d1714SBenjamin Tissoires 		input_report_key(input, BTN_SIDE,   data[8] & 0x20);
1003471d1714SBenjamin Tissoires 		input_report_key(input, BTN_EXTRA,  data[8] & 0x10);
1004471d1714SBenjamin Tissoires 		t = (data[6] << 2) | ((data[7] >> 6) & 3);
1005471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
1006571f572fSJason Gerecke 		break;
1007471d1714SBenjamin Tissoires 
1008571f572fSJason Gerecke 	case 0x06:
1009471d1714SBenjamin Tissoires 		/* I4 mouse */
1010471d1714SBenjamin Tissoires 		input_report_key(input, BTN_LEFT,   data[6] & 0x01);
1011471d1714SBenjamin Tissoires 		input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
1012471d1714SBenjamin Tissoires 		input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
1013471d1714SBenjamin Tissoires 		input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
1014471d1714SBenjamin Tissoires 				 - ((data[7] & 0x40) >> 6));
1015471d1714SBenjamin Tissoires 		input_report_key(input, BTN_SIDE,   data[6] & 0x08);
1016471d1714SBenjamin Tissoires 		input_report_key(input, BTN_EXTRA,  data[6] & 0x10);
1017471d1714SBenjamin Tissoires 
1018471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_TILT_X,
1019ec5fc1c1SJason Gerecke 			(((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
1020ec5fc1c1SJason Gerecke 		input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
1021571f572fSJason Gerecke 		break;
1022571f572fSJason Gerecke 
1023571f572fSJason Gerecke 	case 0x08:
1024571f572fSJason Gerecke 		if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
1025471d1714SBenjamin Tissoires 			/* 2D mouse packet */
1026471d1714SBenjamin Tissoires 			input_report_key(input, BTN_LEFT,   data[8] & 0x04);
1027471d1714SBenjamin Tissoires 			input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
1028471d1714SBenjamin Tissoires 			input_report_key(input, BTN_RIGHT,  data[8] & 0x10);
1029471d1714SBenjamin Tissoires 			input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
1030471d1714SBenjamin Tissoires 					 - ((data[8] & 0x02) >> 1));
1031471d1714SBenjamin Tissoires 
1032471d1714SBenjamin Tissoires 			/* I3 2D mouse side buttons */
1033471d1714SBenjamin Tissoires 			if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
1034471d1714SBenjamin Tissoires 				input_report_key(input, BTN_SIDE,   data[8] & 0x40);
1035471d1714SBenjamin Tissoires 				input_report_key(input, BTN_EXTRA,  data[8] & 0x20);
1036471d1714SBenjamin Tissoires 			}
1037471d1714SBenjamin Tissoires 		}
1038571f572fSJason Gerecke 		else if (wacom->tool[idx] == BTN_TOOL_LENS) {
1039471d1714SBenjamin Tissoires 			/* Lens cursor packets */
1040471d1714SBenjamin Tissoires 			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
1041471d1714SBenjamin Tissoires 			input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
1042471d1714SBenjamin Tissoires 			input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
1043471d1714SBenjamin Tissoires 			input_report_key(input, BTN_SIDE,   data[8] & 0x10);
1044471d1714SBenjamin Tissoires 			input_report_key(input, BTN_EXTRA,  data[8] & 0x08);
1045471d1714SBenjamin Tissoires 		}
1046a8a09c85SJason Gerecke 		break;
1047a8a09c85SJason Gerecke 
1048571f572fSJason Gerecke 	case 0x07:
1049a8a09c85SJason Gerecke 	case 0x09:
1050571f572fSJason Gerecke 	case 0x0b:
1051a8a09c85SJason Gerecke 	case 0x0c:
1052a8a09c85SJason Gerecke 	case 0x0d:
1053a8a09c85SJason Gerecke 	case 0x0e:
1054a8a09c85SJason Gerecke 	case 0x0f:
1055a8a09c85SJason Gerecke 		/* unhandled */
1056a8a09c85SJason Gerecke 		break;
1057471d1714SBenjamin Tissoires 	}
1058471d1714SBenjamin Tissoires 
105982527da3SJason Gerecke 	input_report_abs(input, ABS_MISC,
106082527da3SJason Gerecke 			 wacom_intuos_id_mangle(wacom->id[idx])); /* report tool id */
1061471d1714SBenjamin Tissoires 	input_report_key(input, wacom->tool[idx], 1);
1062471d1714SBenjamin Tissoires 	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
1063b3bd7ef3SPing Cheng 	wacom->reporting_data = true;
106416e0a6a0SJason Gerecke 	return 2;
106516e0a6a0SJason Gerecke }
106616e0a6a0SJason Gerecke 
wacom_intuos_irq(struct wacom_wac * wacom)106716e0a6a0SJason Gerecke static int wacom_intuos_irq(struct wacom_wac *wacom)
106816e0a6a0SJason Gerecke {
106916e0a6a0SJason Gerecke 	unsigned char *data = wacom->data;
107016e0a6a0SJason Gerecke 	struct input_dev *input = wacom->pen_input;
107116e0a6a0SJason Gerecke 	int result;
107216e0a6a0SJason Gerecke 
107316e0a6a0SJason Gerecke 	if (data[0] != WACOM_REPORT_PENABLED &&
107406109993SJason Gerecke 	    data[0] != WACOM_REPORT_INTUOS_ID1 &&
107506109993SJason Gerecke 	    data[0] != WACOM_REPORT_INTUOS_ID2 &&
107616e0a6a0SJason Gerecke 	    data[0] != WACOM_REPORT_INTUOSPAD &&
107716e0a6a0SJason Gerecke 	    data[0] != WACOM_REPORT_INTUOS_PEN &&
107816e0a6a0SJason Gerecke 	    data[0] != WACOM_REPORT_CINTIQ &&
107916e0a6a0SJason Gerecke 	    data[0] != WACOM_REPORT_CINTIQPAD &&
108016e0a6a0SJason Gerecke 	    data[0] != WACOM_REPORT_INTUOS5PAD) {
108116e0a6a0SJason Gerecke 		dev_dbg(input->dev.parent,
108216e0a6a0SJason Gerecke 			"%s: received unknown report #%d\n", __func__, data[0]);
108316e0a6a0SJason Gerecke                 return 0;
108416e0a6a0SJason Gerecke 	}
108516e0a6a0SJason Gerecke 
108616e0a6a0SJason Gerecke 	/* process pad events */
108716e0a6a0SJason Gerecke 	result = wacom_intuos_pad(wacom);
108816e0a6a0SJason Gerecke 	if (result)
108916e0a6a0SJason Gerecke 		return result;
109016e0a6a0SJason Gerecke 
109116e0a6a0SJason Gerecke 	/* process in/out prox events */
109216e0a6a0SJason Gerecke 	result = wacom_intuos_inout(wacom);
109316e0a6a0SJason Gerecke 	if (result)
109416e0a6a0SJason Gerecke 		return result - 1;
109516e0a6a0SJason Gerecke 
109616e0a6a0SJason Gerecke 	/* process general packets */
109716e0a6a0SJason Gerecke 	result = wacom_intuos_general(wacom);
109816e0a6a0SJason Gerecke 	if (result)
109916e0a6a0SJason Gerecke 		return result - 1;
110016e0a6a0SJason Gerecke 
110116e0a6a0SJason Gerecke 	return 0;
1102471d1714SBenjamin Tissoires }
1103471d1714SBenjamin Tissoires 
wacom_remote_irq(struct wacom_wac * wacom_wac,size_t len)1104149f6f6bSJason Gerecke static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
1105149f6f6bSJason Gerecke {
1106149f6f6bSJason Gerecke 	unsigned char *data = wacom_wac->data;
1107149f6f6bSJason Gerecke 	struct input_dev *input;
1108149f6f6bSJason Gerecke 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
1109149f6f6bSJason Gerecke 	struct wacom_remote *remote = wacom->remote;
1110149f6f6bSJason Gerecke 	int bat_charging, bat_percent, touch_ring_mode;
1111149f6f6bSJason Gerecke 	__u32 serial;
1112149f6f6bSJason Gerecke 	int i, index = -1;
1113149f6f6bSJason Gerecke 	unsigned long flags;
1114149f6f6bSJason Gerecke 
1115149f6f6bSJason Gerecke 	if (data[0] != WACOM_REPORT_REMOTE) {
1116149f6f6bSJason Gerecke 		hid_dbg(wacom->hdev, "%s: received unknown report #%d",
1117149f6f6bSJason Gerecke 			__func__, data[0]);
1118149f6f6bSJason Gerecke 		return 0;
1119149f6f6bSJason Gerecke 	}
1120149f6f6bSJason Gerecke 
1121149f6f6bSJason Gerecke 	serial = data[3] + (data[4] << 8) + (data[5] << 16);
1122149f6f6bSJason Gerecke 	wacom_wac->id[0] = PAD_DEVICE_ID;
1123149f6f6bSJason Gerecke 
1124149f6f6bSJason Gerecke 	spin_lock_irqsave(&remote->remote_lock, flags);
1125149f6f6bSJason Gerecke 
1126149f6f6bSJason Gerecke 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1127149f6f6bSJason Gerecke 		if (remote->remotes[i].serial == serial) {
1128149f6f6bSJason Gerecke 			index = i;
1129149f6f6bSJason Gerecke 			break;
1130149f6f6bSJason Gerecke 		}
1131149f6f6bSJason Gerecke 	}
1132149f6f6bSJason Gerecke 
1133149f6f6bSJason Gerecke 	if (index < 0 || !remote->remotes[index].registered)
1134149f6f6bSJason Gerecke 		goto out;
1135149f6f6bSJason Gerecke 
11369ac6678bSAaron Armstrong Skomra 	remote->remotes[i].active_time = ktime_get();
1137149f6f6bSJason Gerecke 	input = remote->remotes[index].input;
1138149f6f6bSJason Gerecke 
1139149f6f6bSJason Gerecke 	input_report_key(input, BTN_0, (data[9] & 0x01));
1140149f6f6bSJason Gerecke 	input_report_key(input, BTN_1, (data[9] & 0x02));
1141149f6f6bSJason Gerecke 	input_report_key(input, BTN_2, (data[9] & 0x04));
1142149f6f6bSJason Gerecke 	input_report_key(input, BTN_3, (data[9] & 0x08));
1143149f6f6bSJason Gerecke 	input_report_key(input, BTN_4, (data[9] & 0x10));
1144149f6f6bSJason Gerecke 	input_report_key(input, BTN_5, (data[9] & 0x20));
1145149f6f6bSJason Gerecke 	input_report_key(input, BTN_6, (data[9] & 0x40));
1146149f6f6bSJason Gerecke 	input_report_key(input, BTN_7, (data[9] & 0x80));
1147149f6f6bSJason Gerecke 
1148149f6f6bSJason Gerecke 	input_report_key(input, BTN_8, (data[10] & 0x01));
1149149f6f6bSJason Gerecke 	input_report_key(input, BTN_9, (data[10] & 0x02));
1150149f6f6bSJason Gerecke 	input_report_key(input, BTN_A, (data[10] & 0x04));
1151149f6f6bSJason Gerecke 	input_report_key(input, BTN_B, (data[10] & 0x08));
1152149f6f6bSJason Gerecke 	input_report_key(input, BTN_C, (data[10] & 0x10));
1153149f6f6bSJason Gerecke 	input_report_key(input, BTN_X, (data[10] & 0x20));
1154149f6f6bSJason Gerecke 	input_report_key(input, BTN_Y, (data[10] & 0x40));
1155149f6f6bSJason Gerecke 	input_report_key(input, BTN_Z, (data[10] & 0x80));
1156149f6f6bSJason Gerecke 
1157149f6f6bSJason Gerecke 	input_report_key(input, BTN_BASE, (data[11] & 0x01));
1158149f6f6bSJason Gerecke 	input_report_key(input, BTN_BASE2, (data[11] & 0x02));
1159149f6f6bSJason Gerecke 
1160149f6f6bSJason Gerecke 	if (data[12] & 0x80)
1161fcf887e7SAaron Armstrong Skomra 		input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f) - 1);
1162149f6f6bSJason Gerecke 	else
1163149f6f6bSJason Gerecke 		input_report_abs(input, ABS_WHEEL, 0);
1164149f6f6bSJason Gerecke 
1165149f6f6bSJason Gerecke 	bat_percent = data[7] & 0x7f;
1166149f6f6bSJason Gerecke 	bat_charging = !!(data[7] & 0x80);
1167149f6f6bSJason Gerecke 
1168149f6f6bSJason Gerecke 	if (data[9] | data[10] | (data[11] & 0x03) | data[12])
1169149f6f6bSJason Gerecke 		input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
1170149f6f6bSJason Gerecke 	else
1171149f6f6bSJason Gerecke 		input_report_abs(input, ABS_MISC, 0);
1172149f6f6bSJason Gerecke 
1173149f6f6bSJason Gerecke 	input_event(input, EV_MSC, MSC_SERIAL, serial);
1174149f6f6bSJason Gerecke 
1175149f6f6bSJason Gerecke 	input_sync(input);
1176149f6f6bSJason Gerecke 
1177149f6f6bSJason Gerecke 	/*Which mode select (LED light) is currently on?*/
1178149f6f6bSJason Gerecke 	touch_ring_mode = (data[11] & 0xC0) >> 6;
1179149f6f6bSJason Gerecke 
1180149f6f6bSJason Gerecke 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1181149f6f6bSJason Gerecke 		if (remote->remotes[i].serial == serial)
1182149f6f6bSJason Gerecke 			wacom->led.groups[i].select = touch_ring_mode;
1183149f6f6bSJason Gerecke 	}
1184149f6f6bSJason Gerecke 
118516e45989SJason Gerecke 	__wacom_notify_battery(&remote->remotes[index].battery,
118616e45989SJason Gerecke 				WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
1187149f6f6bSJason Gerecke 				bat_charging, 1, bat_charging);
1188149f6f6bSJason Gerecke 
1189149f6f6bSJason Gerecke out:
1190149f6f6bSJason Gerecke 	spin_unlock_irqrestore(&remote->remote_lock, flags);
1191149f6f6bSJason Gerecke 	return 0;
1192149f6f6bSJason Gerecke }
1193149f6f6bSJason Gerecke 
wacom_remote_status_irq(struct wacom_wac * wacom_wac,size_t len)1194149f6f6bSJason Gerecke static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
1195149f6f6bSJason Gerecke {
1196149f6f6bSJason Gerecke 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
1197149f6f6bSJason Gerecke 	unsigned char *data = wacom_wac->data;
1198149f6f6bSJason Gerecke 	struct wacom_remote *remote = wacom->remote;
119955ab9b2cSAaron Armstrong Skomra 	struct wacom_remote_work_data remote_data;
1200149f6f6bSJason Gerecke 	unsigned long flags;
1201149f6f6bSJason Gerecke 	int i, ret;
1202149f6f6bSJason Gerecke 
1203149f6f6bSJason Gerecke 	if (data[0] != WACOM_REPORT_DEVICE_LIST)
1204149f6f6bSJason Gerecke 		return;
1205149f6f6bSJason Gerecke 
120655ab9b2cSAaron Armstrong Skomra 	memset(&remote_data, 0, sizeof(struct wacom_remote_work_data));
1207149f6f6bSJason Gerecke 
1208149f6f6bSJason Gerecke 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1209149f6f6bSJason Gerecke 		int j = i * 6;
1210149f6f6bSJason Gerecke 		int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
1211149f6f6bSJason Gerecke 
1212149f6f6bSJason Gerecke 		remote_data.remote[i].serial = serial;
1213149f6f6bSJason Gerecke 	}
1214149f6f6bSJason Gerecke 
1215149f6f6bSJason Gerecke 	spin_lock_irqsave(&remote->remote_lock, flags);
1216149f6f6bSJason Gerecke 
1217149f6f6bSJason Gerecke 	ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
1218149f6f6bSJason Gerecke 	if (ret != sizeof(remote_data)) {
1219149f6f6bSJason Gerecke 		spin_unlock_irqrestore(&remote->remote_lock, flags);
1220149f6f6bSJason Gerecke 		hid_err(wacom->hdev, "Can't queue Remote status event.\n");
1221149f6f6bSJason Gerecke 		return;
1222149f6f6bSJason Gerecke 	}
1223149f6f6bSJason Gerecke 
1224149f6f6bSJason Gerecke 	spin_unlock_irqrestore(&remote->remote_lock, flags);
1225149f6f6bSJason Gerecke 
1226149f6f6bSJason Gerecke 	wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
1227149f6f6bSJason Gerecke }
1228149f6f6bSJason Gerecke 
int_dist(int x1,int y1,int x2,int y2)1229471d1714SBenjamin Tissoires static int int_dist(int x1, int y1, int x2, int y2)
1230471d1714SBenjamin Tissoires {
1231471d1714SBenjamin Tissoires 	int x = x2 - x1;
1232471d1714SBenjamin Tissoires 	int y = y2 - y1;
1233471d1714SBenjamin Tissoires 
1234471d1714SBenjamin Tissoires 	return int_sqrt(x*x + y*y);
1235471d1714SBenjamin Tissoires }
1236471d1714SBenjamin Tissoires 
wacom_intuos_bt_process_data(struct wacom_wac * wacom,unsigned char * data)123781af7e61SBenjamin Tissoires static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
123881af7e61SBenjamin Tissoires 		unsigned char *data)
123981af7e61SBenjamin Tissoires {
124081af7e61SBenjamin Tissoires 	memcpy(wacom->data, data, 10);
124181af7e61SBenjamin Tissoires 	wacom_intuos_irq(wacom);
124281af7e61SBenjamin Tissoires 
12432a6cdbddSJason Gerecke 	input_sync(wacom->pen_input);
124481af7e61SBenjamin Tissoires 	if (wacom->pad_input)
124581af7e61SBenjamin Tissoires 		input_sync(wacom->pad_input);
124681af7e61SBenjamin Tissoires }
124781af7e61SBenjamin Tissoires 
wacom_intuos_bt_irq(struct wacom_wac * wacom,size_t len)124881af7e61SBenjamin Tissoires static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
124981af7e61SBenjamin Tissoires {
125081af7e61SBenjamin Tissoires 	unsigned char data[WACOM_PKGLEN_MAX];
125181af7e61SBenjamin Tissoires 	int i = 1;
125281af7e61SBenjamin Tissoires 	unsigned power_raw, battery_capacity, bat_charging, ps_connected;
125381af7e61SBenjamin Tissoires 
125481af7e61SBenjamin Tissoires 	memcpy(data, wacom->data, len);
125581af7e61SBenjamin Tissoires 
125681af7e61SBenjamin Tissoires 	switch (data[0]) {
125781af7e61SBenjamin Tissoires 	case 0x04:
125881af7e61SBenjamin Tissoires 		wacom_intuos_bt_process_data(wacom, data + i);
125981af7e61SBenjamin Tissoires 		i += 10;
1260df561f66SGustavo A. R. Silva 		fallthrough;
126181af7e61SBenjamin Tissoires 	case 0x03:
126281af7e61SBenjamin Tissoires 		wacom_intuos_bt_process_data(wacom, data + i);
126381af7e61SBenjamin Tissoires 		i += 10;
126481af7e61SBenjamin Tissoires 		wacom_intuos_bt_process_data(wacom, data + i);
126581af7e61SBenjamin Tissoires 		i += 10;
126681af7e61SBenjamin Tissoires 		power_raw = data[i];
126781af7e61SBenjamin Tissoires 		bat_charging = (power_raw & 0x08) ? 1 : 0;
126881af7e61SBenjamin Tissoires 		ps_connected = (power_raw & 0x10) ? 1 : 0;
126981af7e61SBenjamin Tissoires 		battery_capacity = batcap_i4[power_raw & 0x07];
127016e45989SJason Gerecke 		wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
127116e45989SJason Gerecke 				     battery_capacity, bat_charging,
127271fa641eSJason Gerecke 				     battery_capacity || bat_charging,
1273953f2c5fSJason Gerecke 				     ps_connected);
127481af7e61SBenjamin Tissoires 		break;
127581af7e61SBenjamin Tissoires 	default:
12762a6cdbddSJason Gerecke 		dev_dbg(wacom->pen_input->dev.parent,
127781af7e61SBenjamin Tissoires 				"Unknown report: %d,%d size:%zu\n",
127881af7e61SBenjamin Tissoires 				data[0], data[1], len);
127981af7e61SBenjamin Tissoires 		return 0;
128081af7e61SBenjamin Tissoires 	}
128181af7e61SBenjamin Tissoires 	return 0;
128281af7e61SBenjamin Tissoires }
128381af7e61SBenjamin Tissoires 
wacom_wac_finger_count_touches(struct wacom_wac * wacom)12847d059ed0SPing Cheng static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
12857d059ed0SPing Cheng {
12862a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
12877d059ed0SPing Cheng 	unsigned touch_max = wacom->features.touch_max;
12887d059ed0SPing Cheng 	int count = 0;
12897d059ed0SPing Cheng 	int i;
12907d059ed0SPing Cheng 
129126ba61f8SPing Cheng 	if (!touch_max)
129226ba61f8SPing Cheng 		return 0;
129326ba61f8SPing Cheng 
129471b5c476SJason Gerecke 	if (touch_max == 1)
129571b5c476SJason Gerecke 		return test_bit(BTN_TOUCH, input->key) &&
12961924e05eSPing Cheng 			report_touch_events(wacom);
12977d059ed0SPing Cheng 
12987d059ed0SPing Cheng 	for (i = 0; i < input->mt->num_slots; i++) {
12997d059ed0SPing Cheng 		struct input_mt_slot *ps = &input->mt->slots[i];
13007d059ed0SPing Cheng 		int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
13017d059ed0SPing Cheng 		if (id >= 0)
13027d059ed0SPing Cheng 			count++;
13037d059ed0SPing Cheng 	}
13047d059ed0SPing Cheng 
13057d059ed0SPing Cheng 	return count;
13067d059ed0SPing Cheng }
13077d059ed0SPing Cheng 
wacom_intuos_pro2_bt_pen(struct wacom_wac * wacom)13084922cd26SJason Gerecke static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
13094922cd26SJason Gerecke {
131087046b6cSAaron Armstrong Skomra 	int pen_frame_len, pen_frames;
13114922cd26SJason Gerecke 
13124922cd26SJason Gerecke 	struct input_dev *pen_input = wacom->pen_input;
13134922cd26SJason Gerecke 	unsigned char *data = wacom->data;
131417d793f3SPing Cheng 	int number_of_valid_frames = 0;
13159a6c0e28SJason Gerecke 	ktime_t time_interval = 15000000;
131617d793f3SPing Cheng 	ktime_t time_packet_received = ktime_get();
13174922cd26SJason Gerecke 	int i;
13184922cd26SJason Gerecke 
1319912c6aa6SAaron Armstrong Skomra 	if (wacom->features.type == INTUOSP2_BT ||
1320912c6aa6SAaron Armstrong Skomra 	    wacom->features.type == INTUOSP2S_BT) {
13214922cd26SJason Gerecke 		wacom->serial[0] = get_unaligned_le64(&data[99]);
13224922cd26SJason Gerecke 		wacom->id[0]     = get_unaligned_le16(&data[107]);
132387046b6cSAaron Armstrong Skomra 		pen_frame_len = 14;
132487046b6cSAaron Armstrong Skomra 		pen_frames = 7;
132587046b6cSAaron Armstrong Skomra 	} else {
132687046b6cSAaron Armstrong Skomra 		wacom->serial[0] = get_unaligned_le64(&data[33]);
132787046b6cSAaron Armstrong Skomra 		wacom->id[0]     = get_unaligned_le16(&data[41]);
132887046b6cSAaron Armstrong Skomra 		pen_frame_len = 8;
132987046b6cSAaron Armstrong Skomra 		pen_frames = 4;
133087046b6cSAaron Armstrong Skomra 	}
133187046b6cSAaron Armstrong Skomra 
13324922cd26SJason Gerecke 	if (wacom->serial[0] >> 52 == 1) {
13334922cd26SJason Gerecke 		/* Add back in missing bits of ID for non-USI pens */
13344922cd26SJason Gerecke 		wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
13354922cd26SJason Gerecke 	}
13364922cd26SJason Gerecke 
133717d793f3SPing Cheng 	/* number of valid frames */
13384922cd26SJason Gerecke 	for (i = 0; i < pen_frames; i++) {
13394922cd26SJason Gerecke 		unsigned char *frame = &data[i*pen_frame_len + 1];
1340a48324deSJason Gerecke 		bool valid = frame[0] & 0x80;
134117d793f3SPing Cheng 
134217d793f3SPing Cheng 		if (valid)
134317d793f3SPing Cheng 			number_of_valid_frames++;
134417d793f3SPing Cheng 	}
134517d793f3SPing Cheng 
134617d793f3SPing Cheng 	if (number_of_valid_frames) {
134717d793f3SPing Cheng 		if (wacom->hid_data.time_delayed)
134817d793f3SPing Cheng 			time_interval = ktime_get() - wacom->hid_data.time_delayed;
13499a6c0e28SJason Gerecke 		time_interval = div_u64(time_interval, number_of_valid_frames);
135017d793f3SPing Cheng 		wacom->hid_data.time_delayed = time_packet_received;
135117d793f3SPing Cheng 	}
135217d793f3SPing Cheng 
135317d793f3SPing Cheng 	for (i = 0; i < number_of_valid_frames; i++) {
135417d793f3SPing Cheng 		unsigned char *frame = &data[i*pen_frame_len + 1];
135517d793f3SPing Cheng 		bool valid = frame[0] & 0x80;
1356a48324deSJason Gerecke 		bool prox = frame[0] & 0x40;
1357a48324deSJason Gerecke 		bool range = frame[0] & 0x20;
13582cc08800SJason Gerecke 		bool invert = frame[0] & 0x10;
135917d793f3SPing Cheng 		int frames_number_reversed = number_of_valid_frames - i - 1;
13609a6c0e28SJason Gerecke 		ktime_t event_timestamp = time_packet_received - frames_number_reversed * time_interval;
13614922cd26SJason Gerecke 
1362a48324deSJason Gerecke 		if (!valid)
13634922cd26SJason Gerecke 			continue;
13644922cd26SJason Gerecke 
1365619d3a29SAaron Armstrong Skomra 		if (!prox) {
1366619d3a29SAaron Armstrong Skomra 			wacom->shared->stylus_in_proximity = false;
1367619d3a29SAaron Armstrong Skomra 			wacom_exit_report(wacom);
1368619d3a29SAaron Armstrong Skomra 			input_sync(pen_input);
13692cc08800SJason Gerecke 
13702cc08800SJason Gerecke 			wacom->tool[0] = 0;
13712cc08800SJason Gerecke 			wacom->id[0] = 0;
13722cc08800SJason Gerecke 			wacom->serial[0] = 0;
137317d793f3SPing Cheng 			wacom->hid_data.time_delayed = 0;
1374619d3a29SAaron Armstrong Skomra 			return;
1375619d3a29SAaron Armstrong Skomra 		}
13762cc08800SJason Gerecke 
1377a48324deSJason Gerecke 		if (range) {
13782cc08800SJason Gerecke 			if (!wacom->tool[0]) { /* first in range */
13792cc08800SJason Gerecke 				/* Going into range select tool */
13802cc08800SJason Gerecke 				if (invert)
13812cc08800SJason Gerecke 					wacom->tool[0] = BTN_TOOL_RUBBER;
13822cc08800SJason Gerecke 				else if (wacom->id[0])
13832cc08800SJason Gerecke 					wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0]);
13842cc08800SJason Gerecke 				else
13852cc08800SJason Gerecke 					wacom->tool[0] = BTN_TOOL_PEN;
13862cc08800SJason Gerecke 			}
13872cc08800SJason Gerecke 
138887046b6cSAaron Armstrong Skomra 			input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
138987046b6cSAaron Armstrong Skomra 			input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
139087046b6cSAaron Armstrong Skomra 
1391912c6aa6SAaron Armstrong Skomra 			if (wacom->features.type == INTUOSP2_BT ||
1392912c6aa6SAaron Armstrong Skomra 			    wacom->features.type == INTUOSP2S_BT) {
1393d252f4a1SJason Gerecke 				/* Fix rotation alignment: userspace expects zero at left */
139487046b6cSAaron Armstrong Skomra 				int16_t rotation =
139587046b6cSAaron Armstrong Skomra 					(int16_t)get_unaligned_le16(&frame[9]);
1396d252f4a1SJason Gerecke 				rotation += 1800/4;
139787046b6cSAaron Armstrong Skomra 
1398d252f4a1SJason Gerecke 				if (rotation > 899)
1399d252f4a1SJason Gerecke 					rotation -= 1800;
1400d252f4a1SJason Gerecke 
140187046b6cSAaron Armstrong Skomra 				input_report_abs(pen_input, ABS_TILT_X,
1402c68dab16SJason Gerecke 						 (signed char)frame[7]);
140387046b6cSAaron Armstrong Skomra 				input_report_abs(pen_input, ABS_TILT_Y,
1404c68dab16SJason Gerecke 						 (signed char)frame[8]);
1405d252f4a1SJason Gerecke 				input_report_abs(pen_input, ABS_Z, rotation);
140687046b6cSAaron Armstrong Skomra 				input_report_abs(pen_input, ABS_WHEEL,
140787046b6cSAaron Armstrong Skomra 						 get_unaligned_le16(&frame[11]));
140887046b6cSAaron Armstrong Skomra 			}
1409a48324deSJason Gerecke 		}
141017d793f3SPing Cheng 
1411e92a7be7SJason Gerecke 		if (wacom->tool[0]) {
1412a48324deSJason Gerecke 			input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
14137cdf6e40SAaron Armstrong Skomra 			if (wacom->features.type == INTUOSP2_BT ||
14147cdf6e40SAaron Armstrong Skomra 			    wacom->features.type == INTUOSP2S_BT) {
141587046b6cSAaron Armstrong Skomra 				input_report_abs(pen_input, ABS_DISTANCE,
141687046b6cSAaron Armstrong Skomra 						 range ? frame[13] : wacom->features.distance_max);
141787046b6cSAaron Armstrong Skomra 			} else {
141887046b6cSAaron Armstrong Skomra 				input_report_abs(pen_input, ABS_DISTANCE,
141987046b6cSAaron Armstrong Skomra 						 range ? frame[7] : wacom->features.distance_max);
142087046b6cSAaron Armstrong Skomra 			}
14214922cd26SJason Gerecke 
1422fe7f8d73SJason Gerecke 			input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x09);
14234922cd26SJason Gerecke 			input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
14244922cd26SJason Gerecke 			input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
14254922cd26SJason Gerecke 
1426a48324deSJason Gerecke 			input_report_key(pen_input, wacom->tool[0], prox);
14274922cd26SJason Gerecke 			input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
14284922cd26SJason Gerecke 			input_report_abs(pen_input, ABS_MISC,
14294922cd26SJason Gerecke 					 wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
1430e92a7be7SJason Gerecke 		}
14314922cd26SJason Gerecke 
1432a48324deSJason Gerecke 		wacom->shared->stylus_in_proximity = prox;
14334922cd26SJason Gerecke 
143417d793f3SPing Cheng 		/* add timestamp to unpack the frames */
143517d793f3SPing Cheng 		input_set_timestamp(pen_input, event_timestamp);
143617d793f3SPing Cheng 
14374922cd26SJason Gerecke 		input_sync(pen_input);
14384922cd26SJason Gerecke 	}
14394922cd26SJason Gerecke }
14404922cd26SJason Gerecke 
wacom_intuos_pro2_bt_touch(struct wacom_wac * wacom)14414922cd26SJason Gerecke static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
14424922cd26SJason Gerecke {
14434922cd26SJason Gerecke 	const int finger_touch_len = 8;
14444922cd26SJason Gerecke 	const int finger_frames = 4;
14454922cd26SJason Gerecke 	const int finger_frame_len = 43;
14464922cd26SJason Gerecke 
14474922cd26SJason Gerecke 	struct input_dev *touch_input = wacom->touch_input;
14484922cd26SJason Gerecke 	unsigned char *data = wacom->data;
14494922cd26SJason Gerecke 	int num_contacts_left = 5;
14504922cd26SJason Gerecke 	int i, j;
14514922cd26SJason Gerecke 
14524922cd26SJason Gerecke 	for (i = 0; i < finger_frames; i++) {
14534922cd26SJason Gerecke 		unsigned char *frame = &data[i*finger_frame_len + 109];
14544922cd26SJason Gerecke 		int current_num_contacts = frame[0] & 0x7F;
14554922cd26SJason Gerecke 		int contacts_to_send;
14564922cd26SJason Gerecke 
14574922cd26SJason Gerecke 		if (!(frame[0] & 0x80))
14584922cd26SJason Gerecke 			continue;
14594922cd26SJason Gerecke 
14604922cd26SJason Gerecke 		/*
14614922cd26SJason Gerecke 		 * First packet resets the counter since only the first
14624922cd26SJason Gerecke 		 * packet in series will have non-zero current_num_contacts.
14634922cd26SJason Gerecke 		 */
14644922cd26SJason Gerecke 		if (current_num_contacts)
14654922cd26SJason Gerecke 			wacom->num_contacts_left = current_num_contacts;
14664922cd26SJason Gerecke 
14674922cd26SJason Gerecke 		contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
14684922cd26SJason Gerecke 
14694922cd26SJason Gerecke 		for (j = 0; j < contacts_to_send; j++) {
14704922cd26SJason Gerecke 			unsigned char *touch = &frame[j*finger_touch_len + 1];
14714922cd26SJason Gerecke 			int slot = input_mt_get_slot_by_key(touch_input, touch[0]);
14724922cd26SJason Gerecke 			int x = get_unaligned_le16(&touch[2]);
14734922cd26SJason Gerecke 			int y = get_unaligned_le16(&touch[4]);
14744922cd26SJason Gerecke 			int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X);
14754922cd26SJason Gerecke 			int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y);
14764922cd26SJason Gerecke 
14774922cd26SJason Gerecke 			if (slot < 0)
14784922cd26SJason Gerecke 				continue;
14794922cd26SJason Gerecke 
14804922cd26SJason Gerecke 			input_mt_slot(touch_input, slot);
14814922cd26SJason Gerecke 			input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01);
14824922cd26SJason Gerecke 			input_report_abs(touch_input, ABS_MT_POSITION_X, x);
14834922cd26SJason Gerecke 			input_report_abs(touch_input, ABS_MT_POSITION_Y, y);
14844922cd26SJason Gerecke 			input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h));
14854922cd26SJason Gerecke 			input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h));
14864922cd26SJason Gerecke 			input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h);
14874922cd26SJason Gerecke 		}
14884922cd26SJason Gerecke 
14894922cd26SJason Gerecke 		input_mt_sync_frame(touch_input);
14904922cd26SJason Gerecke 
14914922cd26SJason Gerecke 		wacom->num_contacts_left -= contacts_to_send;
14924922cd26SJason Gerecke 		if (wacom->num_contacts_left <= 0) {
14934922cd26SJason Gerecke 			wacom->num_contacts_left = 0;
14944922cd26SJason Gerecke 			wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
149569dbdfffSJason Gerecke 			input_sync(touch_input);
14964922cd26SJason Gerecke 		}
14974922cd26SJason Gerecke 	}
14984922cd26SJason Gerecke 
149969dbdfffSJason Gerecke 	if (wacom->num_contacts_left == 0) {
150069dbdfffSJason Gerecke 		// Be careful that we don't accidentally call input_sync with
150169dbdfffSJason Gerecke 		// only a partial set of fingers of processed
15024922cd26SJason Gerecke 		input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
15034922cd26SJason Gerecke 		input_sync(touch_input);
15044922cd26SJason Gerecke 	}
15054922cd26SJason Gerecke 
150669dbdfffSJason Gerecke }
150769dbdfffSJason Gerecke 
wacom_intuos_pro2_bt_pad(struct wacom_wac * wacom)15084922cd26SJason Gerecke static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
15094922cd26SJason Gerecke {
15104922cd26SJason Gerecke 	struct input_dev *pad_input = wacom->pad_input;
15114922cd26SJason Gerecke 	unsigned char *data = wacom->data;
1512dcce8ef8SJason Gerecke 	int nbuttons = wacom->features.numbered_buttons;
15134922cd26SJason Gerecke 
1514dcce8ef8SJason Gerecke 	int expresskeys = data[282];
1515dcce8ef8SJason Gerecke 	int center = (data[281] & 0x40) >> 6;
1516d252f4a1SJason Gerecke 	int ring = data[285] & 0x7F;
1517d252f4a1SJason Gerecke 	bool ringstatus = data[285] & 0x80;
1518dcce8ef8SJason Gerecke 	bool prox = expresskeys || center || ringstatus;
1519d252f4a1SJason Gerecke 
1520d252f4a1SJason Gerecke 	/* Fix touchring data: userspace expects 0 at left and increasing clockwise */
1521d252f4a1SJason Gerecke 	ring = 71 - ring;
1522d252f4a1SJason Gerecke 	ring += 3*72/16;
1523d252f4a1SJason Gerecke 	if (ring > 71)
1524d252f4a1SJason Gerecke 		ring -= 72;
15254922cd26SJason Gerecke 
1526dcce8ef8SJason Gerecke 	wacom_report_numbered_buttons(pad_input, nbuttons,
1527dcce8ef8SJason Gerecke                                       expresskeys | (center << (nbuttons - 1)));
15284922cd26SJason Gerecke 
1529d252f4a1SJason Gerecke 	input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0);
15304922cd26SJason Gerecke 
15314922cd26SJason Gerecke 	input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
15324922cd26SJason Gerecke 	input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
15334922cd26SJason Gerecke 	input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
15344922cd26SJason Gerecke 
15354922cd26SJason Gerecke 	input_sync(pad_input);
15364922cd26SJason Gerecke }
15374922cd26SJason Gerecke 
wacom_intuos_pro2_bt_battery(struct wacom_wac * wacom)15384922cd26SJason Gerecke static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
15394922cd26SJason Gerecke {
15404922cd26SJason Gerecke 	unsigned char *data = wacom->data;
15414922cd26SJason Gerecke 
15424922cd26SJason Gerecke 	bool chg = data[284] & 0x80;
15434922cd26SJason Gerecke 	int battery_status = data[284] & 0x7F;
15444922cd26SJason Gerecke 
154516e45989SJason Gerecke 	wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
154616e45989SJason Gerecke 			     battery_status, chg, 1, chg);
15474922cd26SJason Gerecke }
15484922cd26SJason Gerecke 
wacom_intuos_gen3_bt_pad(struct wacom_wac * wacom)154987046b6cSAaron Armstrong Skomra static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom)
155087046b6cSAaron Armstrong Skomra {
155187046b6cSAaron Armstrong Skomra 	struct input_dev *pad_input = wacom->pad_input;
155287046b6cSAaron Armstrong Skomra 	unsigned char *data = wacom->data;
155387046b6cSAaron Armstrong Skomra 
155487046b6cSAaron Armstrong Skomra 	int buttons = data[44];
155587046b6cSAaron Armstrong Skomra 
155687046b6cSAaron Armstrong Skomra 	wacom_report_numbered_buttons(pad_input, 4, buttons);
155787046b6cSAaron Armstrong Skomra 
155887046b6cSAaron Armstrong Skomra 	input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0);
155987046b6cSAaron Armstrong Skomra 	input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0);
156087046b6cSAaron Armstrong Skomra 	input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
156187046b6cSAaron Armstrong Skomra 
156287046b6cSAaron Armstrong Skomra 	input_sync(pad_input);
156387046b6cSAaron Armstrong Skomra }
156487046b6cSAaron Armstrong Skomra 
wacom_intuos_gen3_bt_battery(struct wacom_wac * wacom)156587046b6cSAaron Armstrong Skomra static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom)
156687046b6cSAaron Armstrong Skomra {
156787046b6cSAaron Armstrong Skomra 	unsigned char *data = wacom->data;
156887046b6cSAaron Armstrong Skomra 
156987046b6cSAaron Armstrong Skomra 	bool chg = data[45] & 0x80;
157087046b6cSAaron Armstrong Skomra 	int battery_status = data[45] & 0x7F;
157187046b6cSAaron Armstrong Skomra 
157287046b6cSAaron Armstrong Skomra 	wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
157387046b6cSAaron Armstrong Skomra 			     battery_status, chg, 1, chg);
157487046b6cSAaron Armstrong Skomra }
157587046b6cSAaron Armstrong Skomra 
wacom_intuos_pro2_bt_irq(struct wacom_wac * wacom,size_t len)15764922cd26SJason Gerecke static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
15774922cd26SJason Gerecke {
15784922cd26SJason Gerecke 	unsigned char *data = wacom->data;
15794922cd26SJason Gerecke 
158087046b6cSAaron Armstrong Skomra 	if (data[0] != 0x80 && data[0] != 0x81) {
15814922cd26SJason Gerecke 		dev_dbg(wacom->pen_input->dev.parent,
15824922cd26SJason Gerecke 			"%s: received unknown report #%d\n", __func__, data[0]);
15834922cd26SJason Gerecke 		return 0;
15844922cd26SJason Gerecke 	}
15854922cd26SJason Gerecke 
15864922cd26SJason Gerecke 	wacom_intuos_pro2_bt_pen(wacom);
1587912c6aa6SAaron Armstrong Skomra 	if (wacom->features.type == INTUOSP2_BT ||
1588912c6aa6SAaron Armstrong Skomra 	    wacom->features.type == INTUOSP2S_BT) {
15894922cd26SJason Gerecke 		wacom_intuos_pro2_bt_touch(wacom);
15904922cd26SJason Gerecke 		wacom_intuos_pro2_bt_pad(wacom);
15914922cd26SJason Gerecke 		wacom_intuos_pro2_bt_battery(wacom);
159287046b6cSAaron Armstrong Skomra 	} else {
159387046b6cSAaron Armstrong Skomra 		wacom_intuos_gen3_bt_pad(wacom);
159487046b6cSAaron Armstrong Skomra 		wacom_intuos_gen3_bt_battery(wacom);
159587046b6cSAaron Armstrong Skomra 	}
15964922cd26SJason Gerecke 	return 0;
15974922cd26SJason Gerecke }
15984922cd26SJason Gerecke 
wacom_24hdt_irq(struct wacom_wac * wacom)1599471d1714SBenjamin Tissoires static int wacom_24hdt_irq(struct wacom_wac *wacom)
1600471d1714SBenjamin Tissoires {
16012a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
1602471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
1603471d1714SBenjamin Tissoires 	int i;
1604e0d41fd4SPing Cheng 	int current_num_contacts = data[61];
1605471d1714SBenjamin Tissoires 	int contacts_to_send = 0;
1606500d4160SPing Cheng 	int num_contacts_left = 4; /* maximum contacts per packet */
1607500d4160SPing Cheng 	int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
1608500d4160SPing Cheng 	int y_offset = 2;
1609500d4160SPing Cheng 
16109d339fe4SJason Gerecke 	if (touch_is_muted(wacom) && !wacom->shared->touch_down)
1611670e9092SAaron Armstrong Skomra 		return 0;
1612670e9092SAaron Armstrong Skomra 
1613500d4160SPing Cheng 	if (wacom->features.type == WACOM_27QHDT) {
1614500d4160SPing Cheng 		current_num_contacts = data[63];
1615500d4160SPing Cheng 		num_contacts_left = 10;
1616500d4160SPing Cheng 		byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
1617500d4160SPing Cheng 		y_offset = 0;
1618500d4160SPing Cheng 	}
1619471d1714SBenjamin Tissoires 
1620471d1714SBenjamin Tissoires 	/*
1621471d1714SBenjamin Tissoires 	 * First packet resets the counter since only the first
1622471d1714SBenjamin Tissoires 	 * packet in series will have non-zero current_num_contacts.
1623471d1714SBenjamin Tissoires 	 */
16247d059ed0SPing Cheng 	if (current_num_contacts)
1625471d1714SBenjamin Tissoires 		wacom->num_contacts_left = current_num_contacts;
1626471d1714SBenjamin Tissoires 
1627500d4160SPing Cheng 	contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
1628471d1714SBenjamin Tissoires 
1629471d1714SBenjamin Tissoires 	for (i = 0; i < contacts_to_send; i++) {
1630500d4160SPing Cheng 		int offset = (byte_per_packet * i) + 1;
16311924e05eSPing Cheng 		bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
1632471d1714SBenjamin Tissoires 		int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
1633471d1714SBenjamin Tissoires 
1634471d1714SBenjamin Tissoires 		if (slot < 0)
1635471d1714SBenjamin Tissoires 			continue;
1636471d1714SBenjamin Tissoires 		input_mt_slot(input, slot);
1637471d1714SBenjamin Tissoires 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
1638471d1714SBenjamin Tissoires 
1639471d1714SBenjamin Tissoires 		if (touch) {
1640471d1714SBenjamin Tissoires 			int t_x = get_unaligned_le16(&data[offset + 2]);
1641500d4160SPing Cheng 			int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]);
1642500d4160SPing Cheng 
1643500d4160SPing Cheng 			input_report_abs(input, ABS_MT_POSITION_X, t_x);
1644500d4160SPing Cheng 			input_report_abs(input, ABS_MT_POSITION_Y, t_y);
1645500d4160SPing Cheng 
1646500d4160SPing Cheng 			if (wacom->features.type != WACOM_27QHDT) {
1647471d1714SBenjamin Tissoires 				int c_x = get_unaligned_le16(&data[offset + 4]);
1648471d1714SBenjamin Tissoires 				int c_y = get_unaligned_le16(&data[offset + 8]);
1649471d1714SBenjamin Tissoires 				int w = get_unaligned_le16(&data[offset + 10]);
1650471d1714SBenjamin Tissoires 				int h = get_unaligned_le16(&data[offset + 12]);
1651471d1714SBenjamin Tissoires 
1652471d1714SBenjamin Tissoires 				input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
1653500d4160SPing Cheng 				input_report_abs(input, ABS_MT_WIDTH_MAJOR,
1654500d4160SPing Cheng 						 min(w, h) + int_dist(t_x, t_y, c_x, c_y));
1655471d1714SBenjamin Tissoires 				input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
1656471d1714SBenjamin Tissoires 				input_report_abs(input, ABS_MT_ORIENTATION, w > h);
1657471d1714SBenjamin Tissoires 			}
1658471d1714SBenjamin Tissoires 		}
1659500d4160SPing Cheng 	}
16609a1c0012SBenjamin Tissoires 	input_mt_sync_frame(input);
1661471d1714SBenjamin Tissoires 
1662471d1714SBenjamin Tissoires 	wacom->num_contacts_left -= contacts_to_send;
1663e0d41fd4SPing Cheng 	if (wacom->num_contacts_left <= 0) {
1664471d1714SBenjamin Tissoires 		wacom->num_contacts_left = 0;
16657d059ed0SPing Cheng 		wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1666e0d41fd4SPing Cheng 	}
1667471d1714SBenjamin Tissoires 	return 1;
1668471d1714SBenjamin Tissoires }
1669471d1714SBenjamin Tissoires 
wacom_mt_touch(struct wacom_wac * wacom)1670471d1714SBenjamin Tissoires static int wacom_mt_touch(struct wacom_wac *wacom)
1671471d1714SBenjamin Tissoires {
16722a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
1673471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
1674471d1714SBenjamin Tissoires 	int i;
1675471d1714SBenjamin Tissoires 	int current_num_contacts = data[2];
1676471d1714SBenjamin Tissoires 	int contacts_to_send = 0;
1677471d1714SBenjamin Tissoires 	int x_offset = 0;
1678471d1714SBenjamin Tissoires 
1679471d1714SBenjamin Tissoires 	/* MTTPC does not support Height and Width */
1680471d1714SBenjamin Tissoires 	if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
1681471d1714SBenjamin Tissoires 		x_offset = -4;
1682471d1714SBenjamin Tissoires 
1683471d1714SBenjamin Tissoires 	/*
1684471d1714SBenjamin Tissoires 	 * First packet resets the counter since only the first
1685471d1714SBenjamin Tissoires 	 * packet in series will have non-zero current_num_contacts.
1686471d1714SBenjamin Tissoires 	 */
16877d059ed0SPing Cheng 	if (current_num_contacts)
1688471d1714SBenjamin Tissoires 		wacom->num_contacts_left = current_num_contacts;
1689471d1714SBenjamin Tissoires 
1690471d1714SBenjamin Tissoires 	/* There are at most 5 contacts per packet */
1691471d1714SBenjamin Tissoires 	contacts_to_send = min(5, wacom->num_contacts_left);
1692471d1714SBenjamin Tissoires 
1693471d1714SBenjamin Tissoires 	for (i = 0; i < contacts_to_send; i++) {
1694471d1714SBenjamin Tissoires 		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
16951924e05eSPing Cheng 		bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
1696471d1714SBenjamin Tissoires 		int id = get_unaligned_le16(&data[offset + 1]);
1697471d1714SBenjamin Tissoires 		int slot = input_mt_get_slot_by_key(input, id);
1698471d1714SBenjamin Tissoires 
1699471d1714SBenjamin Tissoires 		if (slot < 0)
1700471d1714SBenjamin Tissoires 			continue;
1701471d1714SBenjamin Tissoires 
1702471d1714SBenjamin Tissoires 		input_mt_slot(input, slot);
1703471d1714SBenjamin Tissoires 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
1704471d1714SBenjamin Tissoires 		if (touch) {
1705471d1714SBenjamin Tissoires 			int x = get_unaligned_le16(&data[offset + x_offset + 7]);
1706471d1714SBenjamin Tissoires 			int y = get_unaligned_le16(&data[offset + x_offset + 9]);
1707471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MT_POSITION_X, x);
1708471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MT_POSITION_Y, y);
1709471d1714SBenjamin Tissoires 		}
1710471d1714SBenjamin Tissoires 	}
17119a1c0012SBenjamin Tissoires 	input_mt_sync_frame(input);
1712471d1714SBenjamin Tissoires 
1713471d1714SBenjamin Tissoires 	wacom->num_contacts_left -= contacts_to_send;
1714e0d41fd4SPing Cheng 	if (wacom->num_contacts_left <= 0) {
1715471d1714SBenjamin Tissoires 		wacom->num_contacts_left = 0;
17167d059ed0SPing Cheng 		wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1717e0d41fd4SPing Cheng 	}
1718471d1714SBenjamin Tissoires 	return 1;
1719471d1714SBenjamin Tissoires }
1720471d1714SBenjamin Tissoires 
wacom_tpc_mt_touch(struct wacom_wac * wacom)1721471d1714SBenjamin Tissoires static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
1722471d1714SBenjamin Tissoires {
17232a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
1724471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
1725471d1714SBenjamin Tissoires 	int i;
1726471d1714SBenjamin Tissoires 
1727471d1714SBenjamin Tissoires 	for (i = 0; i < 2; i++) {
1728471d1714SBenjamin Tissoires 		int p = data[1] & (1 << i);
17291924e05eSPing Cheng 		bool touch = p && report_touch_events(wacom);
1730471d1714SBenjamin Tissoires 
1731471d1714SBenjamin Tissoires 		input_mt_slot(input, i);
1732471d1714SBenjamin Tissoires 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
1733471d1714SBenjamin Tissoires 		if (touch) {
1734471d1714SBenjamin Tissoires 			int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff;
1735471d1714SBenjamin Tissoires 			int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff;
1736471d1714SBenjamin Tissoires 
1737471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MT_POSITION_X, x);
1738471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MT_POSITION_Y, y);
1739471d1714SBenjamin Tissoires 		}
1740471d1714SBenjamin Tissoires 	}
17419a1c0012SBenjamin Tissoires 	input_mt_sync_frame(input);
1742471d1714SBenjamin Tissoires 
1743471d1714SBenjamin Tissoires 	/* keep touch state for pen event */
17447d059ed0SPing Cheng 	wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1745471d1714SBenjamin Tissoires 
1746471d1714SBenjamin Tissoires 	return 1;
1747471d1714SBenjamin Tissoires }
1748471d1714SBenjamin Tissoires 
wacom_tpc_single_touch(struct wacom_wac * wacom,size_t len)1749471d1714SBenjamin Tissoires static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
1750471d1714SBenjamin Tissoires {
1751471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
17522a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
17531924e05eSPing Cheng 	bool prox = report_touch_events(wacom);
1754471d1714SBenjamin Tissoires 	int x = 0, y = 0;
1755471d1714SBenjamin Tissoires 
1756471d1714SBenjamin Tissoires 	if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
1757471d1714SBenjamin Tissoires 		return 0;
1758471d1714SBenjamin Tissoires 
1759471d1714SBenjamin Tissoires 	if (len == WACOM_PKGLEN_TPC1FG) {
1760e0d41fd4SPing Cheng 		prox = prox && (data[0] & 0x01);
1761471d1714SBenjamin Tissoires 		x = get_unaligned_le16(&data[1]);
1762471d1714SBenjamin Tissoires 		y = get_unaligned_le16(&data[3]);
1763471d1714SBenjamin Tissoires 	} else if (len == WACOM_PKGLEN_TPC1FG_B) {
1764e0d41fd4SPing Cheng 		prox = prox && (data[2] & 0x01);
1765471d1714SBenjamin Tissoires 		x = get_unaligned_le16(&data[3]);
1766471d1714SBenjamin Tissoires 		y = get_unaligned_le16(&data[5]);
1767471d1714SBenjamin Tissoires 	} else {
1768e0d41fd4SPing Cheng 		prox = prox && (data[1] & 0x01);
1769471d1714SBenjamin Tissoires 		x = le16_to_cpup((__le16 *)&data[2]);
1770471d1714SBenjamin Tissoires 		y = le16_to_cpup((__le16 *)&data[4]);
1771471d1714SBenjamin Tissoires 	}
1772471d1714SBenjamin Tissoires 
1773471d1714SBenjamin Tissoires 	if (prox) {
1774471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_X, x);
1775471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_Y, y);
1776471d1714SBenjamin Tissoires 	}
1777471d1714SBenjamin Tissoires 	input_report_key(input, BTN_TOUCH, prox);
1778471d1714SBenjamin Tissoires 
1779471d1714SBenjamin Tissoires 	/* keep touch state for pen events */
1780471d1714SBenjamin Tissoires 	wacom->shared->touch_down = prox;
1781471d1714SBenjamin Tissoires 
1782471d1714SBenjamin Tissoires 	return 1;
1783471d1714SBenjamin Tissoires }
1784471d1714SBenjamin Tissoires 
wacom_tpc_pen(struct wacom_wac * wacom)1785471d1714SBenjamin Tissoires static int wacom_tpc_pen(struct wacom_wac *wacom)
1786471d1714SBenjamin Tissoires {
1787471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
17882a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
1789471d1714SBenjamin Tissoires 	bool prox = data[1] & 0x20;
1790471d1714SBenjamin Tissoires 
1791471d1714SBenjamin Tissoires 	if (!wacom->shared->stylus_in_proximity) /* first in prox */
1792471d1714SBenjamin Tissoires 		/* Going into proximity select tool */
1793471d1714SBenjamin Tissoires 		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
1794471d1714SBenjamin Tissoires 
1795471d1714SBenjamin Tissoires 	/* keep pen state for touch events */
1796471d1714SBenjamin Tissoires 	wacom->shared->stylus_in_proximity = prox;
1797471d1714SBenjamin Tissoires 
17981924e05eSPing Cheng 	/* send pen events only when touch is up or forced out
17991924e05eSPing Cheng 	 * or touch arbitration is off
18001924e05eSPing Cheng 	 */
18011924e05eSPing Cheng 	if (!delay_pen_events(wacom)) {
1802471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS, data[1] & 0x02);
1803471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
1804471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
1805471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
18060b335cadSJason Gerecke 		input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x07) << 8) | data[6]);
1807471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, data[1] & 0x05);
1808471d1714SBenjamin Tissoires 		input_report_key(input, wacom->tool[0], prox);
1809471d1714SBenjamin Tissoires 		return 1;
1810471d1714SBenjamin Tissoires 	}
1811471d1714SBenjamin Tissoires 
1812471d1714SBenjamin Tissoires 	return 0;
1813471d1714SBenjamin Tissoires }
1814471d1714SBenjamin Tissoires 
wacom_tpc_irq(struct wacom_wac * wacom,size_t len)1815471d1714SBenjamin Tissoires static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
1816471d1714SBenjamin Tissoires {
1817471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
1818471d1714SBenjamin Tissoires 
18192ac97f0fSJason Gerecke 	if (wacom->pen_input) {
18202a6cdbddSJason Gerecke 		dev_dbg(wacom->pen_input->dev.parent,
18212a6cdbddSJason Gerecke 			"%s: received report #%d\n", __func__, data[0]);
18222ac97f0fSJason Gerecke 
18232ac97f0fSJason Gerecke 		if (len == WACOM_PKGLEN_PENABLED ||
18242ac97f0fSJason Gerecke 		    data[0] == WACOM_REPORT_PENABLED)
18252ac97f0fSJason Gerecke 			return wacom_tpc_pen(wacom);
18262ac97f0fSJason Gerecke 	}
18272ac97f0fSJason Gerecke 	else if (wacom->touch_input) {
18282a6cdbddSJason Gerecke 		dev_dbg(wacom->touch_input->dev.parent,
1829471d1714SBenjamin Tissoires 			"%s: received report #%d\n", __func__, data[0]);
1830471d1714SBenjamin Tissoires 
1831471d1714SBenjamin Tissoires 		switch (len) {
1832471d1714SBenjamin Tissoires 		case WACOM_PKGLEN_TPC1FG:
1833471d1714SBenjamin Tissoires 			return wacom_tpc_single_touch(wacom, len);
1834471d1714SBenjamin Tissoires 
1835471d1714SBenjamin Tissoires 		case WACOM_PKGLEN_TPC2FG:
1836471d1714SBenjamin Tissoires 			return wacom_tpc_mt_touch(wacom);
1837471d1714SBenjamin Tissoires 
1838471d1714SBenjamin Tissoires 		default:
1839471d1714SBenjamin Tissoires 			switch (data[0]) {
1840471d1714SBenjamin Tissoires 			case WACOM_REPORT_TPC1FG:
1841471d1714SBenjamin Tissoires 			case WACOM_REPORT_TPCHID:
1842471d1714SBenjamin Tissoires 			case WACOM_REPORT_TPCST:
1843471d1714SBenjamin Tissoires 			case WACOM_REPORT_TPC1FGE:
1844471d1714SBenjamin Tissoires 				return wacom_tpc_single_touch(wacom, len);
1845471d1714SBenjamin Tissoires 
1846471d1714SBenjamin Tissoires 			case WACOM_REPORT_TPCMT:
1847471d1714SBenjamin Tissoires 			case WACOM_REPORT_TPCMT2:
1848471d1714SBenjamin Tissoires 				return wacom_mt_touch(wacom);
1849471d1714SBenjamin Tissoires 
18502ac97f0fSJason Gerecke 			}
1851471d1714SBenjamin Tissoires 		}
1852471d1714SBenjamin Tissoires 	}
1853471d1714SBenjamin Tissoires 
1854471d1714SBenjamin Tissoires 	return 0;
1855471d1714SBenjamin Tissoires }
1856471d1714SBenjamin Tissoires 
wacom_offset_rotation(struct input_dev * input,struct hid_usage * usage,int value,int num,int denom)1857d252f4a1SJason Gerecke static int wacom_offset_rotation(struct input_dev *input, struct hid_usage *usage,
1858d252f4a1SJason Gerecke 				 int value, int num, int denom)
1859d252f4a1SJason Gerecke {
1860d252f4a1SJason Gerecke 	struct input_absinfo *abs = &input->absinfo[usage->code];
1861d252f4a1SJason Gerecke 	int range = (abs->maximum - abs->minimum + 1);
1862d252f4a1SJason Gerecke 
1863d252f4a1SJason Gerecke 	value += num*range/denom;
1864d252f4a1SJason Gerecke 	if (value > abs->maximum)
1865d252f4a1SJason Gerecke 		value -= range;
1866d252f4a1SJason Gerecke 	else if (value < abs->minimum)
1867d252f4a1SJason Gerecke 		value += range;
1868d252f4a1SJason Gerecke 	return value;
1869d252f4a1SJason Gerecke }
1870d252f4a1SJason Gerecke 
wacom_equivalent_usage(int usage)1871ac2423c9SAaron Armstrong Skomra int wacom_equivalent_usage(int usage)
1872c9c09587SJason Gerecke {
1873c9c09587SJason Gerecke 	if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
1874c9c09587SJason Gerecke 		int subpage = (usage & 0xFF00) << 8;
1875c9c09587SJason Gerecke 		int subusage = (usage & 0xFF);
1876c9c09587SJason Gerecke 
18775922e613SJason Gerecke 		if (subpage == WACOM_HID_SP_PAD ||
18785922e613SJason Gerecke 		    subpage == WACOM_HID_SP_BUTTON ||
18795922e613SJason Gerecke 		    subpage == WACOM_HID_SP_DIGITIZER ||
1880b5c921e6SJason Gerecke 		    subpage == WACOM_HID_SP_DIGITIZERINFO ||
188161ce346aSJason Gerecke 		    usage == WACOM_HID_WD_SENSE ||
1882f85c9dc6SJason Gerecke 		    usage == WACOM_HID_WD_SERIALHI ||
1883f85c9dc6SJason Gerecke 		    usage == WACOM_HID_WD_TOOLTYPE ||
18845922e613SJason Gerecke 		    usage == WACOM_HID_WD_DISTANCE ||
1885bf78adcbSJason Gerecke 		    usage == WACOM_HID_WD_TOUCHSTRIP ||
1886bf78adcbSJason Gerecke 		    usage == WACOM_HID_WD_TOUCHSTRIP2 ||
18875922e613SJason Gerecke 		    usage == WACOM_HID_WD_TOUCHRING ||
1888b1f466a9SAaron Armstrong Skomra 		    usage == WACOM_HID_WD_TOUCHRINGSTATUS ||
18896d09085bSJoshua-Dickens 		    usage == WACOM_HID_WD_REPORT_VALID ||
18906d09085bSJoshua-Dickens 		    usage == WACOM_HID_WD_BARRELSWITCH3 ||
18916d09085bSJoshua-Dickens 		    usage == WACOM_HID_WD_SEQUENCENUMBER) {
1892c9c09587SJason Gerecke 			return usage;
1893c9c09587SJason Gerecke 		}
1894c9c09587SJason Gerecke 
1895c9c09587SJason Gerecke 		if (subpage == HID_UP_UNDEFINED)
1896c9c09587SJason Gerecke 			subpage = HID_UP_DIGITIZER;
1897c9c09587SJason Gerecke 
1898c9c09587SJason Gerecke 		return subpage | subusage;
1899c9c09587SJason Gerecke 	}
1900c9c09587SJason Gerecke 
1901ac2423c9SAaron Armstrong Skomra 	if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMTOUCH) {
1902ac2423c9SAaron Armstrong Skomra 		int subpage = (usage & 0xFF00) << 8;
1903ac2423c9SAaron Armstrong Skomra 		int subusage = (usage & 0xFF);
1904ac2423c9SAaron Armstrong Skomra 
1905f4e11d59SAaron Armstrong Skomra 		if (usage == WACOM_HID_WT_REPORT_VALID)
1906f4e11d59SAaron Armstrong Skomra 			return usage;
1907f4e11d59SAaron Armstrong Skomra 
1908ac2423c9SAaron Armstrong Skomra 		if (subpage == HID_UP_UNDEFINED)
1909ac2423c9SAaron Armstrong Skomra 			subpage = WACOM_HID_SP_DIGITIZER;
1910ac2423c9SAaron Armstrong Skomra 
1911ac2423c9SAaron Armstrong Skomra 		return subpage | subusage;
1912ac2423c9SAaron Armstrong Skomra 	}
1913ac2423c9SAaron Armstrong Skomra 
1914c9c09587SJason Gerecke 	return usage;
1915c9c09587SJason Gerecke }
1916c9c09587SJason Gerecke 
wacom_map_usage(struct input_dev * input,struct hid_usage * usage,struct hid_field * field,__u8 type,__u16 code,int fuzz)19172a6cdbddSJason Gerecke static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
19187704ac93SBenjamin Tissoires 		struct hid_field *field, __u8 type, __u16 code, int fuzz)
19197704ac93SBenjamin Tissoires {
1920345857bbSJason Gerecke 	struct wacom *wacom = input_get_drvdata(input);
1921345857bbSJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1922345857bbSJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
19237704ac93SBenjamin Tissoires 	int fmin = field->logical_minimum;
19247704ac93SBenjamin Tissoires 	int fmax = field->logical_maximum;
1925c9c09587SJason Gerecke 	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
192650066a04SJason Gerecke 	int resolution_code = code;
19272b5f22eaSJason Gerecke 	int resolution;
192850066a04SJason Gerecke 
1929c9c09587SJason Gerecke 	if (equivalent_usage == HID_DG_TWIST) {
193050066a04SJason Gerecke 		resolution_code = ABS_RZ;
193150066a04SJason Gerecke 	}
19327704ac93SBenjamin Tissoires 
19332b5f22eaSJason Gerecke 	resolution = hidinput_calc_abs_res(field, resolution_code);
19342b5f22eaSJason Gerecke 
1935345857bbSJason Gerecke 	if (equivalent_usage == HID_GD_X) {
1936345857bbSJason Gerecke 		fmin += features->offset_left;
1937345857bbSJason Gerecke 		fmax -= features->offset_right;
1938345857bbSJason Gerecke 	}
1939345857bbSJason Gerecke 	if (equivalent_usage == HID_GD_Y) {
1940345857bbSJason Gerecke 		fmin += features->offset_top;
1941345857bbSJason Gerecke 		fmax -= features->offset_bottom;
1942345857bbSJason Gerecke 	}
1943345857bbSJason Gerecke 
19447704ac93SBenjamin Tissoires 	usage->type = type;
19457704ac93SBenjamin Tissoires 	usage->code = code;
19467704ac93SBenjamin Tissoires 
19477704ac93SBenjamin Tissoires 	switch (type) {
19487704ac93SBenjamin Tissoires 	case EV_ABS:
19497704ac93SBenjamin Tissoires 		input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
195008a46b41SPing Cheng 
195108a46b41SPing Cheng 		/* older tablet may miss physical usage */
195208a46b41SPing Cheng 		if ((code == ABS_X || code == ABS_Y) && !resolution) {
195308a46b41SPing Cheng 			resolution = WACOM_INTUOS_RES;
195408a46b41SPing Cheng 			hid_warn(input,
195508a46b41SPing Cheng 				 "Wacom usage (%d) missing resolution \n",
195608a46b41SPing Cheng 				 code);
195708a46b41SPing Cheng 		}
195808a46b41SPing Cheng 		input_abs_set_res(input, code, resolution);
19597704ac93SBenjamin Tissoires 		break;
19607704ac93SBenjamin Tissoires 	case EV_KEY:
19617704ac93SBenjamin Tissoires 	case EV_MSC:
1962bf78adcbSJason Gerecke 	case EV_SW:
196346fc466eSPing Cheng 		input_set_capability(input, type, code);
1964bf78adcbSJason Gerecke 		break;
19657704ac93SBenjamin Tissoires 	}
19667704ac93SBenjamin Tissoires }
19677704ac93SBenjamin Tissoires 
wacom_wac_battery_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)19685ac3d4aeSJason Gerecke static void wacom_wac_battery_usage_mapping(struct hid_device *hdev,
19695ac3d4aeSJason Gerecke 		struct hid_field *field, struct hid_usage *usage)
19705ac3d4aeSJason Gerecke {
1971bea407a4SJason Gerecke 	return;
19725ac3d4aeSJason Gerecke }
19735ac3d4aeSJason Gerecke 
wacom_wac_battery_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)19745ac3d4aeSJason Gerecke static void wacom_wac_battery_event(struct hid_device *hdev, struct hid_field *field,
19755ac3d4aeSJason Gerecke 		struct hid_usage *usage, __s32 value)
19765ac3d4aeSJason Gerecke {
19775ac3d4aeSJason Gerecke 	struct wacom *wacom = hid_get_drvdata(hdev);
19785ac3d4aeSJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
19795ac3d4aeSJason Gerecke 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
19805ac3d4aeSJason Gerecke 
19815ac3d4aeSJason Gerecke 	switch (equivalent_usage) {
19825ac3d4aeSJason Gerecke 	case HID_DG_BATTERYSTRENGTH:
19835ac3d4aeSJason Gerecke 		if (value == 0) {
19845ac3d4aeSJason Gerecke 			wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
19855ac3d4aeSJason Gerecke 		}
19865ac3d4aeSJason Gerecke 		else {
19875ac3d4aeSJason Gerecke 			value = value * 100 / (field->logical_maximum - field->logical_minimum);
19885ac3d4aeSJason Gerecke 			wacom_wac->hid_data.battery_capacity = value;
19895ac3d4aeSJason Gerecke 			wacom_wac->hid_data.bat_connected = 1;
19905ac3d4aeSJason Gerecke 			wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
19915ac3d4aeSJason Gerecke 		}
1992bea407a4SJason Gerecke 		wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY;
19935ac3d4aeSJason Gerecke 		break;
19945ac3d4aeSJason Gerecke 	case WACOM_HID_WD_BATTERY_LEVEL:
19955ac3d4aeSJason Gerecke 		value = value * 100 / (field->logical_maximum - field->logical_minimum);
19965ac3d4aeSJason Gerecke 		wacom_wac->hid_data.battery_capacity = value;
19975ac3d4aeSJason Gerecke 		wacom_wac->hid_data.bat_connected = 1;
19985ac3d4aeSJason Gerecke 		wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
1999bea407a4SJason Gerecke 		wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY;
20005ac3d4aeSJason Gerecke 		break;
20015ac3d4aeSJason Gerecke 	case WACOM_HID_WD_BATTERY_CHARGING:
20025ac3d4aeSJason Gerecke 		wacom_wac->hid_data.bat_charging = value;
20035ac3d4aeSJason Gerecke 		wacom_wac->hid_data.ps_connected = value;
20045ac3d4aeSJason Gerecke 		wacom_wac->hid_data.bat_connected = 1;
20055ac3d4aeSJason Gerecke 		wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
2006bea407a4SJason Gerecke 		wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY;
20075ac3d4aeSJason Gerecke 		break;
20085ac3d4aeSJason Gerecke 	}
20095ac3d4aeSJason Gerecke }
20105ac3d4aeSJason Gerecke 
wacom_wac_battery_pre_report(struct hid_device * hdev,struct hid_report * report)20115ac3d4aeSJason Gerecke static void wacom_wac_battery_pre_report(struct hid_device *hdev,
20125ac3d4aeSJason Gerecke 		struct hid_report *report)
20135ac3d4aeSJason Gerecke {
20145ac3d4aeSJason Gerecke 	return;
20155ac3d4aeSJason Gerecke }
20165ac3d4aeSJason Gerecke 
wacom_wac_battery_report(struct hid_device * hdev,struct hid_report * report)20175ac3d4aeSJason Gerecke static void wacom_wac_battery_report(struct hid_device *hdev,
20185ac3d4aeSJason Gerecke 		struct hid_report *report)
20195ac3d4aeSJason Gerecke {
20205ac3d4aeSJason Gerecke 	struct wacom *wacom = hid_get_drvdata(hdev);
20215ac3d4aeSJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
20225ac3d4aeSJason Gerecke 
20235ac3d4aeSJason Gerecke 	int status = wacom_wac->hid_data.bat_status;
20245ac3d4aeSJason Gerecke 	int capacity = wacom_wac->hid_data.battery_capacity;
20255ac3d4aeSJason Gerecke 	bool charging = wacom_wac->hid_data.bat_charging;
20265ac3d4aeSJason Gerecke 	bool connected = wacom_wac->hid_data.bat_connected;
20275ac3d4aeSJason Gerecke 	bool powered = wacom_wac->hid_data.ps_connected;
20285ac3d4aeSJason Gerecke 
20295ac3d4aeSJason Gerecke 	wacom_notify_battery(wacom_wac, status, capacity, charging,
20305ac3d4aeSJason Gerecke 			     connected, powered);
20315ac3d4aeSJason Gerecke }
20325ac3d4aeSJason Gerecke 
wacom_wac_pad_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)20335922e613SJason Gerecke static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
20345922e613SJason Gerecke 		struct hid_field *field, struct hid_usage *usage)
20355922e613SJason Gerecke {
20365922e613SJason Gerecke 	struct wacom *wacom = hid_get_drvdata(hdev);
20375922e613SJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
20385922e613SJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
20395922e613SJason Gerecke 	struct input_dev *input = wacom_wac->pad_input;
20405922e613SJason Gerecke 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
20415922e613SJason Gerecke 
20425922e613SJason Gerecke 	switch (equivalent_usage) {
20435922e613SJason Gerecke 	case WACOM_HID_WD_ACCELEROMETER_X:
20445922e613SJason Gerecke 		__set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
20455922e613SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 0);
2046f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
20475922e613SJason Gerecke 		break;
20485922e613SJason Gerecke 	case WACOM_HID_WD_ACCELEROMETER_Y:
20495922e613SJason Gerecke 		__set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
20505922e613SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 0);
2051f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
20525922e613SJason Gerecke 		break;
20535922e613SJason Gerecke 	case WACOM_HID_WD_ACCELEROMETER_Z:
20545922e613SJason Gerecke 		__set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
20555922e613SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
2056f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
20575922e613SJason Gerecke 		break;
205810c55cacSAaron Armstrong Skomra 	case WACOM_HID_WD_BUTTONCENTER:
20595922e613SJason Gerecke 	case WACOM_HID_WD_BUTTONHOME:
20605922e613SJason Gerecke 	case WACOM_HID_WD_BUTTONUP:
20615922e613SJason Gerecke 	case WACOM_HID_WD_BUTTONDOWN:
20625922e613SJason Gerecke 	case WACOM_HID_WD_BUTTONLEFT:
20635922e613SJason Gerecke 	case WACOM_HID_WD_BUTTONRIGHT:
20645922e613SJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY,
20655922e613SJason Gerecke 				wacom_numbered_button_to_key(features->numbered_buttons),
20665922e613SJason Gerecke 				0);
20675922e613SJason Gerecke 		features->numbered_buttons++;
2068f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
20695922e613SJason Gerecke 		break;
2070d793ff81SPing Cheng 	case WACOM_HID_WD_MUTE_DEVICE:
2071dc9dc864SPing Cheng 		/* softkey touch switch */
2072dc9dc864SPing Cheng 		wacom_wac->is_soft_touch_switch = true;
2073dc9dc864SPing Cheng 		fallthrough;
2074dc9dc864SPing Cheng 	case WACOM_HID_WD_TOUCHONOFF:
2075d2ec58aeSAaron Armstrong Skomra 		/*
2076dc9dc864SPing Cheng 		 * These two usages, which are used to mute touch events, come
2077dc9dc864SPing Cheng 		 * from the pad packet, but are reported on the touch
2078d2ec58aeSAaron Armstrong Skomra 		 * interface. Because the touch interface may not have
2079d2ec58aeSAaron Armstrong Skomra 		 * been created yet, we cannot call wacom_map_usage(). In
2080dc9dc864SPing Cheng 		 * order to process the usages when we receive them, we set
2081d2ec58aeSAaron Armstrong Skomra 		 * the usage type and code directly.
2082d2ec58aeSAaron Armstrong Skomra 		 */
2083d2ec58aeSAaron Armstrong Skomra 		wacom_wac->has_mute_touch_switch = true;
2084d2ec58aeSAaron Armstrong Skomra 		usage->type = EV_SW;
2085d2ec58aeSAaron Armstrong Skomra 		usage->code = SW_MUTE_DEVICE;
2086bf78adcbSJason Gerecke 		break;
2087bf78adcbSJason Gerecke 	case WACOM_HID_WD_TOUCHSTRIP:
2088bf78adcbSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0);
2089f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
2090bf78adcbSJason Gerecke 		break;
2091bf78adcbSJason Gerecke 	case WACOM_HID_WD_TOUCHSTRIP2:
2092bf78adcbSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_RY, 0);
2093f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
2094bf78adcbSJason Gerecke 		break;
20955922e613SJason Gerecke 	case WACOM_HID_WD_TOUCHRING:
20965922e613SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
2097f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
20985922e613SJason Gerecke 		break;
209960a22186SAaron Armstrong Skomra 	case WACOM_HID_WD_TOUCHRINGSTATUS:
21008d411cbfSJason Gerecke 		/*
21018d411cbfSJason Gerecke 		 * Only set up type/code association. Completely mapping
21028d411cbfSJason Gerecke 		 * this usage may overwrite the axis resolution and range.
21038d411cbfSJason Gerecke 		 */
21048d411cbfSJason Gerecke 		usage->type = EV_ABS;
21058d411cbfSJason Gerecke 		usage->code = ABS_WHEEL;
21068d411cbfSJason Gerecke 		set_bit(EV_ABS, input->evbit);
210760a22186SAaron Armstrong Skomra 		features->device_type |= WACOM_DEVICETYPE_PAD;
210860a22186SAaron Armstrong Skomra 		break;
21094eb220cbSPing Cheng 	case WACOM_HID_WD_BUTTONCONFIG:
21104eb220cbSPing Cheng 		wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
21114eb220cbSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
21124eb220cbSPing Cheng 		break;
21134eb220cbSPing Cheng 	case WACOM_HID_WD_ONSCREEN_KEYBOARD:
21144eb220cbSPing Cheng 		wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
21154eb220cbSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
21164eb220cbSPing Cheng 		break;
21174eb220cbSPing Cheng 	case WACOM_HID_WD_CONTROLPANEL:
21184eb220cbSPing Cheng 		wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
21194eb220cbSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
21204eb220cbSPing Cheng 		break;
21214082da80SBenjamin Tissoires 	case WACOM_HID_WD_MODE_CHANGE:
21224082da80SBenjamin Tissoires 		/* do not overwrite previous data */
21234082da80SBenjamin Tissoires 		if (!wacom_wac->has_mode_change) {
21244082da80SBenjamin Tissoires 			wacom_wac->has_mode_change = true;
21254082da80SBenjamin Tissoires 			wacom_wac->is_direct_mode = true;
21264082da80SBenjamin Tissoires 		}
21274082da80SBenjamin Tissoires 		features->device_type |= WACOM_DEVICETYPE_PAD;
21284082da80SBenjamin Tissoires 		break;
21295922e613SJason Gerecke 	}
21305922e613SJason Gerecke 
21315922e613SJason Gerecke 	switch (equivalent_usage & 0xfffffff0) {
21325922e613SJason Gerecke 	case WACOM_HID_WD_EXPRESSKEY00:
21335922e613SJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY,
21345922e613SJason Gerecke 				wacom_numbered_button_to_key(features->numbered_buttons),
21355922e613SJason Gerecke 				0);
21365922e613SJason Gerecke 		features->numbered_buttons++;
2137f3f24e7bSPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
21385922e613SJason Gerecke 		break;
21395922e613SJason Gerecke 	}
21405922e613SJason Gerecke }
21415922e613SJason Gerecke 
wacom_wac_pad_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2142c9cfb2acSPing Cheng static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field,
2143c9cfb2acSPing Cheng 		struct hid_usage *usage, __s32 value)
2144c9cfb2acSPing Cheng {
2145c9cfb2acSPing Cheng 	struct wacom *wacom = hid_get_drvdata(hdev);
2146c9cfb2acSPing Cheng 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2147c9cfb2acSPing Cheng 	struct input_dev *input = wacom_wac->pad_input;
2148c9cfb2acSPing Cheng 	struct wacom_features *features = &wacom_wac->features;
2149c9cfb2acSPing Cheng 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
215010c55cacSAaron Armstrong Skomra 	int i;
2151d252f4a1SJason Gerecke 	bool do_report = false;
2152c9cfb2acSPing Cheng 
215360a22186SAaron Armstrong Skomra 	/*
215460a22186SAaron Armstrong Skomra 	 * Avoid reporting this event and setting inrange_state if this usage
215560a22186SAaron Armstrong Skomra 	 * hasn't been mapped.
215660a22186SAaron Armstrong Skomra 	 */
21574082da80SBenjamin Tissoires 	if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
215860a22186SAaron Armstrong Skomra 		return;
2159c9cfb2acSPing Cheng 
2160c9cfb2acSPing Cheng 	if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
216160a22186SAaron Armstrong Skomra 		if (usage->hid != WACOM_HID_WD_TOUCHRING)
2162c9cfb2acSPing Cheng 			wacom_wac->hid_data.inrange_state |= value;
2163c9cfb2acSPing Cheng 	}
2164c9cfb2acSPing Cheng 
2165d6b67568SPing Cheng 	/* Process touch switch state first since it is reported through touch interface,
2166d6b67568SPing Cheng 	 * which is indepentent of pad interface. In the case when there are no other pad
2167d6b67568SPing Cheng 	 * events, the pad interface will not even be created.
2168d6b67568SPing Cheng 	 */
2169d6b67568SPing Cheng 	if ((equivalent_usage == WACOM_HID_WD_MUTE_DEVICE) ||
2170d6b67568SPing Cheng 	   (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)) {
2171d6b67568SPing Cheng 		if (wacom_wac->shared->touch_input) {
2172d6b67568SPing Cheng 			bool *is_touch_on = &wacom_wac->shared->is_touch_on;
2173d6b67568SPing Cheng 
2174d6b67568SPing Cheng 			if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value)
2175d6b67568SPing Cheng 				*is_touch_on = !(*is_touch_on);
2176d6b67568SPing Cheng 			else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)
2177d6b67568SPing Cheng 				*is_touch_on = value;
2178d6b67568SPing Cheng 
2179d6b67568SPing Cheng 			input_report_switch(wacom_wac->shared->touch_input,
2180d6b67568SPing Cheng 					    SW_MUTE_DEVICE, !(*is_touch_on));
2181d6b67568SPing Cheng 			input_sync(wacom_wac->shared->touch_input);
2182d6b67568SPing Cheng 		}
2183d6b67568SPing Cheng 		return;
2184d6b67568SPing Cheng 	}
2185d6b67568SPing Cheng 
2186d6b67568SPing Cheng 	if (!input)
2187d6b67568SPing Cheng 		return;
2188d6b67568SPing Cheng 
2189c9cfb2acSPing Cheng 	switch (equivalent_usage) {
2190d252f4a1SJason Gerecke 	case WACOM_HID_WD_TOUCHRING:
2191d252f4a1SJason Gerecke 		/*
2192d252f4a1SJason Gerecke 		 * Userspace expects touchrings to increase in value with
2193d252f4a1SJason Gerecke 		 * clockwise gestures and have their zero point at the
2194d252f4a1SJason Gerecke 		 * tablet's left. HID events "should" be clockwise-
2195d252f4a1SJason Gerecke 		 * increasing and zero at top, though the MobileStudio
2196d252f4a1SJason Gerecke 		 * Pro and 2nd-gen Intuos Pro don't do this...
2197d252f4a1SJason Gerecke 		 */
2198d252f4a1SJason Gerecke 		if (hdev->vendor == 0x56a &&
2199d252f4a1SJason Gerecke 		    (hdev->product == 0x34d || hdev->product == 0x34e ||  /* MobileStudio Pro */
2200384225c2SPing Cheng 		     hdev->product == 0x357 || hdev->product == 0x358 ||  /* Intuos Pro 2 */
22016e2abc68SAaron Armstrong Skomra 		     hdev->product == 0x392 ||				  /* Intuos Pro 2 */
2202fe4e940fSJason Gerecke 		     hdev->product == 0x398 || hdev->product == 0x399 ||  /* MobileStudio Pro */
2203fe4e940fSJason Gerecke 		     hdev->product == 0x3AA)) {				  /* MobileStudio Pro */
2204d252f4a1SJason Gerecke 			value = (field->logical_maximum - value);
2205d252f4a1SJason Gerecke 
22066e2abc68SAaron Armstrong Skomra 			if (hdev->product == 0x357 || hdev->product == 0x358 ||
22076e2abc68SAaron Armstrong Skomra 			    hdev->product == 0x392)
2208d252f4a1SJason Gerecke 				value = wacom_offset_rotation(input, usage, value, 3, 16);
2209384225c2SPing Cheng 			else if (hdev->product == 0x34d || hdev->product == 0x34e ||
2210fe4e940fSJason Gerecke 				 hdev->product == 0x398 || hdev->product == 0x399 ||
2211fe4e940fSJason Gerecke 				 hdev->product == 0x3AA)
2212d252f4a1SJason Gerecke 				value = wacom_offset_rotation(input, usage, value, 1, 2);
2213d252f4a1SJason Gerecke 		}
2214d252f4a1SJason Gerecke 		else {
2215d252f4a1SJason Gerecke 			value = wacom_offset_rotation(input, usage, value, 1, 4);
2216d252f4a1SJason Gerecke 		}
2217d252f4a1SJason Gerecke 		do_report = true;
2218d252f4a1SJason Gerecke 		break;
221993aab7faSJason Gerecke 	case WACOM_HID_WD_TOUCHRINGSTATUS:
222060a22186SAaron Armstrong Skomra 		if (!value)
222160a22186SAaron Armstrong Skomra 			input_event(input, usage->type, usage->code, 0);
2222354a3298SPing Cheng 		break;
222393aab7faSJason Gerecke 
22244082da80SBenjamin Tissoires 	case WACOM_HID_WD_MODE_CHANGE:
22254082da80SBenjamin Tissoires 		if (wacom_wac->is_direct_mode != value) {
22264082da80SBenjamin Tissoires 			wacom_wac->is_direct_mode = value;
22274082da80SBenjamin Tissoires 			wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
22284082da80SBenjamin Tissoires 		}
22294082da80SBenjamin Tissoires 		break;
22304082da80SBenjamin Tissoires 
223110c55cacSAaron Armstrong Skomra 	case WACOM_HID_WD_BUTTONCENTER:
223210c55cacSAaron Armstrong Skomra 		for (i = 0; i < wacom->led.count; i++)
223310c55cacSAaron Armstrong Skomra 			wacom_update_led(wacom, features->numbered_buttons,
223410c55cacSAaron Armstrong Skomra 					 value, i);
2235df561f66SGustavo A. R. Silva 		fallthrough;
223693aab7faSJason Gerecke 	default:
2237d252f4a1SJason Gerecke 		do_report = true;
2238d252f4a1SJason Gerecke 		break;
2239d252f4a1SJason Gerecke 	}
2240d252f4a1SJason Gerecke 
2241d252f4a1SJason Gerecke 	if (do_report) {
22425922e613SJason Gerecke 		input_event(input, usage->type, usage->code, value);
2243ed1fa736SPing Cheng 		if (value)
2244ed1fa736SPing Cheng 			wacom_wac->hid_data.pad_input_event_flag = true;
224593aab7faSJason Gerecke 	}
22465922e613SJason Gerecke }
22475922e613SJason Gerecke 
wacom_wac_pad_pre_report(struct hid_device * hdev,struct hid_report * report)22485922e613SJason Gerecke static void wacom_wac_pad_pre_report(struct hid_device *hdev,
22495922e613SJason Gerecke 		struct hid_report *report)
22505922e613SJason Gerecke {
22515922e613SJason Gerecke 	struct wacom *wacom = hid_get_drvdata(hdev);
22525922e613SJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
22535922e613SJason Gerecke 
22545922e613SJason Gerecke 	wacom_wac->hid_data.inrange_state = 0;
22555922e613SJason Gerecke }
22565922e613SJason Gerecke 
wacom_wac_pad_report(struct hid_device * hdev,struct hid_report * report,struct hid_field * field)2257c9cfb2acSPing Cheng static void wacom_wac_pad_report(struct hid_device *hdev,
2258f8b6a747SAaron Armstrong Skomra 		struct hid_report *report, struct hid_field *field)
2259c9cfb2acSPing Cheng {
2260c9cfb2acSPing Cheng 	struct wacom *wacom = hid_get_drvdata(hdev);
2261c9cfb2acSPing Cheng 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2262c9cfb2acSPing Cheng 	struct input_dev *input = wacom_wac->pad_input;
2263c9cfb2acSPing Cheng 	bool active = wacom_wac->hid_data.inrange_state != 0;
2264c9cfb2acSPing Cheng 
2265c9cfb2acSPing Cheng 	/* report prox for expresskey events */
2266d4b8efebSAaron Armstrong Skomra 	if (wacom_wac->hid_data.pad_input_event_flag) {
2267c9cfb2acSPing Cheng 		input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
22685922e613SJason Gerecke 		input_sync(input);
2269ed1fa736SPing Cheng 		if (!active)
2270ed1fa736SPing Cheng 			wacom_wac->hid_data.pad_input_event_flag = false;
22715922e613SJason Gerecke 	}
2272c9cfb2acSPing Cheng }
22735922e613SJason Gerecke 
wacom_set_barrel_switch3_usage(struct wacom_wac * wacom_wac)227446fc466eSPing Cheng static void wacom_set_barrel_switch3_usage(struct wacom_wac *wacom_wac)
227546fc466eSPing Cheng {
227646fc466eSPing Cheng 	struct input_dev *input = wacom_wac->pen_input;
227746fc466eSPing Cheng 	struct wacom_features *features = &wacom_wac->features;
227846fc466eSPing Cheng 
227946fc466eSPing Cheng 	if (!(features->quirks & WACOM_QUIRK_AESPEN) &&
228046fc466eSPing Cheng 	    wacom_wac->hid_data.barrelswitch &&
228146fc466eSPing Cheng 	    wacom_wac->hid_data.barrelswitch2 &&
22826d09085bSJoshua-Dickens 	    wacom_wac->hid_data.serialhi &&
22836d09085bSJoshua-Dickens 	    !wacom_wac->hid_data.barrelswitch3) {
228446fc466eSPing Cheng 		input_set_capability(input, EV_KEY, BTN_STYLUS3);
22856d09085bSJoshua-Dickens 		features->quirks |= WACOM_QUIRK_PEN_BUTTON3;
22866d09085bSJoshua-Dickens 	}
228746fc466eSPing Cheng }
228846fc466eSPing Cheng 
wacom_wac_pen_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)22897704ac93SBenjamin Tissoires static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
22907704ac93SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage)
22917704ac93SBenjamin Tissoires {
22927704ac93SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
22932a6cdbddSJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
229461ce346aSJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
22952a6cdbddSJason Gerecke 	struct input_dev *input = wacom_wac->pen_input;
2296c9c09587SJason Gerecke 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
22977704ac93SBenjamin Tissoires 
2298c9c09587SJason Gerecke 	switch (equivalent_usage) {
22997704ac93SBenjamin Tissoires 	case HID_GD_X:
23002a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
23017704ac93SBenjamin Tissoires 		break;
23027704ac93SBenjamin Tissoires 	case HID_GD_Y:
23032a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
23047704ac93SBenjamin Tissoires 		break;
2305b5c921e6SJason Gerecke 	case WACOM_HID_WD_DISTANCE:
230650066a04SJason Gerecke 	case HID_GD_Z:
230750066a04SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_DISTANCE, 0);
230850066a04SJason Gerecke 		break;
23097704ac93SBenjamin Tissoires 	case HID_DG_TIPPRESSURE:
23102a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_PRESSURE, 0);
23117704ac93SBenjamin Tissoires 		break;
23127704ac93SBenjamin Tissoires 	case HID_DG_INRANGE:
23132a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
23147704ac93SBenjamin Tissoires 		break;
23157704ac93SBenjamin Tissoires 	case HID_DG_INVERT:
23162a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY,
23177704ac93SBenjamin Tissoires 				BTN_TOOL_RUBBER, 0);
23187704ac93SBenjamin Tissoires 		break;
231950066a04SJason Gerecke 	case HID_DG_TILT_X:
232050066a04SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_TILT_X, 0);
232150066a04SJason Gerecke 		break;
232250066a04SJason Gerecke 	case HID_DG_TILT_Y:
232350066a04SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_TILT_Y, 0);
232450066a04SJason Gerecke 		break;
232550066a04SJason Gerecke 	case HID_DG_TWIST:
232650066a04SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
232750066a04SJason Gerecke 		break;
23287704ac93SBenjamin Tissoires 	case HID_DG_ERASER:
232946fc466eSPing Cheng 		input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
233046fc466eSPing Cheng 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
233146fc466eSPing Cheng 		break;
23327704ac93SBenjamin Tissoires 	case HID_DG_TIPSWITCH:
233346fc466eSPing Cheng 		input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
23342a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
23357704ac93SBenjamin Tissoires 		break;
23367704ac93SBenjamin Tissoires 	case HID_DG_BARRELSWITCH:
233746fc466eSPing Cheng 		wacom_wac->hid_data.barrelswitch = true;
233846fc466eSPing Cheng 		wacom_set_barrel_switch3_usage(wacom_wac);
23392a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS, 0);
23407704ac93SBenjamin Tissoires 		break;
23417704ac93SBenjamin Tissoires 	case HID_DG_BARRELSWITCH2:
234246fc466eSPing Cheng 		wacom_wac->hid_data.barrelswitch2 = true;
234346fc466eSPing Cheng 		wacom_set_barrel_switch3_usage(wacom_wac);
23442a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0);
23457704ac93SBenjamin Tissoires 		break;
23467704ac93SBenjamin Tissoires 	case HID_DG_TOOLSERIALNUMBER:
234783417206SJason Gerecke 		features->quirks |= WACOM_QUIRK_TOOLSERIAL;
23482a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
23497704ac93SBenjamin Tissoires 		break;
23506d09085bSJoshua-Dickens 	case HID_DG_SCANTIME:
23516d09085bSJoshua-Dickens 		wacom_map_usage(input, usage, field, EV_MSC, MSC_TIMESTAMP, 0);
23526d09085bSJoshua-Dickens 		break;
235361ce346aSJason Gerecke 	case WACOM_HID_WD_SENSE:
235461ce346aSJason Gerecke 		features->quirks |= WACOM_QUIRK_SENSE;
235561ce346aSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
235661ce346aSJason Gerecke 		break;
2357f85c9dc6SJason Gerecke 	case WACOM_HID_WD_SERIALHI:
235846fc466eSPing Cheng 		wacom_wac->hid_data.serialhi = true;
235946fc466eSPing Cheng 		wacom_set_barrel_switch3_usage(wacom_wac);
2360f85c9dc6SJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0);
2361f85c9dc6SJason Gerecke 		break;
2362929d6d5dSJason Gerecke 	case WACOM_HID_WD_FINGERWHEEL:
236346fc466eSPing Cheng 		input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
2364929d6d5dSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
2365929d6d5dSJason Gerecke 		break;
23666d09085bSJoshua-Dickens 	case WACOM_HID_WD_BARRELSWITCH3:
23676d09085bSJoshua-Dickens 		wacom_wac->hid_data.barrelswitch3 = true;
23686d09085bSJoshua-Dickens 		wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS3, 0);
23696d09085bSJoshua-Dickens 		features->quirks &= ~WACOM_QUIRK_PEN_BUTTON3;
23706d09085bSJoshua-Dickens 		break;
2371f7b4ba5fSJason Gerecke 	case WACOM_HID_WD_SEQUENCENUMBER:
2372f7b4ba5fSJason Gerecke 		wacom_wac->hid_data.sequence_number = -1;
2373f7b4ba5fSJason Gerecke 		break;
23747704ac93SBenjamin Tissoires 	}
23757704ac93SBenjamin Tissoires }
23767704ac93SBenjamin Tissoires 
wacom_wac_pen_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2377354a3298SPing Cheng static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
23787704ac93SBenjamin Tissoires 		struct hid_usage *usage, __s32 value)
23797704ac93SBenjamin Tissoires {
23807704ac93SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
23817704ac93SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
238261ce346aSJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
23832a6cdbddSJason Gerecke 	struct input_dev *input = wacom_wac->pen_input;
2384c9c09587SJason Gerecke 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
23857704ac93SBenjamin Tissoires 
2386b1f466a9SAaron Armstrong Skomra 	if (wacom_wac->is_invalid_bt_frame)
2387b1f466a9SAaron Armstrong Skomra 		return;
2388b1f466a9SAaron Armstrong Skomra 
2389c9c09587SJason Gerecke 	switch (equivalent_usage) {
239050066a04SJason Gerecke 	case HID_GD_Z:
239150066a04SJason Gerecke 		/*
239250066a04SJason Gerecke 		 * HID_GD_Z "should increase as the control's position is
239350066a04SJason Gerecke 		 * moved from high to low", while ABS_DISTANCE instead
239450066a04SJason Gerecke 		 * increases in value as the tool moves from low to high.
239550066a04SJason Gerecke 		 */
239650066a04SJason Gerecke 		value = field->logical_maximum - value;
239750066a04SJason Gerecke 		break;
23987704ac93SBenjamin Tissoires 	case HID_DG_INRANGE:
239994b17905SJason Gerecke 		mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100));
24007704ac93SBenjamin Tissoires 		wacom_wac->hid_data.inrange_state = value;
240161ce346aSJason Gerecke 		if (!(features->quirks & WACOM_QUIRK_SENSE))
240261ce346aSJason Gerecke 			wacom_wac->hid_data.sense_state = value;
2403354a3298SPing Cheng 		return;
24047704ac93SBenjamin Tissoires 	case HID_DG_INVERT:
24057704ac93SBenjamin Tissoires 		wacom_wac->hid_data.invert_state = value;
2406354a3298SPing Cheng 		return;
24077704ac93SBenjamin Tissoires 	case HID_DG_ERASER:
24087704ac93SBenjamin Tissoires 	case HID_DG_TIPSWITCH:
24097704ac93SBenjamin Tissoires 		wacom_wac->hid_data.tipswitch |= value;
2410354a3298SPing Cheng 		return;
24119e429d56SJason Gerecke 	case HID_DG_BARRELSWITCH:
24129e429d56SJason Gerecke 		wacom_wac->hid_data.barrelswitch = value;
24139e429d56SJason Gerecke 		return;
24149e429d56SJason Gerecke 	case HID_DG_BARRELSWITCH2:
24159e429d56SJason Gerecke 		wacom_wac->hid_data.barrelswitch2 = value;
24169e429d56SJason Gerecke 		return;
2417f85c9dc6SJason Gerecke 	case HID_DG_TOOLSERIALNUMBER:
2418993f0d93SJason Gerecke 		if (value) {
2419a35f09b8SDan Carpenter 			wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
2420ff479731SJason Gerecke 			wacom_wac->serial[0] |= wacom_s32tou(value, field->report_size);
2421993f0d93SJason Gerecke 		}
2422354a3298SPing Cheng 		return;
2423d252f4a1SJason Gerecke 	case HID_DG_TWIST:
24247ccced33SPing Cheng 		/* don't modify the value if the pen doesn't support the feature */
24257ccced33SPing Cheng 		if (!wacom_is_art_pen(wacom_wac->id[0])) return;
24267ccced33SPing Cheng 
2427d252f4a1SJason Gerecke 		/*
2428d252f4a1SJason Gerecke 		 * Userspace expects pen twist to have its zero point when
2429d252f4a1SJason Gerecke 		 * the buttons/finger is on the tablet's left. HID values
2430d252f4a1SJason Gerecke 		 * are zero when buttons are toward the top.
2431d252f4a1SJason Gerecke 		 */
2432d252f4a1SJason Gerecke 		value = wacom_offset_rotation(input, usage, value, 1, 4);
2433d252f4a1SJason Gerecke 		break;
243461ce346aSJason Gerecke 	case WACOM_HID_WD_SENSE:
243561ce346aSJason Gerecke 		wacom_wac->hid_data.sense_state = value;
2436354a3298SPing Cheng 		return;
2437f85c9dc6SJason Gerecke 	case WACOM_HID_WD_SERIALHI:
2438993f0d93SJason Gerecke 		if (value) {
2439ff479731SJason Gerecke 			__u32 raw_value = wacom_s32tou(value, field->report_size);
2440ff479731SJason Gerecke 
2441f85c9dc6SJason Gerecke 			wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
2442ff479731SJason Gerecke 			wacom_wac->serial[0] |= ((__u64)raw_value) << 32;
2443f85c9dc6SJason Gerecke 			/*
2444f85c9dc6SJason Gerecke 			 * Non-USI EMR devices may contain additional tool type
2445f85c9dc6SJason Gerecke 			 * information here. See WACOM_HID_WD_TOOLTYPE case for
2446f85c9dc6SJason Gerecke 			 * more details.
2447f85c9dc6SJason Gerecke 			 */
2448f85c9dc6SJason Gerecke 			if (value >> 20 == 1) {
2449ff479731SJason Gerecke 				wacom_wac->id[0] |= raw_value & 0xFFFFF;
2450f85c9dc6SJason Gerecke 			}
2451993f0d93SJason Gerecke 		}
2452354a3298SPing Cheng 		return;
2453f85c9dc6SJason Gerecke 	case WACOM_HID_WD_TOOLTYPE:
2454f85c9dc6SJason Gerecke 		/*
2455f85c9dc6SJason Gerecke 		 * Some devices (MobileStudio Pro, and possibly later
2456f85c9dc6SJason Gerecke 		 * devices as well) do not return the complete tool
2457f85c9dc6SJason Gerecke 		 * type in their WACOM_HID_WD_TOOLTYPE usage. Use a
2458f85c9dc6SJason Gerecke 		 * bitwise OR so the complete value can be built
2459f85c9dc6SJason Gerecke 		 * up over time :(
2460f85c9dc6SJason Gerecke 		 */
2461ff479731SJason Gerecke 		wacom_wac->id[0] |= wacom_s32tou(value, field->report_size);
2462354a3298SPing Cheng 		return;
2463345857bbSJason Gerecke 	case WACOM_HID_WD_OFFSETLEFT:
2464345857bbSJason Gerecke 		if (features->offset_left && value != features->offset_left)
246575a5f3acSColin Ian King 			hid_warn(hdev, "%s: overriding existing left offset "
2466345857bbSJason Gerecke 				 "%d -> %d\n", __func__, value,
2467345857bbSJason Gerecke 				 features->offset_left);
2468345857bbSJason Gerecke 		features->offset_left = value;
2469354a3298SPing Cheng 		return;
2470345857bbSJason Gerecke 	case WACOM_HID_WD_OFFSETRIGHT:
2471345857bbSJason Gerecke 		if (features->offset_right && value != features->offset_right)
247275a5f3acSColin Ian King 			hid_warn(hdev, "%s: overriding existing right offset "
2473345857bbSJason Gerecke 				 "%d -> %d\n", __func__, value,
2474345857bbSJason Gerecke 				 features->offset_right);
2475345857bbSJason Gerecke 		features->offset_right = value;
2476354a3298SPing Cheng 		return;
2477345857bbSJason Gerecke 	case WACOM_HID_WD_OFFSETTOP:
2478345857bbSJason Gerecke 		if (features->offset_top && value != features->offset_top)
247975a5f3acSColin Ian King 			hid_warn(hdev, "%s: overriding existing top offset "
2480345857bbSJason Gerecke 				 "%d -> %d\n", __func__, value,
2481345857bbSJason Gerecke 				 features->offset_top);
2482345857bbSJason Gerecke 		features->offset_top = value;
2483354a3298SPing Cheng 		return;
2484345857bbSJason Gerecke 	case WACOM_HID_WD_OFFSETBOTTOM:
2485345857bbSJason Gerecke 		if (features->offset_bottom && value != features->offset_bottom)
248675a5f3acSColin Ian King 			hid_warn(hdev, "%s: overriding existing bottom offset "
2487345857bbSJason Gerecke 				 "%d -> %d\n", __func__, value,
2488345857bbSJason Gerecke 				 features->offset_bottom);
2489345857bbSJason Gerecke 		features->offset_bottom = value;
2490354a3298SPing Cheng 		return;
2491b1f466a9SAaron Armstrong Skomra 	case WACOM_HID_WD_REPORT_VALID:
2492b1f466a9SAaron Armstrong Skomra 		wacom_wac->is_invalid_bt_frame = !value;
2493b1f466a9SAaron Armstrong Skomra 		return;
24946d09085bSJoshua-Dickens 	case WACOM_HID_WD_BARRELSWITCH3:
24956d09085bSJoshua-Dickens 		wacom_wac->hid_data.barrelswitch3 = value;
24966d09085bSJoshua-Dickens 		return;
24976d09085bSJoshua-Dickens 	case WACOM_HID_WD_SEQUENCENUMBER:
2498f7b4ba5fSJason Gerecke 		if (wacom_wac->hid_data.sequence_number != value &&
2499f7b4ba5fSJason Gerecke 		    wacom_wac->hid_data.sequence_number >= 0) {
250085572bf6SJason Gerecke 			int sequence_size = field->logical_maximum - field->logical_minimum + 1;
250185572bf6SJason Gerecke 			int drop_count = (value - wacom_wac->hid_data.sequence_number) % sequence_size;
250285572bf6SJason Gerecke 			hid_warn(hdev, "Dropped %d packets", drop_count);
250385572bf6SJason Gerecke 		}
25046d09085bSJoshua-Dickens 		wacom_wac->hid_data.sequence_number = value + 1;
250585572bf6SJason Gerecke 		if (wacom_wac->hid_data.sequence_number > field->logical_maximum)
250685572bf6SJason Gerecke 			wacom_wac->hid_data.sequence_number = field->logical_minimum;
25076d09085bSJoshua-Dickens 		return;
25087704ac93SBenjamin Tissoires 	}
25097704ac93SBenjamin Tissoires 
25101924e05eSPing Cheng 	/* send pen events only when touch is up or forced out
25111924e05eSPing Cheng 	 * or touch arbitration is off
25121924e05eSPing Cheng 	 */
25131924e05eSPing Cheng 	if (!usage->type || delay_pen_events(wacom_wac))
2514354a3298SPing Cheng 		return;
25157704ac93SBenjamin Tissoires 
25164affc233SJason Gerecke 	/* send pen events only when the pen is in range */
25175b40104eSJason Gerecke 	if (wacom_wac->hid_data.inrange_state)
25187704ac93SBenjamin Tissoires 		input_event(input, usage->type, usage->code, value);
25195b40104eSJason Gerecke 	else if (wacom_wac->shared->stylus_in_proximity && !wacom_wac->hid_data.sense_state)
25205b40104eSJason Gerecke 		input_event(input, usage->type, usage->code, 0);
25217704ac93SBenjamin Tissoires }
25227704ac93SBenjamin Tissoires 
wacom_wac_pen_pre_report(struct hid_device * hdev,struct hid_report * report)252306324e0cSJason Gerecke static void wacom_wac_pen_pre_report(struct hid_device *hdev,
252406324e0cSJason Gerecke 		struct hid_report *report)
252506324e0cSJason Gerecke {
2526b1f466a9SAaron Armstrong Skomra 	struct wacom *wacom = hid_get_drvdata(hdev);
2527b1f466a9SAaron Armstrong Skomra 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2528b1f466a9SAaron Armstrong Skomra 
2529b1f466a9SAaron Armstrong Skomra 	wacom_wac->is_invalid_bt_frame = false;
253006324e0cSJason Gerecke 	return;
253106324e0cSJason Gerecke }
253206324e0cSJason Gerecke 
wacom_wac_pen_report(struct hid_device * hdev,struct hid_report * report)25337704ac93SBenjamin Tissoires static void wacom_wac_pen_report(struct hid_device *hdev,
25347704ac93SBenjamin Tissoires 		struct hid_report *report)
25357704ac93SBenjamin Tissoires {
25367704ac93SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
25377704ac93SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
25382a6cdbddSJason Gerecke 	struct input_dev *input = wacom_wac->pen_input;
25397690dd18SJason Gerecke 	bool range = wacom_wac->hid_data.inrange_state;
25407690dd18SJason Gerecke 	bool sense = wacom_wac->hid_data.sense_state;
25417704ac93SBenjamin Tissoires 
2542b1f466a9SAaron Armstrong Skomra 	if (wacom_wac->is_invalid_bt_frame)
2543b1f466a9SAaron Armstrong Skomra 		return;
2544b1f466a9SAaron Armstrong Skomra 
25457690dd18SJason Gerecke 	if (!wacom_wac->tool[0] && range) { /* first in range */
25467690dd18SJason Gerecke 		/* Going into range select tool */
2547f85c9dc6SJason Gerecke 		if (wacom_wac->hid_data.invert_state)
2548f85c9dc6SJason Gerecke 			wacom_wac->tool[0] = BTN_TOOL_RUBBER;
2549f85c9dc6SJason Gerecke 		else if (wacom_wac->id[0])
2550f85c9dc6SJason Gerecke 			wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]);
2551f85c9dc6SJason Gerecke 		else
2552f85c9dc6SJason Gerecke 			wacom_wac->tool[0] = BTN_TOOL_PEN;
2553f85c9dc6SJason Gerecke 	}
25547704ac93SBenjamin Tissoires 
25557704ac93SBenjamin Tissoires 	/* keep pen state for touch events */
25567690dd18SJason Gerecke 	wacom_wac->shared->stylus_in_proximity = sense;
25577704ac93SBenjamin Tissoires 
255861ce346aSJason Gerecke 	if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
2559f85c9dc6SJason Gerecke 		int id = wacom_wac->id[0];
2560f77810f7SJason Gerecke 		if (wacom_wac->features.quirks & WACOM_QUIRK_PEN_BUTTON3) {
2561f77810f7SJason Gerecke 			int sw_state = wacom_wac->hid_data.barrelswitch |
2562f77810f7SJason Gerecke 				       (wacom_wac->hid_data.barrelswitch2 << 1);
2563f77810f7SJason Gerecke 			wacom_wac->hid_data.barrelswitch = sw_state == 1;
2564f77810f7SJason Gerecke 			wacom_wac->hid_data.barrelswitch2 = sw_state == 2;
2565f77810f7SJason Gerecke 			wacom_wac->hid_data.barrelswitch3 = sw_state == 3;
25666d09085bSJoshua-Dickens 		}
25676d09085bSJoshua-Dickens 		input_report_key(input, BTN_STYLUS, wacom_wac->hid_data.barrelswitch);
25686d09085bSJoshua-Dickens 		input_report_key(input, BTN_STYLUS2, wacom_wac->hid_data.barrelswitch2);
25696d09085bSJoshua-Dickens 		input_report_key(input, BTN_STYLUS3, wacom_wac->hid_data.barrelswitch3);
2570f85c9dc6SJason Gerecke 
2571f85c9dc6SJason Gerecke 		/*
2572f85c9dc6SJason Gerecke 		 * Non-USI EMR tools should have their IDs mangled to
2573f85c9dc6SJason Gerecke 		 * match the legacy behavior of wacom_intuos_general
2574f85c9dc6SJason Gerecke 		 */
2575f85c9dc6SJason Gerecke 		if (wacom_wac->serial[0] >> 52 == 1)
2576f85c9dc6SJason Gerecke 			id = wacom_intuos_id_mangle(id);
2577f85c9dc6SJason Gerecke 
2578f85c9dc6SJason Gerecke 		/*
2579f85c9dc6SJason Gerecke 		 * To ensure compatibility with xf86-input-wacom, we should
2580f85c9dc6SJason Gerecke 		 * report the BTN_TOOL_* event prior to the ABS_MISC or
2581f85c9dc6SJason Gerecke 		 * MSC_SERIAL events.
2582f85c9dc6SJason Gerecke 		 */
25837704ac93SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH,
25847704ac93SBenjamin Tissoires 				wacom_wac->hid_data.tipswitch);
25854affc233SJason Gerecke 		input_report_key(input, wacom_wac->tool[0], sense);
2586f85c9dc6SJason Gerecke 		if (wacom_wac->serial[0]) {
258704fa3e13STatsunosuke Tobita 			/*
258804fa3e13STatsunosuke Tobita 			 * xf86-input-wacom does not accept a serial number
258904fa3e13STatsunosuke Tobita 			 * of '0'. Report the low 32 bits if possible, but
259004fa3e13STatsunosuke Tobita 			 * if they are zero, report the upper ones instead.
259104fa3e13STatsunosuke Tobita 			 */
259204fa3e13STatsunosuke Tobita 			__u32 serial_lo = wacom_wac->serial[0] & 0xFFFFFFFFu;
259304fa3e13STatsunosuke Tobita 			__u32 serial_hi = wacom_wac->serial[0] >> 32;
259404fa3e13STatsunosuke Tobita 			input_event(input, EV_MSC, MSC_SERIAL, (int)(serial_lo ? serial_lo : serial_hi));
25954affc233SJason Gerecke 			input_report_abs(input, ABS_MISC, sense ? id : 0);
2596f85c9dc6SJason Gerecke 		}
25977704ac93SBenjamin Tissoires 
25987704ac93SBenjamin Tissoires 		wacom_wac->hid_data.tipswitch = false;
25997704ac93SBenjamin Tissoires 
26007704ac93SBenjamin Tissoires 		input_sync(input);
26017704ac93SBenjamin Tissoires 	}
260261ce346aSJason Gerecke 
26034affc233SJason Gerecke 	if (!sense) {
260461ce346aSJason Gerecke 		wacom_wac->tool[0] = 0;
2605f85c9dc6SJason Gerecke 		wacom_wac->id[0] = 0;
2606993f0d93SJason Gerecke 		wacom_wac->serial[0] = 0;
2607f85c9dc6SJason Gerecke 	}
26087704ac93SBenjamin Tissoires }
26097704ac93SBenjamin Tissoires 
wacom_wac_finger_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)26105ae6e89fSBenjamin Tissoires static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
26115ae6e89fSBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage)
26125ae6e89fSBenjamin Tissoires {
26135ae6e89fSBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
26145ae6e89fSBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
26152a6cdbddSJason Gerecke 	struct input_dev *input = wacom_wac->touch_input;
26165ae6e89fSBenjamin Tissoires 	unsigned touch_max = wacom_wac->features.touch_max;
2617c9c09587SJason Gerecke 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
26185ae6e89fSBenjamin Tissoires 
2619c9c09587SJason Gerecke 	switch (equivalent_usage) {
26205ae6e89fSBenjamin Tissoires 	case HID_GD_X:
26215ae6e89fSBenjamin Tissoires 		if (touch_max == 1)
26222a6cdbddSJason Gerecke 			wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
26235ae6e89fSBenjamin Tissoires 		else
26242a6cdbddSJason Gerecke 			wacom_map_usage(input, usage, field, EV_ABS,
26255ae6e89fSBenjamin Tissoires 					ABS_MT_POSITION_X, 4);
26265ae6e89fSBenjamin Tissoires 		break;
26275ae6e89fSBenjamin Tissoires 	case HID_GD_Y:
26285ae6e89fSBenjamin Tissoires 		if (touch_max == 1)
26292a6cdbddSJason Gerecke 			wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
26305ae6e89fSBenjamin Tissoires 		else
26312a6cdbddSJason Gerecke 			wacom_map_usage(input, usage, field, EV_ABS,
26325ae6e89fSBenjamin Tissoires 					ABS_MT_POSITION_Y, 4);
26335ae6e89fSBenjamin Tissoires 		break;
2634488abb5cSJason Gerecke 	case HID_DG_WIDTH:
2635488abb5cSJason Gerecke 	case HID_DG_HEIGHT:
2636488abb5cSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
2637488abb5cSJason Gerecke 		wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
2638488abb5cSJason Gerecke 		input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
2639488abb5cSJason Gerecke 		break;
26405ae6e89fSBenjamin Tissoires 	case HID_DG_TIPSWITCH:
26412a6cdbddSJason Gerecke 		wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
26425ae6e89fSBenjamin Tissoires 		break;
26431b5d514aSJason Gerecke 	case HID_DG_CONTACTCOUNT:
2644499522c8SJason Gerecke 		wacom_wac->hid_data.cc_report = field->report->id;
26451b5d514aSJason Gerecke 		wacom_wac->hid_data.cc_index = field->index;
26461b5d514aSJason Gerecke 		wacom_wac->hid_data.cc_value_index = usage->usage_index;
26471b5d514aSJason Gerecke 		break;
26486f107fabSJason Gerecke 	case HID_DG_CONTACTID:
26496f107fabSJason Gerecke 		if ((field->logical_maximum - field->logical_minimum) < touch_max) {
26506f107fabSJason Gerecke 			/*
26516f107fabSJason Gerecke 			 * The HID descriptor for G11 sensors leaves logical
26526f107fabSJason Gerecke 			 * maximum set to '1' despite it being a multitouch
26536f107fabSJason Gerecke 			 * device. Override to a sensible number.
26546f107fabSJason Gerecke 			 */
26556f107fabSJason Gerecke 			field->logical_maximum = 255;
26566f107fabSJason Gerecke 		}
26576f107fabSJason Gerecke 		break;
26586d09085bSJoshua-Dickens 	case HID_DG_SCANTIME:
26596d09085bSJoshua-Dickens 		wacom_map_usage(input, usage, field, EV_MSC, MSC_TIMESTAMP, 0);
26606d09085bSJoshua-Dickens 		break;
26615ae6e89fSBenjamin Tissoires 	}
26625ae6e89fSBenjamin Tissoires }
26635ae6e89fSBenjamin Tissoires 
wacom_wac_finger_slot(struct wacom_wac * wacom_wac,struct input_dev * input)2664601a22f3SJason Gerecke static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
2665601a22f3SJason Gerecke 		struct input_dev *input)
2666601a22f3SJason Gerecke {
2667601a22f3SJason Gerecke 	struct hid_data *hid_data = &wacom_wac->hid_data;
2668601a22f3SJason Gerecke 	bool mt = wacom_wac->features.touch_max > 1;
266953956bf4SJason Gerecke 	bool touch_down = hid_data->tipswitch && hid_data->confidence;
267053956bf4SJason Gerecke 	bool prox = touch_down && report_touch_events(wacom_wac);
2671601a22f3SJason Gerecke 
26729d339fe4SJason Gerecke 	if (touch_is_muted(wacom_wac)) {
2673d793ff81SPing Cheng 		if (!wacom_wac->shared->touch_down)
2674d793ff81SPing Cheng 			return;
2675e29c62ffSJiapeng Zhong 		prox = false;
2676d793ff81SPing Cheng 	}
2677601a22f3SJason Gerecke 
26781b5d514aSJason Gerecke 	wacom_wac->hid_data.num_received++;
26791b5d514aSJason Gerecke 	if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
26801b5d514aSJason Gerecke 		return;
26811b5d514aSJason Gerecke 
2682601a22f3SJason Gerecke 	if (mt) {
2683601a22f3SJason Gerecke 		int slot;
2684601a22f3SJason Gerecke 
2685601a22f3SJason Gerecke 		slot = input_mt_get_slot_by_key(input, hid_data->id);
2686ccb51c2eSJason Gerecke 		if (slot < 0) {
26877cc8524fSJason Gerecke 			return;
2688ccb51c2eSJason Gerecke 		} else {
2689ccb51c2eSJason Gerecke 			struct input_mt_slot *ps = &input->mt->slots[slot];
2690ccb51c2eSJason Gerecke 			int mt_id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
2691ccb51c2eSJason Gerecke 
2692ccb51c2eSJason Gerecke 			if (!prox && mt_id < 0) {
2693ccb51c2eSJason Gerecke 				// No data to send for this slot; short-circuit
2694ccb51c2eSJason Gerecke 				return;
2695ccb51c2eSJason Gerecke 			}
2696ccb51c2eSJason Gerecke 		}
26977cc8524fSJason Gerecke 
2698601a22f3SJason Gerecke 		input_mt_slot(input, slot);
2699601a22f3SJason Gerecke 		input_mt_report_slot_state(input, MT_TOOL_FINGER, prox);
2700601a22f3SJason Gerecke 	}
2701601a22f3SJason Gerecke 	else {
2702601a22f3SJason Gerecke 		input_report_key(input, BTN_TOUCH, prox);
2703601a22f3SJason Gerecke 	}
2704601a22f3SJason Gerecke 
2705601a22f3SJason Gerecke 	if (prox) {
2706601a22f3SJason Gerecke 		input_report_abs(input, mt ? ABS_MT_POSITION_X : ABS_X,
2707601a22f3SJason Gerecke 				 hid_data->x);
2708601a22f3SJason Gerecke 		input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y,
2709601a22f3SJason Gerecke 				 hid_data->y);
2710488abb5cSJason Gerecke 
2711488abb5cSJason Gerecke 		if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) {
2712488abb5cSJason Gerecke 			input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height));
2713488abb5cSJason Gerecke 			input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height));
2714488abb5cSJason Gerecke 			if (hid_data->width != hid_data->height)
2715488abb5cSJason Gerecke 				input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1);
2716488abb5cSJason Gerecke 		}
2717601a22f3SJason Gerecke 	}
2718601a22f3SJason Gerecke }
2719601a22f3SJason Gerecke 
wacom_wac_finger_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2720354a3298SPing Cheng static void wacom_wac_finger_event(struct hid_device *hdev,
27215ae6e89fSBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage, __s32 value)
27225ae6e89fSBenjamin Tissoires {
27235ae6e89fSBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
27245ae6e89fSBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2725c9c09587SJason Gerecke 	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
2726184eccd4SAaron Armstrong Skomra 	struct wacom_features *features = &wacom->wacom_wac.features;
27275ae6e89fSBenjamin Tissoires 
27289d339fe4SJason Gerecke 	if (touch_is_muted(wacom_wac) && !wacom_wac->shared->touch_down)
27295bed0128SJason Gerecke 		return;
27305bed0128SJason Gerecke 
2731f4e11d59SAaron Armstrong Skomra 	if (wacom_wac->is_invalid_bt_frame)
2732f4e11d59SAaron Armstrong Skomra 		return;
27335ae6e89fSBenjamin Tissoires 
2734c9c09587SJason Gerecke 	switch (equivalent_usage) {
27357fb0413bSJason Gerecke 	case HID_DG_CONFIDENCE:
27367fb0413bSJason Gerecke 		wacom_wac->hid_data.confidence = value;
27377fb0413bSJason Gerecke 		break;
27385ae6e89fSBenjamin Tissoires 	case HID_GD_X:
27395ae6e89fSBenjamin Tissoires 		wacom_wac->hid_data.x = value;
27405ae6e89fSBenjamin Tissoires 		break;
27415ae6e89fSBenjamin Tissoires 	case HID_GD_Y:
27425ae6e89fSBenjamin Tissoires 		wacom_wac->hid_data.y = value;
27435ae6e89fSBenjamin Tissoires 		break;
2744488abb5cSJason Gerecke 	case HID_DG_WIDTH:
2745488abb5cSJason Gerecke 		wacom_wac->hid_data.width = value;
2746488abb5cSJason Gerecke 		break;
2747488abb5cSJason Gerecke 	case HID_DG_HEIGHT:
2748488abb5cSJason Gerecke 		wacom_wac->hid_data.height = value;
2749488abb5cSJason Gerecke 		break;
27505ae6e89fSBenjamin Tissoires 	case HID_DG_CONTACTID:
27515ae6e89fSBenjamin Tissoires 		wacom_wac->hid_data.id = value;
27525ae6e89fSBenjamin Tissoires 		break;
27535ae6e89fSBenjamin Tissoires 	case HID_DG_TIPSWITCH:
27545ae6e89fSBenjamin Tissoires 		wacom_wac->hid_data.tipswitch = value;
27555ae6e89fSBenjamin Tissoires 		break;
2756f4e11d59SAaron Armstrong Skomra 	case WACOM_HID_WT_REPORT_VALID:
2757f4e11d59SAaron Armstrong Skomra 		wacom_wac->is_invalid_bt_frame = !value;
2758f4e11d59SAaron Armstrong Skomra 		return;
2759184eccd4SAaron Armstrong Skomra 	case HID_DG_CONTACTMAX:
276088f38846SJason Gerecke 		if (!features->touch_max) {
2761184eccd4SAaron Armstrong Skomra 			features->touch_max = value;
276288f38846SJason Gerecke 		} else {
276388f38846SJason Gerecke 			hid_warn(hdev, "%s: ignoring attempt to overwrite non-zero touch_max "
276488f38846SJason Gerecke 				 "%d -> %d\n", __func__, features->touch_max, value);
276588f38846SJason Gerecke 		}
2766184eccd4SAaron Armstrong Skomra 		return;
27675ae6e89fSBenjamin Tissoires 	}
27685ae6e89fSBenjamin Tissoires 
2769601a22f3SJason Gerecke 	if (usage->usage_index + 1 == field->report_count) {
277053956bf4SJason Gerecke 		if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
27712a6cdbddSJason Gerecke 			wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
2772601a22f3SJason Gerecke 	}
27735ae6e89fSBenjamin Tissoires }
27745ae6e89fSBenjamin Tissoires 
wacom_wac_finger_pre_report(struct hid_device * hdev,struct hid_report * report)277506324e0cSJason Gerecke static void wacom_wac_finger_pre_report(struct hid_device *hdev,
277606324e0cSJason Gerecke 		struct hid_report *report)
277706324e0cSJason Gerecke {
27781b5d514aSJason Gerecke 	struct wacom *wacom = hid_get_drvdata(hdev);
27791b5d514aSJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
27801b5d514aSJason Gerecke 	struct hid_data* hid_data = &wacom_wac->hid_data;
2781499522c8SJason Gerecke 	int i;
2782499522c8SJason Gerecke 
27839d339fe4SJason Gerecke 	if (touch_is_muted(wacom_wac) && !wacom_wac->shared->touch_down)
27845bed0128SJason Gerecke 		return;
27855bed0128SJason Gerecke 
2786f4e11d59SAaron Armstrong Skomra 	wacom_wac->is_invalid_bt_frame = false;
2787f4e11d59SAaron Armstrong Skomra 
27887fb0413bSJason Gerecke 	hid_data->confidence = true;
27897fb0413bSJason Gerecke 
279020f3cf5fSJason Gerecke 	hid_data->cc_report = 0;
279120f3cf5fSJason Gerecke 	hid_data->cc_index = -1;
279220f3cf5fSJason Gerecke 	hid_data->cc_value_index = -1;
279320f3cf5fSJason Gerecke 
2794499522c8SJason Gerecke 	for (i = 0; i < report->maxfield; i++) {
2795499522c8SJason Gerecke 		struct hid_field *field = report->field[i];
2796499522c8SJason Gerecke 		int j;
2797499522c8SJason Gerecke 
2798499522c8SJason Gerecke 		for (j = 0; j < field->maxusage; j++) {
2799003f50abSJason Gerecke 			struct hid_usage *usage = &field->usage[j];
2800ac2423c9SAaron Armstrong Skomra 			unsigned int equivalent_usage =
2801ac2423c9SAaron Armstrong Skomra 				wacom_equivalent_usage(usage->hid);
2802003f50abSJason Gerecke 
2803ac2423c9SAaron Armstrong Skomra 			switch (equivalent_usage) {
2804003f50abSJason Gerecke 			case HID_GD_X:
2805003f50abSJason Gerecke 			case HID_GD_Y:
2806003f50abSJason Gerecke 			case HID_DG_WIDTH:
2807003f50abSJason Gerecke 			case HID_DG_HEIGHT:
2808003f50abSJason Gerecke 			case HID_DG_CONTACTID:
2809003f50abSJason Gerecke 			case HID_DG_INRANGE:
2810003f50abSJason Gerecke 			case HID_DG_INVERT:
2811003f50abSJason Gerecke 			case HID_DG_TIPSWITCH:
2812ac2423c9SAaron Armstrong Skomra 				hid_data->last_slot_field = equivalent_usage;
2813003f50abSJason Gerecke 				break;
2814b43f977dSJason Gerecke 			case HID_DG_CONTACTCOUNT:
2815b43f977dSJason Gerecke 				hid_data->cc_report = report->id;
2816b43f977dSJason Gerecke 				hid_data->cc_index = i;
2817b43f977dSJason Gerecke 				hid_data->cc_value_index = j;
2818b43f977dSJason Gerecke 				break;
2819003f50abSJason Gerecke 			}
2820003f50abSJason Gerecke 		}
2821003f50abSJason Gerecke 	}
2822b43f977dSJason Gerecke 
2823b43f977dSJason Gerecke 	if (hid_data->cc_report != 0 &&
2824b43f977dSJason Gerecke 	    hid_data->cc_index >= 0) {
2825b43f977dSJason Gerecke 		struct hid_field *field = report->field[hid_data->cc_index];
2826b43f977dSJason Gerecke 		int value = field->value[hid_data->cc_value_index];
2827546e41acSJason Gerecke 		if (value) {
2828b43f977dSJason Gerecke 			hid_data->num_expected = value;
2829546e41acSJason Gerecke 			hid_data->num_received = 0;
2830546e41acSJason Gerecke 		}
2831b43f977dSJason Gerecke 	}
2832b43f977dSJason Gerecke 	else {
2833b43f977dSJason Gerecke 		hid_data->num_expected = wacom_wac->features.touch_max;
2834546e41acSJason Gerecke 		hid_data->num_received = 0;
2835b43f977dSJason Gerecke 	}
283606324e0cSJason Gerecke }
283706324e0cSJason Gerecke 
wacom_wac_finger_report(struct hid_device * hdev,struct hid_report * report)28385ae6e89fSBenjamin Tissoires static void wacom_wac_finger_report(struct hid_device *hdev,
28395ae6e89fSBenjamin Tissoires 		struct hid_report *report)
28405ae6e89fSBenjamin Tissoires {
28415ae6e89fSBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
28425ae6e89fSBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
28432a6cdbddSJason Gerecke 	struct input_dev *input = wacom_wac->touch_input;
28445ae6e89fSBenjamin Tissoires 	unsigned touch_max = wacom_wac->features.touch_max;
28455ae6e89fSBenjamin Tissoires 
2846ccb51c2eSJason Gerecke 	/* if there was nothing to process, don't send an empty sync */
2847ccb51c2eSJason Gerecke 	if (wacom_wac->hid_data.num_expected == 0)
2848ccb51c2eSJason Gerecke 		return;
2849ccb51c2eSJason Gerecke 
28501b5d514aSJason Gerecke 	/* If more packets of data are expected, give us a chance to
28511b5d514aSJason Gerecke 	 * process them rather than immediately syncing a partial
28521b5d514aSJason Gerecke 	 * update.
28531b5d514aSJason Gerecke 	 */
28541b5d514aSJason Gerecke 	if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected)
28551b5d514aSJason Gerecke 		return;
28561b5d514aSJason Gerecke 
28575ae6e89fSBenjamin Tissoires 	if (touch_max > 1)
2858601a22f3SJason Gerecke 		input_mt_sync_frame(input);
2859601a22f3SJason Gerecke 
28605ae6e89fSBenjamin Tissoires 	input_sync(input);
28611b5d514aSJason Gerecke 	wacom_wac->hid_data.num_received = 0;
2862546e41acSJason Gerecke 	wacom_wac->hid_data.num_expected = 0;
28635ae6e89fSBenjamin Tissoires 
28645ae6e89fSBenjamin Tissoires 	/* keep touch state for pen event */
28657d059ed0SPing Cheng 	wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
28665ae6e89fSBenjamin Tissoires }
28675ae6e89fSBenjamin Tissoires 
wacom_wac_usage_mapping(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage)28687704ac93SBenjamin Tissoires void wacom_wac_usage_mapping(struct hid_device *hdev,
28697704ac93SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage)
28707704ac93SBenjamin Tissoires {
28717704ac93SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
28727704ac93SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2873e5bc8eb1SJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
28747704ac93SBenjamin Tissoires 
2875ac2423c9SAaron Armstrong Skomra 	if (WACOM_DIRECT_DEVICE(field))
2876e5bc8eb1SJason Gerecke 		features->device_type |= WACOM_DEVICETYPE_DIRECT;
28777704ac93SBenjamin Tissoires 
28785ac3d4aeSJason Gerecke 	/* usage tests must precede field tests */
28795ac3d4aeSJason Gerecke 	if (WACOM_BATTERY_USAGE(usage))
28805ac3d4aeSJason Gerecke 		wacom_wac_battery_usage_mapping(hdev, field, usage);
28815ac3d4aeSJason Gerecke 	else if (WACOM_PAD_FIELD(field))
2882354a3298SPing Cheng 		wacom_wac_pad_usage_mapping(hdev, field, usage);
28835922e613SJason Gerecke 	else if (WACOM_PEN_FIELD(field))
2884354a3298SPing Cheng 		wacom_wac_pen_usage_mapping(hdev, field, usage);
28855922e613SJason Gerecke 	else if (WACOM_FINGER_FIELD(field))
2886354a3298SPing Cheng 		wacom_wac_finger_usage_mapping(hdev, field, usage);
28877704ac93SBenjamin Tissoires }
28887704ac93SBenjamin Tissoires 
wacom_wac_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)2889354a3298SPing Cheng void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
28907704ac93SBenjamin Tissoires 		struct hid_usage *usage, __s32 value)
28917704ac93SBenjamin Tissoires {
28927704ac93SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
28937704ac93SBenjamin Tissoires 
28947704ac93SBenjamin Tissoires 	if (wacom->wacom_wac.features.type != HID_GENERIC)
2895354a3298SPing Cheng 		return;
28967704ac93SBenjamin Tissoires 
289760a22186SAaron Armstrong Skomra 	if (value > field->logical_maximum || value < field->logical_minimum)
289860a22186SAaron Armstrong Skomra 		return;
289960a22186SAaron Armstrong Skomra 
29005ac3d4aeSJason Gerecke 	/* usage tests must precede field tests */
29015ac3d4aeSJason Gerecke 	if (WACOM_BATTERY_USAGE(usage))
29025ac3d4aeSJason Gerecke 		wacom_wac_battery_event(hdev, field, usage, value);
2903d6b67568SPing Cheng 	else if (WACOM_PAD_FIELD(field))
2904354a3298SPing Cheng 		wacom_wac_pad_event(hdev, field, usage, value);
29055ac3d4aeSJason Gerecke 	else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
2906354a3298SPing Cheng 		wacom_wac_pen_event(hdev, field, usage, value);
29076f46cf9bSPing Cheng 	else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
2908354a3298SPing Cheng 		wacom_wac_finger_event(hdev, field, usage, value);
29097704ac93SBenjamin Tissoires }
29107704ac93SBenjamin Tissoires 
wacom_report_events(struct hid_device * hdev,struct hid_report * report,int collection_index,int field_index)2911f8b6a747SAaron Armstrong Skomra static void wacom_report_events(struct hid_device *hdev,
2912f8b6a747SAaron Armstrong Skomra 				struct hid_report *report, int collection_index,
2913f8b6a747SAaron Armstrong Skomra 				int field_index)
291406324e0cSJason Gerecke {
291506324e0cSJason Gerecke 	int r;
291606324e0cSJason Gerecke 
2917f8b6a747SAaron Armstrong Skomra 	for (r = field_index; r < report->maxfield; r++) {
291806324e0cSJason Gerecke 		struct hid_field *field;
291906324e0cSJason Gerecke 		unsigned count, n;
292006324e0cSJason Gerecke 
292106324e0cSJason Gerecke 		field = report->field[r];
292206324e0cSJason Gerecke 		count = field->report_count;
292306324e0cSJason Gerecke 
292406324e0cSJason Gerecke 		if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
292506324e0cSJason Gerecke 			continue;
292606324e0cSJason Gerecke 
2927f8b6a747SAaron Armstrong Skomra 		for (n = 0 ; n < count; n++) {
2928f8b6a747SAaron Armstrong Skomra 			if (field->usage[n].collection_index == collection_index)
2929f8b6a747SAaron Armstrong Skomra 				wacom_wac_event(hdev, field, &field->usage[n],
2930f8b6a747SAaron Armstrong Skomra 						field->value[n]);
2931f8b6a747SAaron Armstrong Skomra 			else
2932f8b6a747SAaron Armstrong Skomra 				return;
2933f8b6a747SAaron Armstrong Skomra 		}
293406324e0cSJason Gerecke 	}
293506324e0cSJason Gerecke }
293606324e0cSJason Gerecke 
wacom_wac_collection(struct hid_device * hdev,struct hid_report * report,int collection_index,struct hid_field * field,int field_index)29377ba8fc09SJiri Kosina static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
2938f8b6a747SAaron Armstrong Skomra 			 int collection_index, struct hid_field *field,
2939f8b6a747SAaron Armstrong Skomra 			 int field_index)
29407704ac93SBenjamin Tissoires {
29417704ac93SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
29427704ac93SBenjamin Tissoires 
2943f8b6a747SAaron Armstrong Skomra 	wacom_report_events(hdev, report, collection_index, field_index);
294406324e0cSJason Gerecke 
2945a9ce7856SJason Gerecke 	/*
2946a9ce7856SJason Gerecke 	 * Non-input reports may be sent prior to the device being
2947a9ce7856SJason Gerecke 	 * completely initialized. Since only their events need
2948a9ce7856SJason Gerecke 	 * to be processed, exit after 'wacom_report_events' has
2949a9ce7856SJason Gerecke 	 * been called to prevent potential crashes in the report-
2950a9ce7856SJason Gerecke 	 * processing functions.
2951a9ce7856SJason Gerecke 	 */
2952a9ce7856SJason Gerecke 	if (report->type != HID_INPUT_REPORT)
2953f8b6a747SAaron Armstrong Skomra 		return -1;
29545ac3d4aeSJason Gerecke 
2955d9216d75SJason Gerecke 	if (WACOM_PAD_FIELD(field))
2956d9216d75SJason Gerecke 		return 0;
2957d9216d75SJason Gerecke 	else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
2958c9cfb2acSPing Cheng 		wacom_wac_pen_report(hdev, report);
29596f46cf9bSPing Cheng 	else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
2960c9cfb2acSPing Cheng 		wacom_wac_finger_report(hdev, report);
2961f8b6a747SAaron Armstrong Skomra 
2962f8b6a747SAaron Armstrong Skomra 	return 0;
2963f8b6a747SAaron Armstrong Skomra }
2964f8b6a747SAaron Armstrong Skomra 
wacom_wac_report(struct hid_device * hdev,struct hid_report * report)2965f8b6a747SAaron Armstrong Skomra void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
2966f8b6a747SAaron Armstrong Skomra {
2967f8b6a747SAaron Armstrong Skomra 	struct wacom *wacom = hid_get_drvdata(hdev);
2968f8b6a747SAaron Armstrong Skomra 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
2969f8b6a747SAaron Armstrong Skomra 	struct hid_field *field;
2970f8b6a747SAaron Armstrong Skomra 	bool pad_in_hid_field = false, pen_in_hid_field = false,
2971d4b8efebSAaron Armstrong Skomra 		finger_in_hid_field = false, true_pad = false;
2972f8b6a747SAaron Armstrong Skomra 	int r;
2973f8b6a747SAaron Armstrong Skomra 	int prev_collection = -1;
2974f8b6a747SAaron Armstrong Skomra 
2975f8b6a747SAaron Armstrong Skomra 	if (wacom_wac->features.type != HID_GENERIC)
2976f8b6a747SAaron Armstrong Skomra 		return;
2977f8b6a747SAaron Armstrong Skomra 
2978f8b6a747SAaron Armstrong Skomra 	for (r = 0; r < report->maxfield; r++) {
2979f8b6a747SAaron Armstrong Skomra 		field = report->field[r];
2980f8b6a747SAaron Armstrong Skomra 
2981f8b6a747SAaron Armstrong Skomra 		if (WACOM_PAD_FIELD(field))
2982f8b6a747SAaron Armstrong Skomra 			pad_in_hid_field = true;
2983f8b6a747SAaron Armstrong Skomra 		if (WACOM_PEN_FIELD(field))
2984f8b6a747SAaron Armstrong Skomra 			pen_in_hid_field = true;
2985f8b6a747SAaron Armstrong Skomra 		if (WACOM_FINGER_FIELD(field))
2986f8b6a747SAaron Armstrong Skomra 			finger_in_hid_field = true;
2987d4b8efebSAaron Armstrong Skomra 		if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY)
2988d4b8efebSAaron Armstrong Skomra 			true_pad = true;
2989f8b6a747SAaron Armstrong Skomra 	}
2990f8b6a747SAaron Armstrong Skomra 
2991f8b6a747SAaron Armstrong Skomra 	wacom_wac_battery_pre_report(hdev, report);
2992f8b6a747SAaron Armstrong Skomra 
2993f8b6a747SAaron Armstrong Skomra 	if (pad_in_hid_field && wacom->wacom_wac.pad_input)
2994f8b6a747SAaron Armstrong Skomra 		wacom_wac_pad_pre_report(hdev, report);
2995f8b6a747SAaron Armstrong Skomra 	if (pen_in_hid_field && wacom->wacom_wac.pen_input)
2996f8b6a747SAaron Armstrong Skomra 		wacom_wac_pen_pre_report(hdev, report);
2997f8b6a747SAaron Armstrong Skomra 	if (finger_in_hid_field && wacom->wacom_wac.touch_input)
2998f8b6a747SAaron Armstrong Skomra 		wacom_wac_finger_pre_report(hdev, report);
2999f8b6a747SAaron Armstrong Skomra 
3000f8b6a747SAaron Armstrong Skomra 	for (r = 0; r < report->maxfield; r++) {
3001f8b6a747SAaron Armstrong Skomra 		field = report->field[r];
3002f8b6a747SAaron Armstrong Skomra 
3003f8b6a747SAaron Armstrong Skomra 		if (field->usage[0].collection_index != prev_collection) {
3004f8b6a747SAaron Armstrong Skomra 			if (wacom_wac_collection(hdev, report,
3005f8b6a747SAaron Armstrong Skomra 				field->usage[0].collection_index, field, r) < 0)
3006f8b6a747SAaron Armstrong Skomra 				return;
3007f8b6a747SAaron Armstrong Skomra 			prev_collection = field->usage[0].collection_index;
3008f8b6a747SAaron Armstrong Skomra 		}
3009f8b6a747SAaron Armstrong Skomra 	}
3010f8b6a747SAaron Armstrong Skomra 
3011f8b6a747SAaron Armstrong Skomra 	wacom_wac_battery_report(hdev, report);
3012d4b8efebSAaron Armstrong Skomra 
3013d4b8efebSAaron Armstrong Skomra 	if (true_pad && wacom->wacom_wac.pad_input)
3014d4b8efebSAaron Armstrong Skomra 		wacom_wac_pad_report(hdev, report, field);
30157704ac93SBenjamin Tissoires }
30167704ac93SBenjamin Tissoires 
wacom_bpt_touch(struct wacom_wac * wacom)3017471d1714SBenjamin Tissoires static int wacom_bpt_touch(struct wacom_wac *wacom)
3018471d1714SBenjamin Tissoires {
3019471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
30202a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
3021471d1714SBenjamin Tissoires 	struct input_dev *pad_input = wacom->pad_input;
3022471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
3023471d1714SBenjamin Tissoires 	int i;
3024471d1714SBenjamin Tissoires 
3025471d1714SBenjamin Tissoires 	if (data[0] != 0x02)
3026471d1714SBenjamin Tissoires 	    return 0;
3027471d1714SBenjamin Tissoires 
3028471d1714SBenjamin Tissoires 	for (i = 0; i < 2; i++) {
3029471d1714SBenjamin Tissoires 		int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
30301924e05eSPing Cheng 		bool touch = report_touch_events(wacom)
30311924e05eSPing Cheng 			   && (data[offset + 3] & 0x80);
3032471d1714SBenjamin Tissoires 
3033471d1714SBenjamin Tissoires 		input_mt_slot(input, i);
3034471d1714SBenjamin Tissoires 		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
3035471d1714SBenjamin Tissoires 		if (touch) {
3036471d1714SBenjamin Tissoires 			int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
3037471d1714SBenjamin Tissoires 			int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
3038471d1714SBenjamin Tissoires 			if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
3039471d1714SBenjamin Tissoires 				x <<= 5;
3040471d1714SBenjamin Tissoires 				y <<= 5;
3041471d1714SBenjamin Tissoires 			}
3042471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MT_POSITION_X, x);
3043471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_MT_POSITION_Y, y);
3044471d1714SBenjamin Tissoires 		}
3045471d1714SBenjamin Tissoires 	}
3046471d1714SBenjamin Tissoires 
30479a1c0012SBenjamin Tissoires 	input_mt_sync_frame(input);
3048471d1714SBenjamin Tissoires 
3049471d1714SBenjamin Tissoires 	input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
3050471d1714SBenjamin Tissoires 	input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
3051471d1714SBenjamin Tissoires 	input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
3052471d1714SBenjamin Tissoires 	input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
30537d059ed0SPing Cheng 	wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
3054471d1714SBenjamin Tissoires 
3055471d1714SBenjamin Tissoires 	return 1;
3056471d1714SBenjamin Tissoires }
3057471d1714SBenjamin Tissoires 
wacom_bpt3_touch_msg(struct wacom_wac * wacom,unsigned char * data)30587d059ed0SPing Cheng static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
3059471d1714SBenjamin Tissoires {
3060471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
30612a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
3062471d1714SBenjamin Tissoires 	bool touch = data[1] & 0x80;
3063471d1714SBenjamin Tissoires 	int slot = input_mt_get_slot_by_key(input, data[0]);
3064471d1714SBenjamin Tissoires 
3065471d1714SBenjamin Tissoires 	if (slot < 0)
30667d059ed0SPing Cheng 		return;
3067471d1714SBenjamin Tissoires 
30681924e05eSPing Cheng 	touch = touch && report_touch_events(wacom);
3069471d1714SBenjamin Tissoires 
3070471d1714SBenjamin Tissoires 	input_mt_slot(input, slot);
3071471d1714SBenjamin Tissoires 	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
3072471d1714SBenjamin Tissoires 
3073471d1714SBenjamin Tissoires 	if (touch) {
3074471d1714SBenjamin Tissoires 		int x = (data[2] << 4) | (data[4] >> 4);
3075471d1714SBenjamin Tissoires 		int y = (data[3] << 4) | (data[4] & 0x0f);
3076471d1714SBenjamin Tissoires 		int width, height;
3077471d1714SBenjamin Tissoires 
3078eda01dabSPing Cheng 		if (features->type >= INTUOSPS && features->type <= INTUOSHT2) {
3079471d1714SBenjamin Tissoires 			width  = data[5] * 100;
3080471d1714SBenjamin Tissoires 			height = data[6] * 100;
3081471d1714SBenjamin Tissoires 		} else {
3082471d1714SBenjamin Tissoires 			/*
3083471d1714SBenjamin Tissoires 			 * "a" is a scaled-down area which we assume is
3084471d1714SBenjamin Tissoires 			 * roughly circular and which can be described as:
3085471d1714SBenjamin Tissoires 			 * a=(pi*r^2)/C.
3086471d1714SBenjamin Tissoires 			 */
3087471d1714SBenjamin Tissoires 			int a = data[5];
30885e2aa2edSDmitry Torokhov 			int x_res = input_abs_get_res(input, ABS_MT_POSITION_X);
30895e2aa2edSDmitry Torokhov 			int y_res = input_abs_get_res(input, ABS_MT_POSITION_Y);
3090471d1714SBenjamin Tissoires 			width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
3091471d1714SBenjamin Tissoires 			height = width * y_res / x_res;
3092471d1714SBenjamin Tissoires 		}
3093471d1714SBenjamin Tissoires 
3094471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MT_POSITION_X, x);
3095471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MT_POSITION_Y, y);
3096471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
3097471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
3098471d1714SBenjamin Tissoires 	}
3099471d1714SBenjamin Tissoires }
3100471d1714SBenjamin Tissoires 
wacom_bpt3_button_msg(struct wacom_wac * wacom,unsigned char * data)3101471d1714SBenjamin Tissoires static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
3102471d1714SBenjamin Tissoires {
3103471d1714SBenjamin Tissoires 	struct input_dev *input = wacom->pad_input;
3104471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
3105471d1714SBenjamin Tissoires 
3106eda01dabSPing Cheng 	if (features->type == INTUOSHT || features->type == INTUOSHT2) {
3107471d1714SBenjamin Tissoires 		input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
3108471d1714SBenjamin Tissoires 		input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
3109471d1714SBenjamin Tissoires 	} else {
3110471d1714SBenjamin Tissoires 		input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
3111471d1714SBenjamin Tissoires 		input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
3112471d1714SBenjamin Tissoires 	}
3113471d1714SBenjamin Tissoires 	input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
3114471d1714SBenjamin Tissoires 	input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
3115471d1714SBenjamin Tissoires }
3116471d1714SBenjamin Tissoires 
wacom_bpt3_touch(struct wacom_wac * wacom)3117471d1714SBenjamin Tissoires static int wacom_bpt3_touch(struct wacom_wac *wacom)
3118471d1714SBenjamin Tissoires {
3119471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
3120471d1714SBenjamin Tissoires 	int count = data[1] & 0x07;
3121eda01dabSPing Cheng 	int  touch_changed = 0, i;
3122471d1714SBenjamin Tissoires 
3123471d1714SBenjamin Tissoires 	if (data[0] != 0x02)
3124471d1714SBenjamin Tissoires 	    return 0;
3125471d1714SBenjamin Tissoires 
3126471d1714SBenjamin Tissoires 	/* data has up to 7 fixed sized 8-byte messages starting at data[2] */
3127471d1714SBenjamin Tissoires 	for (i = 0; i < count; i++) {
3128471d1714SBenjamin Tissoires 		int offset = (8 * i) + 2;
3129471d1714SBenjamin Tissoires 		int msg_id = data[offset];
3130471d1714SBenjamin Tissoires 
3131eda01dabSPing Cheng 		if (msg_id >= 2 && msg_id <= 17) {
31327d059ed0SPing Cheng 			wacom_bpt3_touch_msg(wacom, data + offset);
3133eda01dabSPing Cheng 			touch_changed++;
3134eda01dabSPing Cheng 		} else if (msg_id == 128)
3135471d1714SBenjamin Tissoires 			wacom_bpt3_button_msg(wacom, data + offset);
3136471d1714SBenjamin Tissoires 
3137471d1714SBenjamin Tissoires 	}
31382a6cdbddSJason Gerecke 
3139eda01dabSPing Cheng 	/* only update touch if we actually have a touchpad and touch data changed */
314084dfbd7fSBenjamin Tissoires 	if (wacom->touch_input && touch_changed) {
31412a6cdbddSJason Gerecke 		input_mt_sync_frame(wacom->touch_input);
31427d059ed0SPing Cheng 		wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
31432a6cdbddSJason Gerecke 	}
3144471d1714SBenjamin Tissoires 
3145471d1714SBenjamin Tissoires 	return 1;
3146471d1714SBenjamin Tissoires }
3147471d1714SBenjamin Tissoires 
wacom_bpt_pen(struct wacom_wac * wacom)3148471d1714SBenjamin Tissoires static int wacom_bpt_pen(struct wacom_wac *wacom)
3149471d1714SBenjamin Tissoires {
3150471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->features;
31512a6cdbddSJason Gerecke 	struct input_dev *input = wacom->pen_input;
3152471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
31538947b0cfSJason Gerecke 	int x = 0, y = 0, p = 0, d = 0;
31548947b0cfSJason Gerecke 	bool pen = false, btn1 = false, btn2 = false;
31558947b0cfSJason Gerecke 	bool range, prox, rdy;
3156471d1714SBenjamin Tissoires 
31574ca4ec71SJason Gerecke 	if (data[0] != WACOM_REPORT_PENABLED)
3158486b908dSPing Cheng 	    return 0;
3159486b908dSPing Cheng 
31608947b0cfSJason Gerecke 	range = (data[1] & 0x80) == 0x80;
31618947b0cfSJason Gerecke 	prox = (data[1] & 0x40) == 0x40;
31628947b0cfSJason Gerecke 	rdy = (data[1] & 0x20) == 0x20;
3163471d1714SBenjamin Tissoires 
31648947b0cfSJason Gerecke 	wacom->shared->stylus_in_proximity = range;
31658947b0cfSJason Gerecke 	if (delay_pen_events(wacom))
31668947b0cfSJason Gerecke 		return 0;
31678947b0cfSJason Gerecke 
31688947b0cfSJason Gerecke 	if (rdy) {
31698947b0cfSJason Gerecke 		p = le16_to_cpup((__le16 *)&data[6]);
31708947b0cfSJason Gerecke 		pen = data[1] & 0x01;
31718947b0cfSJason Gerecke 		btn1 = data[1] & 0x02;
31728947b0cfSJason Gerecke 		btn2 = data[1] & 0x04;
31738947b0cfSJason Gerecke 	}
31748947b0cfSJason Gerecke 	if (prox) {
31758947b0cfSJason Gerecke 		x = le16_to_cpup((__le16 *)&data[2]);
31768947b0cfSJason Gerecke 		y = le16_to_cpup((__le16 *)&data[4]);
31778947b0cfSJason Gerecke 
3178471d1714SBenjamin Tissoires 		if (data[1] & 0x08) {
3179471d1714SBenjamin Tissoires 			wacom->tool[0] = BTN_TOOL_RUBBER;
3180471d1714SBenjamin Tissoires 			wacom->id[0] = ERASER_DEVICE_ID;
3181471d1714SBenjamin Tissoires 		} else {
3182471d1714SBenjamin Tissoires 			wacom->tool[0] = BTN_TOOL_PEN;
3183471d1714SBenjamin Tissoires 			wacom->id[0] = STYLUS_DEVICE_ID;
3184471d1714SBenjamin Tissoires 		}
31858947b0cfSJason Gerecke 		wacom->reporting_data = true;
3186471d1714SBenjamin Tissoires 	}
31878947b0cfSJason Gerecke 	if (range) {
3188471d1714SBenjamin Tissoires 		/*
3189471d1714SBenjamin Tissoires 		 * Convert distance from out prox to distance from tablet.
3190471d1714SBenjamin Tissoires 		 * distance will be greater than distance_max once
3191471d1714SBenjamin Tissoires 		 * touching and applying pressure; do not report negative
3192471d1714SBenjamin Tissoires 		 * distance.
3193471d1714SBenjamin Tissoires 		 */
3194471d1714SBenjamin Tissoires 		if (data[8] <= features->distance_max)
3195471d1714SBenjamin Tissoires 			d = features->distance_max - data[8];
31960149931eSPing Cheng 	} else {
31970149931eSPing Cheng 		wacom->id[0] = 0;
3198471d1714SBenjamin Tissoires 	}
3199471d1714SBenjamin Tissoires 
32008947b0cfSJason Gerecke 	if (wacom->reporting_data) {
3201471d1714SBenjamin Tissoires 		input_report_key(input, BTN_TOUCH, pen);
3202471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS, btn1);
3203471d1714SBenjamin Tissoires 		input_report_key(input, BTN_STYLUS2, btn2);
3204471d1714SBenjamin Tissoires 
32058947b0cfSJason Gerecke 		if (prox || !range) {
3206471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_X, x);
3207471d1714SBenjamin Tissoires 			input_report_abs(input, ABS_Y, y);
32088947b0cfSJason Gerecke 		}
3209471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_PRESSURE, p);
3210471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_DISTANCE, d);
3211471d1714SBenjamin Tissoires 
32128947b0cfSJason Gerecke 		input_report_key(input, wacom->tool[0], range); /* PEN or RUBBER */
3213471d1714SBenjamin Tissoires 		input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
32148947b0cfSJason Gerecke 	}
32158947b0cfSJason Gerecke 
32168947b0cfSJason Gerecke 	if (!range) {
32178947b0cfSJason Gerecke 		wacom->reporting_data = false;
32188947b0cfSJason Gerecke 	}
3219471d1714SBenjamin Tissoires 
3220471d1714SBenjamin Tissoires 	return 1;
3221471d1714SBenjamin Tissoires }
3222471d1714SBenjamin Tissoires 
wacom_bpt_irq(struct wacom_wac * wacom,size_t len)3223471d1714SBenjamin Tissoires static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
3224471d1714SBenjamin Tissoires {
3225eda01dabSPing Cheng 	struct wacom_features *features = &wacom->features;
3226eda01dabSPing Cheng 
3227eda01dabSPing Cheng 	if ((features->type == INTUOSHT2) &&
3228eda01dabSPing Cheng 	    (features->device_type & WACOM_DEVICETYPE_PEN))
3229eda01dabSPing Cheng 		return wacom_intuos_irq(wacom);
3230eda01dabSPing Cheng 	else if (len == WACOM_PKGLEN_BBTOUCH)
3231471d1714SBenjamin Tissoires 		return wacom_bpt_touch(wacom);
3232471d1714SBenjamin Tissoires 	else if (len == WACOM_PKGLEN_BBTOUCH3)
3233471d1714SBenjamin Tissoires 		return wacom_bpt3_touch(wacom);
3234471d1714SBenjamin Tissoires 	else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN)
3235471d1714SBenjamin Tissoires 		return wacom_bpt_pen(wacom);
3236471d1714SBenjamin Tissoires 
3237471d1714SBenjamin Tissoires 	return 0;
3238471d1714SBenjamin Tissoires }
3239471d1714SBenjamin Tissoires 
wacom_bamboo_pad_pen_event(struct wacom_wac * wacom,unsigned char * data)32408c97a765SBenjamin Tissoires static void wacom_bamboo_pad_pen_event(struct wacom_wac *wacom,
32418c97a765SBenjamin Tissoires 		unsigned char *data)
32428c97a765SBenjamin Tissoires {
32438c97a765SBenjamin Tissoires 	unsigned char prefix;
32448c97a765SBenjamin Tissoires 
32458c97a765SBenjamin Tissoires 	/*
32468c97a765SBenjamin Tissoires 	 * We need to reroute the event from the debug interface to the
32478c97a765SBenjamin Tissoires 	 * pen interface.
32488c97a765SBenjamin Tissoires 	 * We need to add the report ID to the actual pen report, so we
32498c97a765SBenjamin Tissoires 	 * temporary overwrite the first byte to prevent having to kzalloc/kfree
32508c97a765SBenjamin Tissoires 	 * and memcpy the report.
32518c97a765SBenjamin Tissoires 	 */
32528c97a765SBenjamin Tissoires 	prefix = data[0];
32538c97a765SBenjamin Tissoires 	data[0] = WACOM_REPORT_BPAD_PEN;
32548c97a765SBenjamin Tissoires 
32558c97a765SBenjamin Tissoires 	/*
32568c97a765SBenjamin Tissoires 	 * actually reroute the event.
32578c97a765SBenjamin Tissoires 	 * No need to check if wacom->shared->pen is valid, hid_input_report()
32588c97a765SBenjamin Tissoires 	 * will check for us.
32598c97a765SBenjamin Tissoires 	 */
32608c97a765SBenjamin Tissoires 	hid_input_report(wacom->shared->pen, HID_INPUT_REPORT, data,
32618c97a765SBenjamin Tissoires 			 WACOM_PKGLEN_PENABLED, 1);
32628c97a765SBenjamin Tissoires 
32638c97a765SBenjamin Tissoires 	data[0] = prefix;
32648c97a765SBenjamin Tissoires }
32658c97a765SBenjamin Tissoires 
wacom_bamboo_pad_touch_event(struct wacom_wac * wacom,unsigned char * data)32668c97a765SBenjamin Tissoires static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
32678c97a765SBenjamin Tissoires 		unsigned char *data)
32688c97a765SBenjamin Tissoires {
32692a6cdbddSJason Gerecke 	struct input_dev *input = wacom->touch_input;
32708c97a765SBenjamin Tissoires 	unsigned char *finger_data, prefix;
32718c97a765SBenjamin Tissoires 	unsigned id;
32728c97a765SBenjamin Tissoires 	int x, y;
32738c97a765SBenjamin Tissoires 	bool valid;
32748c97a765SBenjamin Tissoires 
32758c97a765SBenjamin Tissoires 	prefix = data[0];
32768c97a765SBenjamin Tissoires 
32778c97a765SBenjamin Tissoires 	for (id = 0; id < wacom->features.touch_max; id++) {
32788c97a765SBenjamin Tissoires 		valid = !!(prefix & BIT(id)) &&
32791924e05eSPing Cheng 			report_touch_events(wacom);
32808c97a765SBenjamin Tissoires 
32818c97a765SBenjamin Tissoires 		input_mt_slot(input, id);
32828c97a765SBenjamin Tissoires 		input_mt_report_slot_state(input, MT_TOOL_FINGER, valid);
32838c97a765SBenjamin Tissoires 
32848c97a765SBenjamin Tissoires 		if (!valid)
32858c97a765SBenjamin Tissoires 			continue;
32868c97a765SBenjamin Tissoires 
32878c97a765SBenjamin Tissoires 		finger_data = data + 1 + id * 3;
32888c97a765SBenjamin Tissoires 		x = finger_data[0] | ((finger_data[1] & 0x0f) << 8);
32898c97a765SBenjamin Tissoires 		y = (finger_data[2] << 4) | (finger_data[1] >> 4);
32908c97a765SBenjamin Tissoires 
32918c97a765SBenjamin Tissoires 		input_report_abs(input, ABS_MT_POSITION_X, x);
32928c97a765SBenjamin Tissoires 		input_report_abs(input, ABS_MT_POSITION_Y, y);
32938c97a765SBenjamin Tissoires 	}
32948c97a765SBenjamin Tissoires 
32958c97a765SBenjamin Tissoires 	input_mt_sync_frame(input);
32968c97a765SBenjamin Tissoires 
32978c97a765SBenjamin Tissoires 	input_report_key(input, BTN_LEFT, prefix & 0x40);
32988c97a765SBenjamin Tissoires 	input_report_key(input, BTN_RIGHT, prefix & 0x80);
32998c97a765SBenjamin Tissoires 
33008c97a765SBenjamin Tissoires 	/* keep touch state for pen event */
33011924e05eSPing Cheng 	wacom->shared->touch_down = !!prefix && report_touch_events(wacom);
33028c97a765SBenjamin Tissoires 
33038c97a765SBenjamin Tissoires 	return 1;
33048c97a765SBenjamin Tissoires }
33058c97a765SBenjamin Tissoires 
wacom_bamboo_pad_irq(struct wacom_wac * wacom,size_t len)33068c97a765SBenjamin Tissoires static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)
33078c97a765SBenjamin Tissoires {
33088c97a765SBenjamin Tissoires 	unsigned char *data = wacom->data;
33098c97a765SBenjamin Tissoires 
33108c97a765SBenjamin Tissoires 	if (!((len == WACOM_PKGLEN_BPAD_TOUCH) ||
33118c97a765SBenjamin Tissoires 	      (len == WACOM_PKGLEN_BPAD_TOUCH_USB)) ||
33128c97a765SBenjamin Tissoires 	    (data[0] != WACOM_REPORT_BPAD_TOUCH))
33138c97a765SBenjamin Tissoires 		return 0;
33148c97a765SBenjamin Tissoires 
33158c97a765SBenjamin Tissoires 	if (data[1] & 0x01)
33168c97a765SBenjamin Tissoires 		wacom_bamboo_pad_pen_event(wacom, &data[1]);
33178c97a765SBenjamin Tissoires 
33188c97a765SBenjamin Tissoires 	if (data[1] & 0x02)
33198c97a765SBenjamin Tissoires 		return wacom_bamboo_pad_touch_event(wacom, &data[9]);
33208c97a765SBenjamin Tissoires 
33218c97a765SBenjamin Tissoires 	return 0;
33228c97a765SBenjamin Tissoires }
33238c97a765SBenjamin Tissoires 
wacom_wireless_irq(struct wacom_wac * wacom,size_t len)3324471d1714SBenjamin Tissoires static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
3325471d1714SBenjamin Tissoires {
3326471d1714SBenjamin Tissoires 	unsigned char *data = wacom->data;
3327471d1714SBenjamin Tissoires 	int connected;
3328471d1714SBenjamin Tissoires 
3329471d1714SBenjamin Tissoires 	if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL)
3330471d1714SBenjamin Tissoires 		return 0;
3331471d1714SBenjamin Tissoires 
3332471d1714SBenjamin Tissoires 	connected = data[1] & 0x01;
3333471d1714SBenjamin Tissoires 	if (connected) {
3334b0882cb7SJason Gerecke 		int pid, battery, charging;
3335471d1714SBenjamin Tissoires 
3336eda01dabSPing Cheng 		if ((wacom->shared->type == INTUOSHT ||
3337eda01dabSPing Cheng 		    wacom->shared->type == INTUOSHT2) &&
333844b96838SPing Cheng 		    wacom->shared->touch_input &&
3339471d1714SBenjamin Tissoires 		    wacom->shared->touch_max) {
3340471d1714SBenjamin Tissoires 			input_report_switch(wacom->shared->touch_input,
3341471d1714SBenjamin Tissoires 					SW_MUTE_DEVICE, data[5] & 0x40);
3342471d1714SBenjamin Tissoires 			input_sync(wacom->shared->touch_input);
3343471d1714SBenjamin Tissoires 		}
3344471d1714SBenjamin Tissoires 
3345471d1714SBenjamin Tissoires 		pid = get_unaligned_be16(&data[6]);
3346ac8d1010SBenjamin Tissoires 		battery = (data[5] & 0x3f) * 100 / 31;
3347b0882cb7SJason Gerecke 		charging = !!(data[5] & 0x80);
3348471d1714SBenjamin Tissoires 		if (wacom->pid != pid) {
3349471d1714SBenjamin Tissoires 			wacom->pid = pid;
3350d17d1f17SBenjamin Tissoires 			wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
3351471d1714SBenjamin Tissoires 		}
3352ac8d1010SBenjamin Tissoires 
335316e45989SJason Gerecke 		wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
335416e45989SJason Gerecke 				     battery, charging, 1, 0);
3355953f2c5fSJason Gerecke 
3356471d1714SBenjamin Tissoires 	} else if (wacom->pid != 0) {
3357471d1714SBenjamin Tissoires 		/* disconnected while previously connected */
3358471d1714SBenjamin Tissoires 		wacom->pid = 0;
3359d17d1f17SBenjamin Tissoires 		wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
336016e45989SJason Gerecke 		wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
3361471d1714SBenjamin Tissoires 	}
3362471d1714SBenjamin Tissoires 
3363471d1714SBenjamin Tissoires 	return 0;
3364471d1714SBenjamin Tissoires }
3365471d1714SBenjamin Tissoires 
wacom_status_irq(struct wacom_wac * wacom_wac,size_t len)33664ca4ec71SJason Gerecke static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
33674ca4ec71SJason Gerecke {
33688f93b0b2SJason Gerecke 	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
33694ca4ec71SJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
33704ca4ec71SJason Gerecke 	unsigned char *data = wacom_wac->data;
33714ca4ec71SJason Gerecke 
33724ca4ec71SJason Gerecke 	if (data[0] != WACOM_REPORT_USB)
33734ca4ec71SJason Gerecke 		return 0;
33744ca4ec71SJason Gerecke 
3375eda01dabSPing Cheng 	if ((features->type == INTUOSHT ||
3376eda01dabSPing Cheng 	    features->type == INTUOSHT2) &&
33774ca4ec71SJason Gerecke 	    wacom_wac->shared->touch_input &&
33784ca4ec71SJason Gerecke 	    features->touch_max) {
33794ca4ec71SJason Gerecke 		input_report_switch(wacom_wac->shared->touch_input,
33804ca4ec71SJason Gerecke 				    SW_MUTE_DEVICE, data[8] & 0x40);
33814ca4ec71SJason Gerecke 		input_sync(wacom_wac->shared->touch_input);
33824ca4ec71SJason Gerecke 	}
33838f93b0b2SJason Gerecke 
33848f93b0b2SJason Gerecke 	if (data[9] & 0x02) { /* wireless module is attached */
33858f93b0b2SJason Gerecke 		int battery = (data[8] & 0x3f) * 100 / 31;
3386b0882cb7SJason Gerecke 		bool charging = !!(data[8] & 0x80);
33878f93b0b2SJason Gerecke 
33887fc68653SJason Gerecke 		features->quirks |= WACOM_QUIRK_BATTERY;
338916e45989SJason Gerecke 		wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
339016e45989SJason Gerecke 				     battery, charging, battery || charging, 1);
33918f93b0b2SJason Gerecke 	}
33928f93b0b2SJason Gerecke 	else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
339359d69bc8SBenjamin Tissoires 		 wacom->battery.battery) {
33948f93b0b2SJason Gerecke 		features->quirks &= ~WACOM_QUIRK_BATTERY;
339516e45989SJason Gerecke 		wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
33968f93b0b2SJason Gerecke 	}
33974ca4ec71SJason Gerecke 	return 0;
33984ca4ec71SJason Gerecke }
33994ca4ec71SJason Gerecke 
wacom_wac_irq(struct wacom_wac * wacom_wac,size_t len)3400471d1714SBenjamin Tissoires void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
3401471d1714SBenjamin Tissoires {
3402471d1714SBenjamin Tissoires 	bool sync;
3403471d1714SBenjamin Tissoires 
3404471d1714SBenjamin Tissoires 	switch (wacom_wac->features.type) {
3405471d1714SBenjamin Tissoires 	case PENPARTNER:
3406471d1714SBenjamin Tissoires 		sync = wacom_penpartner_irq(wacom_wac);
3407471d1714SBenjamin Tissoires 		break;
3408471d1714SBenjamin Tissoires 
3409471d1714SBenjamin Tissoires 	case PL:
3410471d1714SBenjamin Tissoires 		sync = wacom_pl_irq(wacom_wac);
3411471d1714SBenjamin Tissoires 		break;
3412471d1714SBenjamin Tissoires 
3413471d1714SBenjamin Tissoires 	case WACOM_G4:
3414471d1714SBenjamin Tissoires 	case GRAPHIRE:
3415387142bbSBenjamin Tissoires 	case GRAPHIRE_BT:
3416471d1714SBenjamin Tissoires 	case WACOM_MO:
3417471d1714SBenjamin Tissoires 		sync = wacom_graphire_irq(wacom_wac);
3418471d1714SBenjamin Tissoires 		break;
3419471d1714SBenjamin Tissoires 
3420471d1714SBenjamin Tissoires 	case PTU:
3421471d1714SBenjamin Tissoires 		sync = wacom_ptu_irq(wacom_wac);
3422471d1714SBenjamin Tissoires 		break;
3423471d1714SBenjamin Tissoires 
3424471d1714SBenjamin Tissoires 	case DTU:
3425471d1714SBenjamin Tissoires 		sync = wacom_dtu_irq(wacom_wac);
3426471d1714SBenjamin Tissoires 		break;
3427471d1714SBenjamin Tissoires 
3428471d1714SBenjamin Tissoires 	case DTUS:
3429fff00bf8SPing Cheng 	case DTUSX:
3430471d1714SBenjamin Tissoires 		sync = wacom_dtus_irq(wacom_wac);
3431471d1714SBenjamin Tissoires 		break;
3432471d1714SBenjamin Tissoires 
3433471d1714SBenjamin Tissoires 	case INTUOS:
3434471d1714SBenjamin Tissoires 	case INTUOS3S:
3435471d1714SBenjamin Tissoires 	case INTUOS3:
3436471d1714SBenjamin Tissoires 	case INTUOS3L:
3437471d1714SBenjamin Tissoires 	case INTUOS4S:
3438471d1714SBenjamin Tissoires 	case INTUOS4:
3439471d1714SBenjamin Tissoires 	case INTUOS4L:
3440471d1714SBenjamin Tissoires 	case CINTIQ:
3441471d1714SBenjamin Tissoires 	case WACOM_BEE:
3442471d1714SBenjamin Tissoires 	case WACOM_13HD:
3443471d1714SBenjamin Tissoires 	case WACOM_21UX2:
3444471d1714SBenjamin Tissoires 	case WACOM_22HD:
3445471d1714SBenjamin Tissoires 	case WACOM_24HD:
3446500d4160SPing Cheng 	case WACOM_27QHD:
3447471d1714SBenjamin Tissoires 	case DTK:
3448471d1714SBenjamin Tissoires 	case CINTIQ_HYBRID:
3449f7acb55cSJason Gerecke 	case CINTIQ_COMPANION_2:
3450471d1714SBenjamin Tissoires 		sync = wacom_intuos_irq(wacom_wac);
3451471d1714SBenjamin Tissoires 		break;
3452471d1714SBenjamin Tissoires 
345381af7e61SBenjamin Tissoires 	case INTUOS4WL:
345481af7e61SBenjamin Tissoires 		sync = wacom_intuos_bt_irq(wacom_wac, len);
345581af7e61SBenjamin Tissoires 		break;
345681af7e61SBenjamin Tissoires 
3457471d1714SBenjamin Tissoires 	case WACOM_24HDT:
3458500d4160SPing Cheng 	case WACOM_27QHDT:
3459471d1714SBenjamin Tissoires 		sync = wacom_24hdt_irq(wacom_wac);
3460471d1714SBenjamin Tissoires 		break;
3461471d1714SBenjamin Tissoires 
3462471d1714SBenjamin Tissoires 	case INTUOS5S:
3463471d1714SBenjamin Tissoires 	case INTUOS5:
3464471d1714SBenjamin Tissoires 	case INTUOS5L:
3465471d1714SBenjamin Tissoires 	case INTUOSPS:
3466471d1714SBenjamin Tissoires 	case INTUOSPM:
3467471d1714SBenjamin Tissoires 	case INTUOSPL:
3468471d1714SBenjamin Tissoires 		if (len == WACOM_PKGLEN_BBTOUCH3)
3469471d1714SBenjamin Tissoires 			sync = wacom_bpt3_touch(wacom_wac);
34702d13a438SJason Gerecke 		else if (wacom_wac->data[0] == WACOM_REPORT_USB)
34712d13a438SJason Gerecke 			sync = wacom_status_irq(wacom_wac, len);
3472471d1714SBenjamin Tissoires 		else
3473471d1714SBenjamin Tissoires 			sync = wacom_intuos_irq(wacom_wac);
3474471d1714SBenjamin Tissoires 		break;
3475471d1714SBenjamin Tissoires 
34764922cd26SJason Gerecke 	case INTUOSP2_BT:
3477912c6aa6SAaron Armstrong Skomra 	case INTUOSP2S_BT:
347887046b6cSAaron Armstrong Skomra 	case INTUOSHT3_BT:
34794922cd26SJason Gerecke 		sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
34804922cd26SJason Gerecke 		break;
34814922cd26SJason Gerecke 
3482471d1714SBenjamin Tissoires 	case TABLETPC:
3483471d1714SBenjamin Tissoires 	case TABLETPCE:
3484471d1714SBenjamin Tissoires 	case TABLETPC2FG:
3485471d1714SBenjamin Tissoires 	case MTSCREEN:
3486471d1714SBenjamin Tissoires 	case MTTPC:
3487471d1714SBenjamin Tissoires 	case MTTPC_B:
3488471d1714SBenjamin Tissoires 		sync = wacom_tpc_irq(wacom_wac, len);
3489471d1714SBenjamin Tissoires 		break;
3490471d1714SBenjamin Tissoires 
3491471d1714SBenjamin Tissoires 	case BAMBOO_PT:
34923b164a00SPing Cheng 	case BAMBOO_PEN:
34933b164a00SPing Cheng 	case BAMBOO_TOUCH:
3494471d1714SBenjamin Tissoires 	case INTUOSHT:
3495eda01dabSPing Cheng 	case INTUOSHT2:
34964ca4ec71SJason Gerecke 		if (wacom_wac->data[0] == WACOM_REPORT_USB)
34974ca4ec71SJason Gerecke 			sync = wacom_status_irq(wacom_wac, len);
34984ca4ec71SJason Gerecke 		else
3499471d1714SBenjamin Tissoires 			sync = wacom_bpt_irq(wacom_wac, len);
3500471d1714SBenjamin Tissoires 		break;
3501471d1714SBenjamin Tissoires 
35028c97a765SBenjamin Tissoires 	case BAMBOO_PAD:
35038c97a765SBenjamin Tissoires 		sync = wacom_bamboo_pad_irq(wacom_wac, len);
35048c97a765SBenjamin Tissoires 		break;
35058c97a765SBenjamin Tissoires 
3506471d1714SBenjamin Tissoires 	case WIRELESS:
3507471d1714SBenjamin Tissoires 		sync = wacom_wireless_irq(wacom_wac, len);
3508471d1714SBenjamin Tissoires 		break;
3509471d1714SBenjamin Tissoires 
351072b236d6SAaron Skomra 	case REMOTE:
3511e6f2813aSBenjamin Tissoires 		sync = false;
351272b236d6SAaron Skomra 		if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
3513e6f2813aSBenjamin Tissoires 			wacom_remote_status_irq(wacom_wac, len);
351472b236d6SAaron Skomra 		else
351572b236d6SAaron Skomra 			sync = wacom_remote_irq(wacom_wac, len);
351672b236d6SAaron Skomra 		break;
351772b236d6SAaron Skomra 
3518471d1714SBenjamin Tissoires 	default:
3519471d1714SBenjamin Tissoires 		sync = false;
3520471d1714SBenjamin Tissoires 		break;
3521471d1714SBenjamin Tissoires 	}
3522471d1714SBenjamin Tissoires 
3523471d1714SBenjamin Tissoires 	if (sync) {
35242a6cdbddSJason Gerecke 		if (wacom_wac->pen_input)
35252a6cdbddSJason Gerecke 			input_sync(wacom_wac->pen_input);
35262a6cdbddSJason Gerecke 		if (wacom_wac->touch_input)
35272a6cdbddSJason Gerecke 			input_sync(wacom_wac->touch_input);
3528471d1714SBenjamin Tissoires 		if (wacom_wac->pad_input)
3529471d1714SBenjamin Tissoires 			input_sync(wacom_wac->pad_input);
3530471d1714SBenjamin Tissoires 	}
3531471d1714SBenjamin Tissoires }
3532471d1714SBenjamin Tissoires 
wacom_setup_basic_pro_pen(struct wacom_wac * wacom_wac)3533eda01dabSPing Cheng static void wacom_setup_basic_pro_pen(struct wacom_wac *wacom_wac)
3534471d1714SBenjamin Tissoires {
35352a6cdbddSJason Gerecke 	struct input_dev *input_dev = wacom_wac->pen_input;
3536471d1714SBenjamin Tissoires 
3537471d1714SBenjamin Tissoires 	input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
3538471d1714SBenjamin Tissoires 
3539471d1714SBenjamin Tissoires 	__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3540471d1714SBenjamin Tissoires 	__set_bit(BTN_STYLUS, input_dev->keybit);
3541471d1714SBenjamin Tissoires 	__set_bit(BTN_STYLUS2, input_dev->keybit);
3542471d1714SBenjamin Tissoires 
3543471d1714SBenjamin Tissoires 	input_set_abs_params(input_dev, ABS_DISTANCE,
3544bef7e200SJason Gerecke 			     0, wacom_wac->features.distance_max, wacom_wac->features.distance_fuzz, 0);
3545eda01dabSPing Cheng }
3546eda01dabSPing Cheng 
wacom_setup_cintiq(struct wacom_wac * wacom_wac)3547eda01dabSPing Cheng static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
3548eda01dabSPing Cheng {
3549eda01dabSPing Cheng 	struct input_dev *input_dev = wacom_wac->pen_input;
3550bef7e200SJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
3551eda01dabSPing Cheng 
3552eda01dabSPing Cheng 	wacom_setup_basic_pro_pen(wacom_wac);
3553eda01dabSPing Cheng 
3554eda01dabSPing Cheng 	__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3555eda01dabSPing Cheng 	__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
3556eda01dabSPing Cheng 	__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
3557eda01dabSPing Cheng 	__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
3558eda01dabSPing Cheng 
3559471d1714SBenjamin Tissoires 	input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
3560bef7e200SJason Gerecke 	input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, features->tilt_fuzz, 0);
356126fe4124SJason Gerecke 	input_abs_set_res(input_dev, ABS_TILT_X, 57);
3562bef7e200SJason Gerecke 	input_set_abs_params(input_dev, ABS_TILT_Y, -64, 63, features->tilt_fuzz, 0);
356326fe4124SJason Gerecke 	input_abs_set_res(input_dev, ABS_TILT_Y, 57);
3564471d1714SBenjamin Tissoires }
3565471d1714SBenjamin Tissoires 
wacom_setup_intuos(struct wacom_wac * wacom_wac)3566471d1714SBenjamin Tissoires static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
3567471d1714SBenjamin Tissoires {
35682a6cdbddSJason Gerecke 	struct input_dev *input_dev = wacom_wac->pen_input;
3569471d1714SBenjamin Tissoires 
3570471d1714SBenjamin Tissoires 	input_set_capability(input_dev, EV_REL, REL_WHEEL);
3571471d1714SBenjamin Tissoires 
3572471d1714SBenjamin Tissoires 	wacom_setup_cintiq(wacom_wac);
3573471d1714SBenjamin Tissoires 
3574471d1714SBenjamin Tissoires 	__set_bit(BTN_LEFT, input_dev->keybit);
3575471d1714SBenjamin Tissoires 	__set_bit(BTN_RIGHT, input_dev->keybit);
3576471d1714SBenjamin Tissoires 	__set_bit(BTN_MIDDLE, input_dev->keybit);
3577471d1714SBenjamin Tissoires 	__set_bit(BTN_SIDE, input_dev->keybit);
3578471d1714SBenjamin Tissoires 	__set_bit(BTN_EXTRA, input_dev->keybit);
3579471d1714SBenjamin Tissoires 	__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
3580471d1714SBenjamin Tissoires 	__set_bit(BTN_TOOL_LENS, input_dev->keybit);
3581471d1714SBenjamin Tissoires 
3582471d1714SBenjamin Tissoires 	input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
358326fe4124SJason Gerecke 	input_abs_set_res(input_dev, ABS_RZ, 287);
3584471d1714SBenjamin Tissoires 	input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
3585471d1714SBenjamin Tissoires }
3586471d1714SBenjamin Tissoires 
wacom_setup_device_quirks(struct wacom * wacom)358742f4f272SPing Cheng void wacom_setup_device_quirks(struct wacom *wacom)
3588471d1714SBenjamin Tissoires {
358911db8173SJason Gerecke 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
359042f4f272SPing Cheng 	struct wacom_features *features = &wacom->wacom_wac.features;
3591471d1714SBenjamin Tissoires 
3592862cf553SJason Gerecke 	/* The pen and pad share the same interface on most devices */
3593862cf553SJason Gerecke 	if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
35943b164a00SPing Cheng 	    features->type == DTUS ||
35953b164a00SPing Cheng 	    (features->type >= INTUOS3S && features->type <= WACOM_MO)) {
3596862cf553SJason Gerecke 		if (features->device_type & WACOM_DEVICETYPE_PEN)
3597862cf553SJason Gerecke 			features->device_type |= WACOM_DEVICETYPE_PAD;
3598862cf553SJason Gerecke 	}
3599471d1714SBenjamin Tissoires 
3600471d1714SBenjamin Tissoires 	/* touch device found but size is not defined. use default */
3601aa86b18cSJason Gerecke 	if (features->device_type & WACOM_DEVICETYPE_TOUCH && !features->x_max) {
3602471d1714SBenjamin Tissoires 		features->x_max = 1023;
3603471d1714SBenjamin Tissoires 		features->y_max = 1023;
3604471d1714SBenjamin Tissoires 	}
3605471d1714SBenjamin Tissoires 
360642f4f272SPing Cheng 	/*
360742f4f272SPing Cheng 	 * Intuos5/Pro and Bamboo 3rd gen have no useful data about its
360842f4f272SPing Cheng 	 * touch interface in its HID descriptor. If this is the touch
360942f4f272SPing Cheng 	 * interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the
361042f4f272SPing Cheng 	 * tablet values.
361142f4f272SPing Cheng 	 */
36123b164a00SPing Cheng 	if ((features->type >= INTUOS5S && features->type <= INTUOSPL) ||
36133b164a00SPing Cheng 		(features->type >= INTUOSHT && features->type <= BAMBOO_PT)) {
361442f4f272SPing Cheng 		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
3615862cf553SJason Gerecke 			if (features->touch_max)
3616aa86b18cSJason Gerecke 				features->device_type |= WACOM_DEVICETYPE_TOUCH;
3617a3088abcSJiri Kosina 			if (features->type >= INTUOSHT && features->type <= BAMBOO_PT)
3618862cf553SJason Gerecke 				features->device_type |= WACOM_DEVICETYPE_PAD;
361942f4f272SPing Cheng 
36203b8d5735SJason Gerecke 			if (features->type == INTUOSHT2) {
36213b8d5735SJason Gerecke 				features->x_max = features->x_max / 10;
36223b8d5735SJason Gerecke 				features->y_max = features->y_max / 10;
36233b8d5735SJason Gerecke 			}
36243b8d5735SJason Gerecke 			else {
362542f4f272SPing Cheng 				features->x_max = 4096;
362642f4f272SPing Cheng 				features->y_max = 4096;
362742f4f272SPing Cheng 			}
36283b8d5735SJason Gerecke 		}
36299633920eSJason Gerecke 		else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) {
36309633920eSJason Gerecke 			features->device_type |= WACOM_DEVICETYPE_PAD;
36319633920eSJason Gerecke 		}
363242f4f272SPing Cheng 	}
363342f4f272SPing Cheng 
363442f4f272SPing Cheng 	/*
3635580549efSBenjamin Tissoires 	 * Hack for the Bamboo One:
3636580549efSBenjamin Tissoires 	 * the device presents a PAD/Touch interface as most Bamboos and even
3637580549efSBenjamin Tissoires 	 * sends ghosts PAD data on it. However, later, we must disable this
3638580549efSBenjamin Tissoires 	 * ghost interface, and we can not detect it unless we set it here
3639580549efSBenjamin Tissoires 	 * to WACOM_DEVICETYPE_PAD or WACOM_DEVICETYPE_TOUCH.
3640580549efSBenjamin Tissoires 	 */
3641580549efSBenjamin Tissoires 	if (features->type == BAMBOO_PEN &&
3642580549efSBenjamin Tissoires 	    features->pktlen == WACOM_PKGLEN_BBTOUCH3)
3643580549efSBenjamin Tissoires 		features->device_type |= WACOM_DEVICETYPE_PAD;
3644580549efSBenjamin Tissoires 
3645580549efSBenjamin Tissoires 	/*
3646042628abSJason Gerecke 	 * Raw Wacom-mode pen and touch events both come from interface
3647042628abSJason Gerecke 	 * 0, whose HID descriptor has an application usage of 0xFF0D
36488de82280SJason Gerecke 	 * (i.e., WACOM_HID_WD_DIGITIZER). We route pen packets back
3649042628abSJason Gerecke 	 * out through the HID_GENERIC device created for interface 1,
365070caee0aSBenjamin Tissoires 	 * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH.
365142f4f272SPing Cheng 	 */
365242f4f272SPing Cheng 	if (features->type == BAMBOO_PAD)
365370caee0aSBenjamin Tissoires 		features->device_type = WACOM_DEVICETYPE_TOUCH;
365442f4f272SPing Cheng 
365572b236d6SAaron Skomra 	if (features->type == REMOTE)
365672b236d6SAaron Skomra 		features->device_type = WACOM_DEVICETYPE_PAD;
365742f4f272SPing Cheng 
3658912c6aa6SAaron Armstrong Skomra 	if (features->type == INTUOSP2_BT ||
3659912c6aa6SAaron Armstrong Skomra 	    features->type == INTUOSP2S_BT) {
36604922cd26SJason Gerecke 		features->device_type |= WACOM_DEVICETYPE_PEN |
36614922cd26SJason Gerecke 					 WACOM_DEVICETYPE_PAD |
36624922cd26SJason Gerecke 					 WACOM_DEVICETYPE_TOUCH;
36634922cd26SJason Gerecke 		features->quirks |= WACOM_QUIRK_BATTERY;
36644922cd26SJason Gerecke 	}
36654922cd26SJason Gerecke 
366687046b6cSAaron Armstrong Skomra 	if (features->type == INTUOSHT3_BT) {
366787046b6cSAaron Armstrong Skomra 		features->device_type |= WACOM_DEVICETYPE_PEN |
366887046b6cSAaron Armstrong Skomra 					 WACOM_DEVICETYPE_PAD;
366987046b6cSAaron Armstrong Skomra 		features->quirks |= WACOM_QUIRK_BATTERY;
367087046b6cSAaron Armstrong Skomra 	}
367187046b6cSAaron Armstrong Skomra 
3672e5bc8eb1SJason Gerecke 	switch (features->type) {
3673e5bc8eb1SJason Gerecke 	case PL:
3674e5bc8eb1SJason Gerecke 	case DTU:
3675e5bc8eb1SJason Gerecke 	case DTUS:
3676e5bc8eb1SJason Gerecke 	case DTUSX:
3677e5bc8eb1SJason Gerecke 	case WACOM_21UX2:
3678e5bc8eb1SJason Gerecke 	case WACOM_22HD:
3679e5bc8eb1SJason Gerecke 	case DTK:
3680e5bc8eb1SJason Gerecke 	case WACOM_24HD:
3681e5bc8eb1SJason Gerecke 	case WACOM_27QHD:
3682e5bc8eb1SJason Gerecke 	case CINTIQ_HYBRID:
3683e5bc8eb1SJason Gerecke 	case CINTIQ_COMPANION_2:
3684e5bc8eb1SJason Gerecke 	case CINTIQ:
3685e5bc8eb1SJason Gerecke 	case WACOM_BEE:
3686e5bc8eb1SJason Gerecke 	case WACOM_13HD:
3687e5bc8eb1SJason Gerecke 	case WACOM_24HDT:
3688e5bc8eb1SJason Gerecke 	case WACOM_27QHDT:
3689e5bc8eb1SJason Gerecke 	case TABLETPC:
3690e5bc8eb1SJason Gerecke 	case TABLETPCE:
3691e5bc8eb1SJason Gerecke 	case TABLETPC2FG:
3692e5bc8eb1SJason Gerecke 	case MTSCREEN:
3693e5bc8eb1SJason Gerecke 	case MTTPC:
3694e5bc8eb1SJason Gerecke 	case MTTPC_B:
3695e5bc8eb1SJason Gerecke 		features->device_type |= WACOM_DEVICETYPE_DIRECT;
3696e5bc8eb1SJason Gerecke 		break;
3697e5bc8eb1SJason Gerecke 	}
3698e5bc8eb1SJason Gerecke 
369942f4f272SPing Cheng 	if (wacom->hdev->bus == BUS_BLUETOOTH)
370042f4f272SPing Cheng 		features->quirks |= WACOM_QUIRK_BATTERY;
370142f4f272SPing Cheng 
3702471d1714SBenjamin Tissoires 	/* quirk for bamboo touch with 2 low res touches */
3703be853fd1SJason Gerecke 	if ((features->type == BAMBOO_PT || features->type == BAMBOO_TOUCH) &&
3704471d1714SBenjamin Tissoires 	    features->pktlen == WACOM_PKGLEN_BBTOUCH) {
3705471d1714SBenjamin Tissoires 		features->x_max <<= 5;
3706471d1714SBenjamin Tissoires 		features->y_max <<= 5;
3707471d1714SBenjamin Tissoires 		features->x_fuzz <<= 5;
3708471d1714SBenjamin Tissoires 		features->y_fuzz <<= 5;
3709471d1714SBenjamin Tissoires 		features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
3710471d1714SBenjamin Tissoires 	}
3711471d1714SBenjamin Tissoires 
3712471d1714SBenjamin Tissoires 	if (features->type == WIRELESS) {
3713ccad85ccSJason Gerecke 		if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) {
3714ac8d1010SBenjamin Tissoires 			features->quirks |= WACOM_QUIRK_BATTERY;
3715ac8d1010SBenjamin Tissoires 		}
3716471d1714SBenjamin Tissoires 	}
37177c35dc3cSBenjamin Tissoires 
37187c35dc3cSBenjamin Tissoires 	if (features->type == REMOTE)
37197c35dc3cSBenjamin Tissoires 		features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
372011db8173SJason Gerecke 
372111db8173SJason Gerecke 	/* HID descriptor for DTK-2451 / DTH-2452 claims to report lots
372211db8173SJason Gerecke 	 * of things it shouldn't. Lets fix up the damage...
372311db8173SJason Gerecke 	 */
372411db8173SJason Gerecke 	if (wacom->hdev->product == 0x382 || wacom->hdev->product == 0x37d) {
372511db8173SJason Gerecke 		features->quirks &= ~WACOM_QUIRK_TOOLSERIAL;
372611db8173SJason Gerecke 		__clear_bit(BTN_TOOL_BRUSH, wacom_wac->pen_input->keybit);
372711db8173SJason Gerecke 		__clear_bit(BTN_TOOL_PENCIL, wacom_wac->pen_input->keybit);
372811db8173SJason Gerecke 		__clear_bit(BTN_TOOL_AIRBRUSH, wacom_wac->pen_input->keybit);
372911db8173SJason Gerecke 		__clear_bit(ABS_Z, wacom_wac->pen_input->absbit);
373011db8173SJason Gerecke 		__clear_bit(ABS_DISTANCE, wacom_wac->pen_input->absbit);
373111db8173SJason Gerecke 		__clear_bit(ABS_TILT_X, wacom_wac->pen_input->absbit);
373211db8173SJason Gerecke 		__clear_bit(ABS_TILT_Y, wacom_wac->pen_input->absbit);
373311db8173SJason Gerecke 		__clear_bit(ABS_WHEEL, wacom_wac->pen_input->absbit);
373411db8173SJason Gerecke 		__clear_bit(ABS_MISC, wacom_wac->pen_input->absbit);
373511db8173SJason Gerecke 		__clear_bit(MSC_SERIAL, wacom_wac->pen_input->mscbit);
373611db8173SJason Gerecke 		__clear_bit(EV_MSC, wacom_wac->pen_input->evbit);
373711db8173SJason Gerecke 	}
3738471d1714SBenjamin Tissoires }
3739471d1714SBenjamin Tissoires 
wacom_setup_pen_input_capabilities(struct input_dev * input_dev,struct wacom_wac * wacom_wac)37402636a3f2SJason Gerecke int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
3741471d1714SBenjamin Tissoires 				   struct wacom_wac *wacom_wac)
3742471d1714SBenjamin Tissoires {
3743471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom_wac->features;
3744471d1714SBenjamin Tissoires 
37452636a3f2SJason Gerecke 	if (!(features->device_type & WACOM_DEVICETYPE_PEN))
37462636a3f2SJason Gerecke 		return -ENODEV;
37472636a3f2SJason Gerecke 
3748e5bc8eb1SJason Gerecke 	if (features->device_type & WACOM_DEVICETYPE_DIRECT)
3749e5bc8eb1SJason Gerecke 		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
3750e5bc8eb1SJason Gerecke 	else
3751e5bc8eb1SJason Gerecke 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
3752e5bc8eb1SJason Gerecke 
375346fc466eSPing Cheng 	if (features->type == HID_GENERIC)
375446fc466eSPing Cheng 		/* setup has already been done */
37552636a3f2SJason Gerecke 		return 0;
37562636a3f2SJason Gerecke 
3757276559d8SPing Cheng 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
37582636a3f2SJason Gerecke 	__set_bit(BTN_TOUCH, input_dev->keybit);
37592636a3f2SJason Gerecke 	__set_bit(ABS_MISC, input_dev->absbit);
37602636a3f2SJason Gerecke 
3761e779ef23SJason Gerecke 	input_set_abs_params(input_dev, ABS_X, 0 + features->offset_left,
3762e779ef23SJason Gerecke 			     features->x_max - features->offset_right,
3763e779ef23SJason Gerecke 			     features->x_fuzz, 0);
3764e779ef23SJason Gerecke 	input_set_abs_params(input_dev, ABS_Y, 0 + features->offset_top,
3765e779ef23SJason Gerecke 			     features->y_max - features->offset_bottom,
3766e779ef23SJason Gerecke 			     features->y_fuzz, 0);
3767471d1714SBenjamin Tissoires 	input_set_abs_params(input_dev, ABS_PRESSURE, 0,
3768471d1714SBenjamin Tissoires 		features->pressure_max, features->pressure_fuzz, 0);
3769471d1714SBenjamin Tissoires 
3770471d1714SBenjamin Tissoires 	/* penabled devices have fixed resolution for each model */
3771471d1714SBenjamin Tissoires 	input_abs_set_res(input_dev, ABS_X, features->x_resolution);
3772471d1714SBenjamin Tissoires 	input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
3773471d1714SBenjamin Tissoires 
3774471d1714SBenjamin Tissoires 	switch (features->type) {
3775a2f71c6cSPing Cheng 	case GRAPHIRE_BT:
3776a2f71c6cSPing Cheng 		__clear_bit(ABS_MISC, input_dev->absbit);
3777df561f66SGustavo A. R. Silva 		fallthrough;
3778a2f71c6cSPing Cheng 
3779471d1714SBenjamin Tissoires 	case WACOM_MO:
3780471d1714SBenjamin Tissoires 	case WACOM_G4:
3781a2f71c6cSPing Cheng 		input_set_abs_params(input_dev, ABS_DISTANCE, 0,
3782a2f71c6cSPing Cheng 					      features->distance_max,
3783bef7e200SJason Gerecke 					      features->distance_fuzz, 0);
3784df561f66SGustavo A. R. Silva 		fallthrough;
3785471d1714SBenjamin Tissoires 
3786471d1714SBenjamin Tissoires 	case GRAPHIRE:
3787471d1714SBenjamin Tissoires 		input_set_capability(input_dev, EV_REL, REL_WHEEL);
3788471d1714SBenjamin Tissoires 
3789471d1714SBenjamin Tissoires 		__set_bit(BTN_LEFT, input_dev->keybit);
3790471d1714SBenjamin Tissoires 		__set_bit(BTN_RIGHT, input_dev->keybit);
3791471d1714SBenjamin Tissoires 		__set_bit(BTN_MIDDLE, input_dev->keybit);
3792471d1714SBenjamin Tissoires 
3793471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3794471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3795471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
3796471d1714SBenjamin Tissoires 		__set_bit(BTN_STYLUS, input_dev->keybit);
3797471d1714SBenjamin Tissoires 		__set_bit(BTN_STYLUS2, input_dev->keybit);
3798471d1714SBenjamin Tissoires 		break;
3799471d1714SBenjamin Tissoires 
3800500d4160SPing Cheng 	case WACOM_27QHD:
3801471d1714SBenjamin Tissoires 	case WACOM_24HD:
3802471d1714SBenjamin Tissoires 	case DTK:
3803471d1714SBenjamin Tissoires 	case WACOM_22HD:
3804471d1714SBenjamin Tissoires 	case WACOM_21UX2:
3805471d1714SBenjamin Tissoires 	case WACOM_BEE:
3806471d1714SBenjamin Tissoires 	case CINTIQ:
3807471d1714SBenjamin Tissoires 	case WACOM_13HD:
3808a2f71c6cSPing Cheng 	case CINTIQ_HYBRID:
3809f7acb55cSJason Gerecke 	case CINTIQ_COMPANION_2:
3810471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
381126fe4124SJason Gerecke 		input_abs_set_res(input_dev, ABS_Z, 287);
3812471d1714SBenjamin Tissoires 		wacom_setup_cintiq(wacom_wac);
3813471d1714SBenjamin Tissoires 		break;
3814471d1714SBenjamin Tissoires 
3815471d1714SBenjamin Tissoires 	case INTUOS3:
3816471d1714SBenjamin Tissoires 	case INTUOS3L:
3817471d1714SBenjamin Tissoires 	case INTUOS3S:
3818a2f71c6cSPing Cheng 	case INTUOS4:
3819a2f71c6cSPing Cheng 	case INTUOS4WL:
3820a2f71c6cSPing Cheng 	case INTUOS4L:
3821a2f71c6cSPing Cheng 	case INTUOS4S:
3822471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
382326fe4124SJason Gerecke 		input_abs_set_res(input_dev, ABS_Z, 287);
3824df561f66SGustavo A. R. Silva 		fallthrough;
3825471d1714SBenjamin Tissoires 
3826471d1714SBenjamin Tissoires 	case INTUOS:
3827471d1714SBenjamin Tissoires 		wacom_setup_intuos(wacom_wac);
3828471d1714SBenjamin Tissoires 		break;
3829471d1714SBenjamin Tissoires 
3830471d1714SBenjamin Tissoires 	case INTUOS5:
3831471d1714SBenjamin Tissoires 	case INTUOS5L:
3832471d1714SBenjamin Tissoires 	case INTUOSPM:
3833471d1714SBenjamin Tissoires 	case INTUOSPL:
3834471d1714SBenjamin Tissoires 	case INTUOS5S:
3835471d1714SBenjamin Tissoires 	case INTUOSPS:
38364922cd26SJason Gerecke 	case INTUOSP2_BT:
3837912c6aa6SAaron Armstrong Skomra 	case INTUOSP2S_BT:
3838471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_DISTANCE, 0,
3839471d1714SBenjamin Tissoires 				      features->distance_max,
3840bef7e200SJason Gerecke 				      features->distance_fuzz, 0);
3841471d1714SBenjamin Tissoires 
3842471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
384326fe4124SJason Gerecke 		input_abs_set_res(input_dev, ABS_Z, 287);
3844471d1714SBenjamin Tissoires 
3845471d1714SBenjamin Tissoires 		wacom_setup_intuos(wacom_wac);
3846471d1714SBenjamin Tissoires 		break;
3847471d1714SBenjamin Tissoires 
3848471d1714SBenjamin Tissoires 	case WACOM_24HDT:
3849500d4160SPing Cheng 	case WACOM_27QHDT:
3850471d1714SBenjamin Tissoires 	case MTSCREEN:
3851471d1714SBenjamin Tissoires 	case MTTPC:
3852471d1714SBenjamin Tissoires 	case MTTPC_B:
3853471d1714SBenjamin Tissoires 	case TABLETPC2FG:
3854471d1714SBenjamin Tissoires 	case TABLETPC:
3855471d1714SBenjamin Tissoires 	case TABLETPCE:
3856471d1714SBenjamin Tissoires 		__clear_bit(ABS_MISC, input_dev->absbit);
3857df561f66SGustavo A. R. Silva 		fallthrough;
3858471d1714SBenjamin Tissoires 
3859471d1714SBenjamin Tissoires 	case DTUS:
3860fff00bf8SPing Cheng 	case DTUSX:
3861471d1714SBenjamin Tissoires 	case PL:
3862471d1714SBenjamin Tissoires 	case DTU:
3863471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3864471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3865471d1714SBenjamin Tissoires 		__set_bit(BTN_STYLUS, input_dev->keybit);
3866471d1714SBenjamin Tissoires 		__set_bit(BTN_STYLUS2, input_dev->keybit);
3867471d1714SBenjamin Tissoires 		break;
3868471d1714SBenjamin Tissoires 
3869471d1714SBenjamin Tissoires 	case PTU:
3870471d1714SBenjamin Tissoires 		__set_bit(BTN_STYLUS2, input_dev->keybit);
3871df561f66SGustavo A. R. Silva 		fallthrough;
3872471d1714SBenjamin Tissoires 
3873471d1714SBenjamin Tissoires 	case PENPARTNER:
3874471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3875471d1714SBenjamin Tissoires 		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
3876471d1714SBenjamin Tissoires 		__set_bit(BTN_STYLUS, input_dev->keybit);
3877471d1714SBenjamin Tissoires 		break;
3878471d1714SBenjamin Tissoires 
3879471d1714SBenjamin Tissoires 	case INTUOSHT:
3880471d1714SBenjamin Tissoires 	case BAMBOO_PT:
38813b164a00SPing Cheng 	case BAMBOO_PEN:
3882eda01dabSPing Cheng 	case INTUOSHT2:
388387046b6cSAaron Armstrong Skomra 	case INTUOSHT3_BT:
388487046b6cSAaron Armstrong Skomra 		if (features->type == INTUOSHT2 ||
388587046b6cSAaron Armstrong Skomra 		    features->type == INTUOSHT3_BT) {
3886eda01dabSPing Cheng 			wacom_setup_basic_pro_pen(wacom_wac);
3887eda01dabSPing Cheng 		} else {
3888eda01dabSPing Cheng 			__clear_bit(ABS_MISC, input_dev->absbit);
38892636a3f2SJason Gerecke 			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
3890eda01dabSPing Cheng 			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
38912636a3f2SJason Gerecke 			__set_bit(BTN_STYLUS, input_dev->keybit);
38922636a3f2SJason Gerecke 			__set_bit(BTN_STYLUS2, input_dev->keybit);
38932636a3f2SJason Gerecke 			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
38942636a3f2SJason Gerecke 				      features->distance_max,
3895bef7e200SJason Gerecke 				      features->distance_fuzz, 0);
3896eda01dabSPing Cheng 		}
38972636a3f2SJason Gerecke 		break;
38982636a3f2SJason Gerecke 	case BAMBOO_PAD:
38992636a3f2SJason Gerecke 		__clear_bit(ABS_MISC, input_dev->absbit);
39002636a3f2SJason Gerecke 		break;
39012636a3f2SJason Gerecke 	}
39022636a3f2SJason Gerecke 	return 0;
39032636a3f2SJason Gerecke }
3904471d1714SBenjamin Tissoires 
wacom_setup_touch_input_capabilities(struct input_dev * input_dev,struct wacom_wac * wacom_wac)39052636a3f2SJason Gerecke int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
39062636a3f2SJason Gerecke 					 struct wacom_wac *wacom_wac)
39072636a3f2SJason Gerecke {
39082636a3f2SJason Gerecke 	struct wacom_features *features = &wacom_wac->features;
39092636a3f2SJason Gerecke 
39102636a3f2SJason Gerecke 	if (!(features->device_type & WACOM_DEVICETYPE_TOUCH))
39112636a3f2SJason Gerecke 		return -ENODEV;
39122636a3f2SJason Gerecke 
3913e5bc8eb1SJason Gerecke 	if (features->device_type & WACOM_DEVICETYPE_DIRECT)
3914e5bc8eb1SJason Gerecke 		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
3915e5bc8eb1SJason Gerecke 	else
3916e5bc8eb1SJason Gerecke 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
3917e5bc8eb1SJason Gerecke 
39182636a3f2SJason Gerecke 	if (features->type == HID_GENERIC)
39192636a3f2SJason Gerecke 		/* setup has already been done */
39202636a3f2SJason Gerecke 		return 0;
39212636a3f2SJason Gerecke 
3922276559d8SPing Cheng 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
39232636a3f2SJason Gerecke 	__set_bit(BTN_TOUCH, input_dev->keybit);
39242636a3f2SJason Gerecke 
39252636a3f2SJason Gerecke 	if (features->touch_max == 1) {
39262636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_X, 0,
39272636a3f2SJason Gerecke 			features->x_max, features->x_fuzz, 0);
39282636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_Y, 0,
39292636a3f2SJason Gerecke 			features->y_max, features->y_fuzz, 0);
39302636a3f2SJason Gerecke 		input_abs_set_res(input_dev, ABS_X,
39312636a3f2SJason Gerecke 				  features->x_resolution);
39322636a3f2SJason Gerecke 		input_abs_set_res(input_dev, ABS_Y,
39332636a3f2SJason Gerecke 				  features->y_resolution);
39342636a3f2SJason Gerecke 	}
39352636a3f2SJason Gerecke 	else if (features->touch_max > 1) {
39362636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
39372636a3f2SJason Gerecke 			features->x_max, features->x_fuzz, 0);
39382636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
39392636a3f2SJason Gerecke 			features->y_max, features->y_fuzz, 0);
39402636a3f2SJason Gerecke 		input_abs_set_res(input_dev, ABS_MT_POSITION_X,
39412636a3f2SJason Gerecke 				  features->x_resolution);
39422636a3f2SJason Gerecke 		input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
39432636a3f2SJason Gerecke 				  features->y_resolution);
39442636a3f2SJason Gerecke 	}
39452636a3f2SJason Gerecke 
39462636a3f2SJason Gerecke 	switch (features->type) {
39474922cd26SJason Gerecke 	case INTUOSP2_BT:
3948912c6aa6SAaron Armstrong Skomra 	case INTUOSP2S_BT:
39494922cd26SJason Gerecke 		input_dev->evbit[0] |= BIT_MASK(EV_SW);
39504922cd26SJason Gerecke 		__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
39514922cd26SJason Gerecke 
39524922cd26SJason Gerecke 		if (wacom_wac->shared->touch->product == 0x361) {
39534922cd26SJason Gerecke 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
39544922cd26SJason Gerecke 					     0, 12440, 4, 0);
39554922cd26SJason Gerecke 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
39564922cd26SJason Gerecke 					     0, 8640, 4, 0);
39574922cd26SJason Gerecke 		}
39584922cd26SJason Gerecke 		else if (wacom_wac->shared->touch->product == 0x360) {
39594922cd26SJason Gerecke 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
39604922cd26SJason Gerecke 					     0, 8960, 4, 0);
39614922cd26SJason Gerecke 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
39624922cd26SJason Gerecke 					     0, 5920, 4, 0);
39634922cd26SJason Gerecke 		}
3964912c6aa6SAaron Armstrong Skomra 		else if (wacom_wac->shared->touch->product == 0x393) {
3965912c6aa6SAaron Armstrong Skomra 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
3966912c6aa6SAaron Armstrong Skomra 					     0, 6400, 4, 0);
3967912c6aa6SAaron Armstrong Skomra 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
3968912c6aa6SAaron Armstrong Skomra 					     0, 4000, 4, 0);
3969912c6aa6SAaron Armstrong Skomra 		}
39704922cd26SJason Gerecke 		input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
397168c20cc2SAaron Armstrong Skomra 		input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
39724922cd26SJason Gerecke 
3973df561f66SGustavo A. R. Silva 		fallthrough;
39744922cd26SJason Gerecke 
39752636a3f2SJason Gerecke 	case INTUOS5:
39762636a3f2SJason Gerecke 	case INTUOS5L:
39772636a3f2SJason Gerecke 	case INTUOSPM:
39782636a3f2SJason Gerecke 	case INTUOSPL:
39792636a3f2SJason Gerecke 	case INTUOS5S:
39802636a3f2SJason Gerecke 	case INTUOSPS:
39812636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
39822636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0);
39832636a3f2SJason Gerecke 		input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
39842636a3f2SJason Gerecke 		break;
39852636a3f2SJason Gerecke 
39862636a3f2SJason Gerecke 	case WACOM_24HDT:
39872636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
39882636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0);
39892636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0);
39902636a3f2SJason Gerecke 		input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
3991df561f66SGustavo A. R. Silva 		fallthrough;
39922636a3f2SJason Gerecke 
39932636a3f2SJason Gerecke 	case WACOM_27QHDT:
3994670e9092SAaron Armstrong Skomra 		if (wacom_wac->shared->touch->product == 0x32C ||
3995670e9092SAaron Armstrong Skomra 		    wacom_wac->shared->touch->product == 0xF6) {
3996670e9092SAaron Armstrong Skomra 			input_dev->evbit[0] |= BIT_MASK(EV_SW);
3997670e9092SAaron Armstrong Skomra 			__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
39986ca2350eSJason Gerecke 			wacom_wac->has_mute_touch_switch = true;
3999dc9dc864SPing Cheng 			wacom_wac->is_soft_touch_switch = true;
4000670e9092SAaron Armstrong Skomra 		}
4001df561f66SGustavo A. R. Silva 		fallthrough;
4002670e9092SAaron Armstrong Skomra 
40032636a3f2SJason Gerecke 	case MTSCREEN:
40042636a3f2SJason Gerecke 	case MTTPC:
40052636a3f2SJason Gerecke 	case MTTPC_B:
40062636a3f2SJason Gerecke 	case TABLETPC2FG:
40072636a3f2SJason Gerecke 		input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT);
4008df561f66SGustavo A. R. Silva 		fallthrough;
40092636a3f2SJason Gerecke 
40102636a3f2SJason Gerecke 	case TABLETPC:
40112636a3f2SJason Gerecke 	case TABLETPCE:
40122636a3f2SJason Gerecke 		break;
40132636a3f2SJason Gerecke 
40142636a3f2SJason Gerecke 	case INTUOSHT:
4015eda01dabSPing Cheng 	case INTUOSHT2:
40162636a3f2SJason Gerecke 		input_dev->evbit[0] |= BIT_MASK(EV_SW);
40172636a3f2SJason Gerecke 		__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
4018df561f66SGustavo A. R. Silva 		fallthrough;
40192636a3f2SJason Gerecke 
40202636a3f2SJason Gerecke 	case BAMBOO_PT:
40213b164a00SPing Cheng 	case BAMBOO_TOUCH:
4022471d1714SBenjamin Tissoires 		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
4023471d1714SBenjamin Tissoires 			input_set_abs_params(input_dev,
4024471d1714SBenjamin Tissoires 				     ABS_MT_TOUCH_MAJOR,
4025471d1714SBenjamin Tissoires 				     0, features->x_max, 0, 0);
4026471d1714SBenjamin Tissoires 			input_set_abs_params(input_dev,
4027471d1714SBenjamin Tissoires 				     ABS_MT_TOUCH_MINOR,
4028471d1714SBenjamin Tissoires 				     0, features->y_max, 0, 0);
4029471d1714SBenjamin Tissoires 		}
40305e2aa2edSDmitry Torokhov 		input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
4031471d1714SBenjamin Tissoires 		break;
40322636a3f2SJason Gerecke 
40338c97a765SBenjamin Tissoires 	case BAMBOO_PAD:
40348c97a765SBenjamin Tissoires 		input_mt_init_slots(input_dev, features->touch_max,
40358c97a765SBenjamin Tissoires 				    INPUT_MT_POINTER);
40368c97a765SBenjamin Tissoires 		__set_bit(BTN_LEFT, input_dev->keybit);
40378c97a765SBenjamin Tissoires 		__set_bit(BTN_RIGHT, input_dev->keybit);
40388c97a765SBenjamin Tissoires 		break;
4039471d1714SBenjamin Tissoires 	}
4040471d1714SBenjamin Tissoires 	return 0;
4041471d1714SBenjamin Tissoires }
4042471d1714SBenjamin Tissoires 
wacom_numbered_button_to_key(int n)404349005b9fSJason Gerecke static int wacom_numbered_button_to_key(int n)
404449005b9fSJason Gerecke {
404549005b9fSJason Gerecke 	if (n < 10)
404649005b9fSJason Gerecke 		return BTN_0 + n;
404749005b9fSJason Gerecke 	else if (n < 16)
404849005b9fSJason Gerecke 		return BTN_A + (n-10);
404949005b9fSJason Gerecke 	else if (n < 18)
405049005b9fSJason Gerecke 		return BTN_BASE + (n-16);
405149005b9fSJason Gerecke 	else
405249005b9fSJason Gerecke 		return 0;
405349005b9fSJason Gerecke }
405449005b9fSJason Gerecke 
wacom_setup_numbered_buttons(struct input_dev * input_dev,int button_count)40555397df15SJiri Kosina static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
405670ee06c5SAaron Skomra 				int button_count)
405770ee06c5SAaron Skomra {
405870ee06c5SAaron Skomra 	int i;
405970ee06c5SAaron Skomra 
406049005b9fSJason Gerecke 	for (i = 0; i < button_count; i++) {
406149005b9fSJason Gerecke 		int key = wacom_numbered_button_to_key(i);
406249005b9fSJason Gerecke 
406349005b9fSJason Gerecke 		if (key)
406449005b9fSJason Gerecke 			__set_bit(key, input_dev->keybit);
406549005b9fSJason Gerecke 	}
406670ee06c5SAaron Skomra }
406770ee06c5SAaron Skomra 
wacom_24hd_update_leds(struct wacom * wacom,int mask,int group)40686a06281eSBenjamin Tissoires static void wacom_24hd_update_leds(struct wacom *wacom, int mask, int group)
40696a06281eSBenjamin Tissoires {
40706a06281eSBenjamin Tissoires 	struct wacom_led *led;
40716a06281eSBenjamin Tissoires 	int i;
40726a06281eSBenjamin Tissoires 	bool updated = false;
40736a06281eSBenjamin Tissoires 
40746a06281eSBenjamin Tissoires 	/*
40756a06281eSBenjamin Tissoires 	 * 24HD has LED group 1 to the left and LED group 0 to the right.
40766a06281eSBenjamin Tissoires 	 * So group 0 matches the second half of the buttons and thus the mask
40776a06281eSBenjamin Tissoires 	 * needs to be shifted.
40786a06281eSBenjamin Tissoires 	 */
40796a06281eSBenjamin Tissoires 	if (group == 0)
40806a06281eSBenjamin Tissoires 		mask >>= 8;
40816a06281eSBenjamin Tissoires 
40826a06281eSBenjamin Tissoires 	for (i = 0; i < 3; i++) {
40836a06281eSBenjamin Tissoires 		led = wacom_led_find(wacom, group, i);
40846a06281eSBenjamin Tissoires 		if (!led) {
40856a06281eSBenjamin Tissoires 			hid_err(wacom->hdev, "can't find LED %d in group %d\n",
40866a06281eSBenjamin Tissoires 				i, group);
40876a06281eSBenjamin Tissoires 			continue;
40886a06281eSBenjamin Tissoires 		}
40896a06281eSBenjamin Tissoires 		if (!updated && mask & BIT(i)) {
40906a06281eSBenjamin Tissoires 			led->held = true;
40916a06281eSBenjamin Tissoires 			led_trigger_event(&led->trigger, LED_FULL);
40926a06281eSBenjamin Tissoires 		} else {
40936a06281eSBenjamin Tissoires 			led->held = false;
40946a06281eSBenjamin Tissoires 		}
40956a06281eSBenjamin Tissoires 	}
40966a06281eSBenjamin Tissoires }
40976a06281eSBenjamin Tissoires 
wacom_is_led_toggled(struct wacom * wacom,int button_count,int mask,int group)409834736aa9SBenjamin Tissoires static bool wacom_is_led_toggled(struct wacom *wacom, int button_count,
409934736aa9SBenjamin Tissoires 				 int mask, int group)
410034736aa9SBenjamin Tissoires {
41016441fc78SJason Gerecke 	int group_button;
410234736aa9SBenjamin Tissoires 
41035a0fe8abSBenjamin Tissoires 	/*
41046a06281eSBenjamin Tissoires 	 * 21UX2 has LED group 1 to the left and LED group 0
41055a0fe8abSBenjamin Tissoires 	 * to the right. We need to reverse the group to match this
41065a0fe8abSBenjamin Tissoires 	 * historical behavior.
41075a0fe8abSBenjamin Tissoires 	 */
41086a06281eSBenjamin Tissoires 	if (wacom->wacom_wac.features.type == WACOM_21UX2)
41095a0fe8abSBenjamin Tissoires 		group = 1 - group;
41105a0fe8abSBenjamin Tissoires 
41116441fc78SJason Gerecke 	group_button = group * (button_count/wacom->led.count);
411234736aa9SBenjamin Tissoires 
41136441fc78SJason Gerecke 	if (wacom->wacom_wac.features.type == INTUOSP2_BT)
41146441fc78SJason Gerecke 		group_button = 8;
41156441fc78SJason Gerecke 
41166441fc78SJason Gerecke 	return mask & (1 << group_button);
411734736aa9SBenjamin Tissoires }
411834736aa9SBenjamin Tissoires 
wacom_update_led(struct wacom * wacom,int button_count,int mask,int group)411934736aa9SBenjamin Tissoires static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
412034736aa9SBenjamin Tissoires 			     int group)
412134736aa9SBenjamin Tissoires {
412234736aa9SBenjamin Tissoires 	struct wacom_led *led, *next_led;
412334736aa9SBenjamin Tissoires 	int cur;
412434736aa9SBenjamin Tissoires 	bool pressed;
412534736aa9SBenjamin Tissoires 
41266a06281eSBenjamin Tissoires 	if (wacom->wacom_wac.features.type == WACOM_24HD)
41276a06281eSBenjamin Tissoires 		return wacom_24hd_update_leds(wacom, mask, group);
41286a06281eSBenjamin Tissoires 
412934736aa9SBenjamin Tissoires 	pressed = wacom_is_led_toggled(wacom, button_count, mask, group);
413034736aa9SBenjamin Tissoires 	cur = wacom->led.groups[group].select;
413134736aa9SBenjamin Tissoires 
413234736aa9SBenjamin Tissoires 	led = wacom_led_find(wacom, group, cur);
413334736aa9SBenjamin Tissoires 	if (!led) {
413434736aa9SBenjamin Tissoires 		hid_err(wacom->hdev, "can't find current LED %d in group %d\n",
413534736aa9SBenjamin Tissoires 			cur, group);
413634736aa9SBenjamin Tissoires 		return;
413734736aa9SBenjamin Tissoires 	}
413834736aa9SBenjamin Tissoires 
413934736aa9SBenjamin Tissoires 	if (!pressed) {
414034736aa9SBenjamin Tissoires 		led->held = false;
414134736aa9SBenjamin Tissoires 		return;
414234736aa9SBenjamin Tissoires 	}
414334736aa9SBenjamin Tissoires 
414434736aa9SBenjamin Tissoires 	if (led->held && pressed)
414534736aa9SBenjamin Tissoires 		return;
414634736aa9SBenjamin Tissoires 
414734736aa9SBenjamin Tissoires 	next_led = wacom_led_next(wacom, led);
414834736aa9SBenjamin Tissoires 	if (!next_led) {
414934736aa9SBenjamin Tissoires 		hid_err(wacom->hdev, "can't find next LED in group %d\n",
415034736aa9SBenjamin Tissoires 			group);
415134736aa9SBenjamin Tissoires 		return;
415234736aa9SBenjamin Tissoires 	}
415334736aa9SBenjamin Tissoires 	if (next_led == led)
415434736aa9SBenjamin Tissoires 		return;
415534736aa9SBenjamin Tissoires 
415634736aa9SBenjamin Tissoires 	next_led->held = true;
415734736aa9SBenjamin Tissoires 	led_trigger_event(&next_led->trigger,
415834736aa9SBenjamin Tissoires 			  wacom_leds_brightness_get(next_led));
415934736aa9SBenjamin Tissoires }
416034736aa9SBenjamin Tissoires 
wacom_report_numbered_buttons(struct input_dev * input_dev,int button_count,int mask)4161c7f0522aSJason Gerecke static void wacom_report_numbered_buttons(struct input_dev *input_dev,
4162c7f0522aSJason Gerecke 				int button_count, int mask)
4163c7f0522aSJason Gerecke {
416434736aa9SBenjamin Tissoires 	struct wacom *wacom = input_get_drvdata(input_dev);
4165c7f0522aSJason Gerecke 	int i;
4166c7f0522aSJason Gerecke 
416734736aa9SBenjamin Tissoires 	for (i = 0; i < wacom->led.count; i++)
416834736aa9SBenjamin Tissoires 		wacom_update_led(wacom,  button_count, mask, i);
416934736aa9SBenjamin Tissoires 
417049005b9fSJason Gerecke 	for (i = 0; i < button_count; i++) {
417149005b9fSJason Gerecke 		int key = wacom_numbered_button_to_key(i);
417249005b9fSJason Gerecke 
417349005b9fSJason Gerecke 		if (key)
417449005b9fSJason Gerecke 			input_report_key(input_dev, key, mask & (1 << i));
417549005b9fSJason Gerecke 	}
4176c7f0522aSJason Gerecke }
4177c7f0522aSJason Gerecke 
wacom_setup_pad_input_capabilities(struct input_dev * input_dev,struct wacom_wac * wacom_wac)4178471d1714SBenjamin Tissoires int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
4179471d1714SBenjamin Tissoires 				   struct wacom_wac *wacom_wac)
4180471d1714SBenjamin Tissoires {
4181471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom_wac->features;
4182471d1714SBenjamin Tissoires 
4183e7deb157SPing Cheng 	if ((features->type == HID_GENERIC) && features->numbered_buttons > 0)
4184e7deb157SPing Cheng 		features->device_type |= WACOM_DEVICETYPE_PAD;
4185e7deb157SPing Cheng 
4186862cf553SJason Gerecke 	if (!(features->device_type & WACOM_DEVICETYPE_PAD))
4187862cf553SJason Gerecke 		return -ENODEV;
4188862cf553SJason Gerecke 
41897c35dc3cSBenjamin Tissoires 	if (features->type == REMOTE && input_dev == wacom_wac->pad_input)
41907c35dc3cSBenjamin Tissoires 		return -ENODEV;
41917c35dc3cSBenjamin Tissoires 
4192471d1714SBenjamin Tissoires 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
4193471d1714SBenjamin Tissoires 
4194471d1714SBenjamin Tissoires 	/* kept for making legacy xf86-input-wacom working with the wheels */
4195471d1714SBenjamin Tissoires 	__set_bit(ABS_MISC, input_dev->absbit);
4196471d1714SBenjamin Tissoires 
4197471d1714SBenjamin Tissoires 	/* kept for making legacy xf86-input-wacom accepting the pad */
41985922e613SJason Gerecke 	if (!(input_dev->absinfo && (input_dev->absinfo[ABS_X].minimum ||
41995922e613SJason Gerecke 	      input_dev->absinfo[ABS_X].maximum)))
4200471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
42015922e613SJason Gerecke 	if (!(input_dev->absinfo && (input_dev->absinfo[ABS_Y].minimum ||
42025922e613SJason Gerecke 	      input_dev->absinfo[ABS_Y].maximum)))
4203471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
4204471d1714SBenjamin Tissoires 
420512969e3bSBenjamin Tissoires 	/* kept for making udev and libwacom accepting the pad */
420612969e3bSBenjamin Tissoires 	__set_bit(BTN_STYLUS, input_dev->keybit);
420712969e3bSBenjamin Tissoires 
420870ee06c5SAaron Skomra 	wacom_setup_numbered_buttons(input_dev, features->numbered_buttons);
420970ee06c5SAaron Skomra 
4210471d1714SBenjamin Tissoires 	switch (features->type) {
421170ee06c5SAaron Skomra 
421270ee06c5SAaron Skomra 	case CINTIQ_HYBRID:
4213f7acb55cSJason Gerecke 	case CINTIQ_COMPANION_2:
421470ee06c5SAaron Skomra 	case DTK:
421570ee06c5SAaron Skomra 	case DTUS:
4216387142bbSBenjamin Tissoires 	case GRAPHIRE_BT:
4217387142bbSBenjamin Tissoires 		break;
4218387142bbSBenjamin Tissoires 
4219471d1714SBenjamin Tissoires 	case WACOM_MO:
4220471d1714SBenjamin Tissoires 		__set_bit(BTN_BACK, input_dev->keybit);
4221471d1714SBenjamin Tissoires 		__set_bit(BTN_LEFT, input_dev->keybit);
4222471d1714SBenjamin Tissoires 		__set_bit(BTN_FORWARD, input_dev->keybit);
4223471d1714SBenjamin Tissoires 		__set_bit(BTN_RIGHT, input_dev->keybit);
4224471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4225471d1714SBenjamin Tissoires 		break;
4226471d1714SBenjamin Tissoires 
4227471d1714SBenjamin Tissoires 	case WACOM_G4:
4228471d1714SBenjamin Tissoires 		__set_bit(BTN_BACK, input_dev->keybit);
4229471d1714SBenjamin Tissoires 		__set_bit(BTN_FORWARD, input_dev->keybit);
4230471d1714SBenjamin Tissoires 		input_set_capability(input_dev, EV_REL, REL_WHEEL);
4231471d1714SBenjamin Tissoires 		break;
4232471d1714SBenjamin Tissoires 
4233471d1714SBenjamin Tissoires 	case WACOM_24HD:
4234471d1714SBenjamin Tissoires 		__set_bit(KEY_PROG1, input_dev->keybit);
4235471d1714SBenjamin Tissoires 		__set_bit(KEY_PROG2, input_dev->keybit);
4236471d1714SBenjamin Tissoires 		__set_bit(KEY_PROG3, input_dev->keybit);
4237471d1714SBenjamin Tissoires 
4238670e9092SAaron Armstrong Skomra 		__set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
4239670e9092SAaron Armstrong Skomra 		__set_bit(KEY_INFO, input_dev->keybit);
4240670e9092SAaron Armstrong Skomra 
4241670e9092SAaron Armstrong Skomra 		if (!features->oPid)
4242670e9092SAaron Armstrong Skomra 			__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
4243670e9092SAaron Armstrong Skomra 
4244471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4245471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
4246471d1714SBenjamin Tissoires 		break;
4247471d1714SBenjamin Tissoires 
4248500d4160SPing Cheng 	case WACOM_27QHD:
4249500d4160SPing Cheng 		__set_bit(KEY_PROG1, input_dev->keybit);
4250500d4160SPing Cheng 		__set_bit(KEY_PROG2, input_dev->keybit);
4251500d4160SPing Cheng 		__set_bit(KEY_PROG3, input_dev->keybit);
4252670e9092SAaron Armstrong Skomra 
4253670e9092SAaron Armstrong Skomra 		__set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
4254670e9092SAaron Armstrong Skomra 		__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
4255670e9092SAaron Armstrong Skomra 
4256670e9092SAaron Armstrong Skomra 		if (!features->oPid)
4257670e9092SAaron Armstrong Skomra 			__set_bit(KEY_CONTROLPANEL, input_dev->keybit);
4258500d4160SPing Cheng 		input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0);
4259500d4160SPing Cheng 		input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
4260500d4160SPing Cheng 		input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0);
4261500d4160SPing Cheng 		input_abs_set_res(input_dev, ABS_Y, 1024);
4262500d4160SPing Cheng 		input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0);
4263500d4160SPing Cheng 		input_abs_set_res(input_dev, ABS_Z, 1024);
4264500d4160SPing Cheng 		__set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
4265500d4160SPing Cheng 		break;
4266500d4160SPing Cheng 
4267471d1714SBenjamin Tissoires 	case WACOM_22HD:
4268471d1714SBenjamin Tissoires 		__set_bit(KEY_PROG1, input_dev->keybit);
4269471d1714SBenjamin Tissoires 		__set_bit(KEY_PROG2, input_dev->keybit);
4270471d1714SBenjamin Tissoires 		__set_bit(KEY_PROG3, input_dev->keybit);
4271670e9092SAaron Armstrong Skomra 
4272670e9092SAaron Armstrong Skomra 		__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
4273670e9092SAaron Armstrong Skomra 		__set_bit(KEY_INFO, input_dev->keybit);
4274df561f66SGustavo A. R. Silva 		fallthrough;
4275471d1714SBenjamin Tissoires 
4276471d1714SBenjamin Tissoires 	case WACOM_21UX2:
4277471d1714SBenjamin Tissoires 	case WACOM_BEE:
4278471d1714SBenjamin Tissoires 	case CINTIQ:
4279471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
4280471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
4281471d1714SBenjamin Tissoires 		break;
4282471d1714SBenjamin Tissoires 
4283471d1714SBenjamin Tissoires 	case WACOM_13HD:
4284471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4285471d1714SBenjamin Tissoires 		break;
4286471d1714SBenjamin Tissoires 
4287471d1714SBenjamin Tissoires 	case INTUOS3:
4288471d1714SBenjamin Tissoires 	case INTUOS3L:
4289471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
4290df561f66SGustavo A. R. Silva 		fallthrough;
4291471d1714SBenjamin Tissoires 
4292471d1714SBenjamin Tissoires 	case INTUOS3S:
4293471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
4294471d1714SBenjamin Tissoires 		break;
4295471d1714SBenjamin Tissoires 
4296471d1714SBenjamin Tissoires 	case INTUOS5:
4297471d1714SBenjamin Tissoires 	case INTUOS5L:
4298471d1714SBenjamin Tissoires 	case INTUOSPM:
4299471d1714SBenjamin Tissoires 	case INTUOSPL:
4300471d1714SBenjamin Tissoires 	case INTUOS5S:
4301471d1714SBenjamin Tissoires 	case INTUOSPS:
43024922cd26SJason Gerecke 	case INTUOSP2_BT:
4303912c6aa6SAaron Armstrong Skomra 	case INTUOSP2S_BT:
4304471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4305471d1714SBenjamin Tissoires 		break;
4306471d1714SBenjamin Tissoires 
430781af7e61SBenjamin Tissoires 	case INTUOS4WL:
430881af7e61SBenjamin Tissoires 		/*
430981af7e61SBenjamin Tissoires 		 * For Bluetooth devices, the udev rule does not work correctly
431081af7e61SBenjamin Tissoires 		 * for pads unless we add a stylus capability, which forces
431181af7e61SBenjamin Tissoires 		 * ID_INPUT_TABLET to be set.
431281af7e61SBenjamin Tissoires 		 */
431381af7e61SBenjamin Tissoires 		__set_bit(BTN_STYLUS, input_dev->keybit);
4314df561f66SGustavo A. R. Silva 		fallthrough;
431581af7e61SBenjamin Tissoires 
4316471d1714SBenjamin Tissoires 	case INTUOS4:
4317471d1714SBenjamin Tissoires 	case INTUOS4L:
4318471d1714SBenjamin Tissoires 	case INTUOS4S:
4319471d1714SBenjamin Tissoires 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
4320471d1714SBenjamin Tissoires 		break;
4321471d1714SBenjamin Tissoires 
4322471d1714SBenjamin Tissoires 	case INTUOSHT:
4323471d1714SBenjamin Tissoires 	case BAMBOO_PT:
43243b164a00SPing Cheng 	case BAMBOO_TOUCH:
4325eda01dabSPing Cheng 	case INTUOSHT2:
4326471d1714SBenjamin Tissoires 		__clear_bit(ABS_MISC, input_dev->absbit);
4327471d1714SBenjamin Tissoires 
4328471d1714SBenjamin Tissoires 		__set_bit(BTN_LEFT, input_dev->keybit);
4329471d1714SBenjamin Tissoires 		__set_bit(BTN_FORWARD, input_dev->keybit);
4330471d1714SBenjamin Tissoires 		__set_bit(BTN_BACK, input_dev->keybit);
4331471d1714SBenjamin Tissoires 		__set_bit(BTN_RIGHT, input_dev->keybit);
4332471d1714SBenjamin Tissoires 
4333471d1714SBenjamin Tissoires 		break;
4334471d1714SBenjamin Tissoires 
433572b236d6SAaron Skomra 	case REMOTE:
433672b236d6SAaron Skomra 		input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
433772b236d6SAaron Skomra 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
433872b236d6SAaron Skomra 		break;
433972b236d6SAaron Skomra 
434087046b6cSAaron Armstrong Skomra 	case INTUOSHT3_BT:
43415922e613SJason Gerecke 	case HID_GENERIC:
43425922e613SJason Gerecke 		break;
43435922e613SJason Gerecke 
4344471d1714SBenjamin Tissoires 	default:
4345471d1714SBenjamin Tissoires 		/* no pad supported */
4346b3c8e93fSPing Cheng 		return -ENODEV;
4347471d1714SBenjamin Tissoires 	}
4348471d1714SBenjamin Tissoires 	return 0;
4349471d1714SBenjamin Tissoires }
4350471d1714SBenjamin Tissoires 
4351471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x00 =
4352471d1714SBenjamin Tissoires 	{ "Wacom Penpartner", 5040, 3780, 255, 0,
4353471d1714SBenjamin Tissoires 	  PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
4354471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x10 =
4355471d1714SBenjamin Tissoires 	{ "Wacom Graphire", 10206, 7422, 511, 63,
4356471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4357387142bbSBenjamin Tissoires static const struct wacom_features wacom_features_0x81 =
4358387142bbSBenjamin Tissoires 	{ "Wacom Graphire BT", 16704, 12064, 511, 32,
435970ee06c5SAaron Skomra 	  GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES, 2 };
4360471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x11 =
4361471d1714SBenjamin Tissoires 	{ "Wacom Graphire2 4x5", 10206, 7422, 511, 63,
4362471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4363471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x12 =
4364471d1714SBenjamin Tissoires 	{ "Wacom Graphire2 5x7", 13918, 10206, 511, 63,
4365471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4366471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x13 =
4367471d1714SBenjamin Tissoires 	{ "Wacom Graphire3", 10208, 7424, 511, 63,
4368471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4369471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x14 =
4370471d1714SBenjamin Tissoires 	{ "Wacom Graphire3 6x8", 16704, 12064, 511, 63,
4371471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4372471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x15 =
4373471d1714SBenjamin Tissoires 	{ "Wacom Graphire4 4x5", 10208, 7424, 511, 63,
4374471d1714SBenjamin Tissoires 	  WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4375471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x16 =
4376471d1714SBenjamin Tissoires 	{ "Wacom Graphire4 6x8", 16704, 12064, 511, 63,
4377471d1714SBenjamin Tissoires 	  WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4378471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x17 =
4379471d1714SBenjamin Tissoires 	{ "Wacom BambooFun 4x5", 14760, 9225, 511, 63,
4380471d1714SBenjamin Tissoires 	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4381471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x18 =
4382471d1714SBenjamin Tissoires 	{ "Wacom BambooFun 6x8", 21648, 13530, 511, 63,
4383471d1714SBenjamin Tissoires 	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4384471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x19 =
4385471d1714SBenjamin Tissoires 	{ "Wacom Bamboo1 Medium", 16704, 12064, 511, 63,
4386471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
4387471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x60 =
4388471d1714SBenjamin Tissoires 	{ "Wacom Volito", 5104, 3712, 511, 63,
4389471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4390471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x61 =
4391471d1714SBenjamin Tissoires 	{ "Wacom PenStation2", 3250, 2320, 255, 63,
4392471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4393471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x62 =
4394471d1714SBenjamin Tissoires 	{ "Wacom Volito2 4x5", 5104, 3712, 511, 63,
4395471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4396471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x63 =
4397471d1714SBenjamin Tissoires 	{ "Wacom Volito2 2x3", 3248, 2320, 511, 63,
4398471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4399471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x64 =
4400471d1714SBenjamin Tissoires 	{ "Wacom PenPartner2", 3250, 2320, 511, 63,
4401471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
4402471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x65 =
4403471d1714SBenjamin Tissoires 	{ "Wacom Bamboo", 14760, 9225, 511, 63,
4404471d1714SBenjamin Tissoires 	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4405471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x69 =
4406471d1714SBenjamin Tissoires 	{ "Wacom Bamboo1", 5104, 3712, 511, 63,
4407471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
4408471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x6A =
4409471d1714SBenjamin Tissoires 	{ "Wacom Bamboo1 4x6", 14760, 9225, 1023, 63,
4410471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4411471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x6B =
4412471d1714SBenjamin Tissoires 	{ "Wacom Bamboo1 5x8", 21648, 13530, 1023, 63,
4413471d1714SBenjamin Tissoires 	  GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4414471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x20 =
4415471d1714SBenjamin Tissoires 	{ "Wacom Intuos 4x5", 12700, 10600, 1023, 31,
4416471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4417471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x21 =
4418471d1714SBenjamin Tissoires 	{ "Wacom Intuos 6x8", 20320, 16240, 1023, 31,
4419471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4420471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x22 =
4421471d1714SBenjamin Tissoires 	{ "Wacom Intuos 9x12", 30480, 24060, 1023, 31,
4422471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4423471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x23 =
4424471d1714SBenjamin Tissoires 	{ "Wacom Intuos 12x12", 30480, 31680, 1023, 31,
4425471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4426471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x24 =
4427471d1714SBenjamin Tissoires 	{ "Wacom Intuos 12x18", 45720, 31680, 1023, 31,
4428471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4429471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x30 =
4430471d1714SBenjamin Tissoires 	{ "Wacom PL400", 5408, 4056, 255, 0,
4431471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4432471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x31 =
4433471d1714SBenjamin Tissoires 	{ "Wacom PL500", 6144, 4608, 255, 0,
4434471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4435471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x32 =
4436471d1714SBenjamin Tissoires 	{ "Wacom PL600", 6126, 4604, 255, 0,
4437471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4438471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x33 =
4439471d1714SBenjamin Tissoires 	{ "Wacom PL600SX", 6260, 5016, 255, 0,
4440471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4441471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x34 =
4442471d1714SBenjamin Tissoires 	{ "Wacom PL550", 6144, 4608, 511, 0,
4443471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4444471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x35 =
4445471d1714SBenjamin Tissoires 	{ "Wacom PL800", 7220, 5780, 511, 0,
4446471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4447471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x37 =
4448471d1714SBenjamin Tissoires 	{ "Wacom PL700", 6758, 5406, 511, 0,
4449471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4450471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x38 =
4451471d1714SBenjamin Tissoires 	{ "Wacom PL510", 6282, 4762, 511, 0,
4452471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4453471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x39 =
4454471d1714SBenjamin Tissoires 	{ "Wacom DTU710", 34080, 27660, 511, 0,
4455471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4456471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xC4 =
4457471d1714SBenjamin Tissoires 	{ "Wacom DTF521", 6282, 4762, 511, 0,
4458471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4459471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xC0 =
4460471d1714SBenjamin Tissoires 	{ "Wacom DTF720", 6858, 5506, 511, 0,
4461471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4462471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xC2 =
4463471d1714SBenjamin Tissoires 	{ "Wacom DTF720a", 6858, 5506, 511, 0,
4464471d1714SBenjamin Tissoires 	  PL, WACOM_PL_RES, WACOM_PL_RES };
4465471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x03 =
4466471d1714SBenjamin Tissoires 	{ "Wacom Cintiq Partner", 20480, 15360, 511, 0,
4467471d1714SBenjamin Tissoires 	  PTU, WACOM_PL_RES, WACOM_PL_RES };
4468471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x41 =
4469471d1714SBenjamin Tissoires 	{ "Wacom Intuos2 4x5", 12700, 10600, 1023, 31,
4470471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4471471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x42 =
4472471d1714SBenjamin Tissoires 	{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
4473471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4474471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x43 =
4475471d1714SBenjamin Tissoires 	{ "Wacom Intuos2 9x12", 30480, 24060, 1023, 31,
4476471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4477471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x44 =
4478471d1714SBenjamin Tissoires 	{ "Wacom Intuos2 12x12", 30480, 31680, 1023, 31,
4479471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4480471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x45 =
4481471d1714SBenjamin Tissoires 	{ "Wacom Intuos2 12x18", 45720, 31680, 1023, 31,
4482471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4483471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB0 =
4484471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 4x5", 25400, 20320, 1023, 63,
448570ee06c5SAaron Skomra 	  INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 };
4486471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB1 =
4487471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 6x8", 40640, 30480, 1023, 63,
448870ee06c5SAaron Skomra 	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4489471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB2 =
4490471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 9x12", 60960, 45720, 1023, 63,
449170ee06c5SAaron Skomra 	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4492471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB3 =
4493471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 12x12", 60960, 60960, 1023, 63,
449470ee06c5SAaron Skomra 	  INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4495471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB4 =
4496471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 12x19", 97536, 60960, 1023, 63,
449770ee06c5SAaron Skomra 	  INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4498471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB5 =
4499471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 6x11", 54204, 31750, 1023, 63,
450070ee06c5SAaron Skomra 	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4501471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB7 =
4502471d1714SBenjamin Tissoires 	{ "Wacom Intuos3 4x6", 31496, 19685, 1023, 63,
450370ee06c5SAaron Skomra 	  INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 };
4504471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB8 =
4505471d1714SBenjamin Tissoires 	{ "Wacom Intuos4 4x6", 31496, 19685, 2047, 63,
450670ee06c5SAaron Skomra 	  INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 };
4507471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xB9 =
4508471d1714SBenjamin Tissoires 	{ "Wacom Intuos4 6x9", 44704, 27940, 2047, 63,
450970ee06c5SAaron Skomra 	  INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4510471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xBA =
4511471d1714SBenjamin Tissoires 	{ "Wacom Intuos4 8x13", 65024, 40640, 2047, 63,
451270ee06c5SAaron Skomra 	  INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4513471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xBB =
4514471d1714SBenjamin Tissoires 	{ "Wacom Intuos4 12x19", 97536, 60960, 2047, 63,
451570ee06c5SAaron Skomra 	  INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4516471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xBC =
4517471d1714SBenjamin Tissoires 	{ "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
451870ee06c5SAaron Skomra 	  INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
451981af7e61SBenjamin Tissoires static const struct wacom_features wacom_features_0xBD =
452081af7e61SBenjamin Tissoires 	{ "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
452170ee06c5SAaron Skomra 	  INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4522471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x26 =
4523471d1714SBenjamin Tissoires 	{ "Wacom Intuos5 touch S", 31496, 19685, 2047, 63,
452470ee06c5SAaron Skomra 	  INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 };
4525471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x27 =
4526471d1714SBenjamin Tissoires 	{ "Wacom Intuos5 touch M", 44704, 27940, 2047, 63,
452770ee06c5SAaron Skomra 	  INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 };
4528471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x28 =
4529471d1714SBenjamin Tissoires 	{ "Wacom Intuos5 touch L", 65024, 40640, 2047, 63,
453070ee06c5SAaron Skomra 	  INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 };
4531471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x29 =
4532471d1714SBenjamin Tissoires 	{ "Wacom Intuos5 S", 31496, 19685, 2047, 63,
453370ee06c5SAaron Skomra 	  INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 };
4534471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x2A =
4535471d1714SBenjamin Tissoires 	{ "Wacom Intuos5 M", 44704, 27940, 2047, 63,
453670ee06c5SAaron Skomra 	  INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
4537471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x314 =
4538471d1714SBenjamin Tissoires 	{ "Wacom Intuos Pro S", 31496, 19685, 2047, 63,
453970ee06c5SAaron Skomra 	  INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16,
4540471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4541471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x315 =
4542471d1714SBenjamin Tissoires 	{ "Wacom Intuos Pro M", 44704, 27940, 2047, 63,
454370ee06c5SAaron Skomra 	  INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16,
4544471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4545471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x317 =
4546471d1714SBenjamin Tissoires 	{ "Wacom Intuos Pro L", 65024, 40640, 2047, 63,
454770ee06c5SAaron Skomra 	  INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16,
4548471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4549471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xF4 =
4550e779ef23SJason Gerecke 	{ "Wacom Cintiq 24HD", 104480, 65600, 2047, 63,
455170ee06c5SAaron Skomra 	  WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16,
4552e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4553fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4554471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xF8 =
4555e779ef23SJason Gerecke 	{ "Wacom Cintiq 24HD touch", 104480, 65600, 2047, 63, /* Pen */
455670ee06c5SAaron Skomra 	  WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16,
4557fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4558e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4559471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
4560471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xF6 =
4561471d1714SBenjamin Tissoires 	{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
4562471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
4563471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4564500d4160SPing Cheng static const struct wacom_features wacom_features_0x32A =
4565e779ef23SJason Gerecke 	{ "Wacom Cintiq 27QHD", 120140, 67920, 2047, 63,
456670ee06c5SAaron Skomra 	  WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0,
4567e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4568a7e6645eSPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4569500d4160SPing Cheng static const struct wacom_features wacom_features_0x32B =
4570e779ef23SJason Gerecke 	{ "Wacom Cintiq 27QHD touch", 120140, 67920, 2047, 63,
457170ee06c5SAaron Skomra 	  WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0,
4572500d4160SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4573e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4574500d4160SPing Cheng 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C };
4575500d4160SPing Cheng static const struct wacom_features wacom_features_0x32C =
4576500d4160SPing Cheng 	{ "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT,
4577500d4160SPing Cheng 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 };
4578471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x3F =
4579471d1714SBenjamin Tissoires 	{ "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
458070ee06c5SAaron Skomra 	  CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
4581471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xC5 =
4582471d1714SBenjamin Tissoires 	{ "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63,
458370ee06c5SAaron Skomra 	  WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 };
4584471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xC6 =
4585471d1714SBenjamin Tissoires 	{ "Wacom Cintiq 12WX", 53020, 33440, 1023, 63,
458670ee06c5SAaron Skomra 	  WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 };
4587471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x304 =
4588e779ef23SJason Gerecke 	{ "Wacom Cintiq 13HD", 59552, 33848, 1023, 63,
458970ee06c5SAaron Skomra 	  WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4590e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4591fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4592b4bf2120SPing Cheng static const struct wacom_features wacom_features_0x333 =
4593e779ef23SJason Gerecke 	{ "Wacom Cintiq 13HD touch", 59552, 33848, 2047, 63,
459470ee06c5SAaron Skomra 	  WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4595b4bf2120SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4596e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4597b4bf2120SPing Cheng 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 };
4598b4bf2120SPing Cheng static const struct wacom_features wacom_features_0x335 =
4599b4bf2120SPing Cheng 	{ "Wacom Cintiq 13HD touch", .type = WACOM_24HDT, /* Touch */
4600b4bf2120SPing Cheng 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x333, .touch_max = 10,
4601b4bf2120SPing Cheng 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4602471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xC7 =
4603471d1714SBenjamin Tissoires 	{ "Wacom DTU1931", 37832, 30305, 511, 0,
4604471d1714SBenjamin Tissoires 	  PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4605471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xCE =
4606471d1714SBenjamin Tissoires 	{ "Wacom DTU2231", 47864, 27011, 511, 0,
4607471d1714SBenjamin Tissoires 	  DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4608471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBMOUSE };
4609471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xF0 =
4610471d1714SBenjamin Tissoires 	{ "Wacom DTU1631", 34623, 19553, 511, 0,
4611471d1714SBenjamin Tissoires 	  DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4612471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xFB =
4613e779ef23SJason Gerecke 	{ "Wacom DTU1031", 22096, 13960, 511, 0,
461470ee06c5SAaron Skomra 	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
4615e779ef23SJason Gerecke 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4616fa770340SPing Cheng 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4617fff00bf8SPing Cheng static const struct wacom_features wacom_features_0x32F =
4618e779ef23SJason Gerecke 	{ "Wacom DTU1031X", 22672, 12928, 511, 0,
461970ee06c5SAaron Skomra 	  DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0,
4620e779ef23SJason Gerecke 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4621fff00bf8SPing Cheng 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4622007760cfSAaron Skomra static const struct wacom_features wacom_features_0x336 =
4623e779ef23SJason Gerecke 	{ "Wacom DTU1141", 23672, 13403, 1023, 0,
4624ff38e829SPing Cheng 	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
4625e779ef23SJason Gerecke 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4626ff38e829SPing Cheng 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4627471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x57 =
4628e779ef23SJason Gerecke 	{ "Wacom DTK2241", 95840, 54260, 2047, 63,
462970ee06c5SAaron Skomra 	  DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
4630e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4631fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4632471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x59 = /* Pen */
4633e779ef23SJason Gerecke 	{ "Wacom DTH2242", 95840, 54260, 2047, 63,
463470ee06c5SAaron Skomra 	  DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
4635fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4636e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4637471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
4638471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x5D = /* Touch */
4639471d1714SBenjamin Tissoires 	{ "Wacom DTH2242",       .type = WACOM_24HDT,
4640471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10,
4641471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4642471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xCC =
4643e779ef23SJason Gerecke 	{ "Wacom Cintiq 21UX2", 87200, 65600, 2047, 63,
464470ee06c5SAaron Skomra 	  WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
4645e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4646fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4647471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xFA =
4648e779ef23SJason Gerecke 	{ "Wacom Cintiq 22HD", 95840, 54260, 2047, 63,
464970ee06c5SAaron Skomra 	  WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
4650e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4651fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
4652471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x5B =
4653e779ef23SJason Gerecke 	{ "Wacom Cintiq 22HDT", 95840, 54260, 2047, 63,
465470ee06c5SAaron Skomra 	  WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
4655fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4656e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4657471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
4658471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x5E =
4659471d1714SBenjamin Tissoires 	{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
4660471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10,
4661471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4662471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x90 =
4663471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 90", 26202, 16325, 255, 0,
466429b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4665471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x93 =
4666471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 93", 26202, 16325, 255, 0,
466729b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4668471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x97 =
4669471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 97", 26202, 16325, 511, 0,
467029b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4671471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x9A =
4672471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 9A", 26202, 16325, 255, 0,
467329b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4674471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x9F =
4675471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 9F", 26202, 16325, 255, 0,
467629b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4677471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xE2 =
4678471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 E2", 26202, 16325, 255, 0,
4679471d1714SBenjamin Tissoires 	  TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4680471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xE3 =
4681471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 E3", 26202, 16325, 255, 0,
4682471d1714SBenjamin Tissoires 	  TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4683471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xE5 =
4684471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 E5", 26202, 16325, 255, 0,
4685471d1714SBenjamin Tissoires 	  MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4686471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xE6 =
4687471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 E6", 27760, 15694, 255, 0,
4688471d1714SBenjamin Tissoires 	  TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4689471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xEC =
4690471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 EC", 25710, 14500, 255, 0,
469129b9e148SJason Gerecke 	  TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4692471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xED =
4693471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 ED", 26202, 16325, 255, 0,
469429b9e148SJason Gerecke 	  TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4695471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xEF =
4696471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 EF", 26202, 16325, 255, 0,
469729b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4698471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x100 =
4699471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 100", 26202, 16325, 255, 0,
4700471d1714SBenjamin Tissoires 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4701471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x101 =
4702471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 101", 26202, 16325, 255, 0,
4703471d1714SBenjamin Tissoires 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4704471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x10D =
4705471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 10D", 26202, 16325, 255, 0,
4706471d1714SBenjamin Tissoires 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4707471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x10E =
4708471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 10E", 27760, 15694, 255, 0,
4709471d1714SBenjamin Tissoires 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4710471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x10F =
4711471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 10F", 27760, 15694, 255, 0,
4712471d1714SBenjamin Tissoires 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4713471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x116 =
4714471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 116", 26202, 16325, 255, 0,
471529b9e148SJason Gerecke 	  TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
4716aeaf50d4SJason Gerecke static const struct wacom_features wacom_features_0x12C =
4717aeaf50d4SJason Gerecke 	{ "Wacom ISDv4 12C", 27848, 15752, 2047, 0,
471829b9e148SJason Gerecke 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
4719471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x4001 =
4720471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 4001", 26202, 16325, 255, 0,
4721471d1714SBenjamin Tissoires 	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4722471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x4004 =
4723471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 4004", 11060, 6220, 255, 0,
4724471d1714SBenjamin Tissoires 	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4725471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x5000 =
4726471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 5000", 27848, 15752, 1023, 0,
4727471d1714SBenjamin Tissoires 	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4728471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x5002 =
4729471d1714SBenjamin Tissoires 	{ "Wacom ISDv4 5002", 29576, 16724, 1023, 0,
4730471d1714SBenjamin Tissoires 	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4731471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x47 =
4732471d1714SBenjamin Tissoires 	{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
4733471d1714SBenjamin Tissoires 	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4734471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x84 =
47353b164a00SPing Cheng 	{ "Wacom Wireless Receiver", .type = WIRELESS, .touch_max = 16 };
4736471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD0 =
4737471d1714SBenjamin Tissoires 	{ "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
47383b164a00SPing Cheng 	  BAMBOO_TOUCH, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4739471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD1 =
4740471d1714SBenjamin Tissoires 	{ "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
4741471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4742471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD2 =
4743471d1714SBenjamin Tissoires 	{ "Wacom Bamboo Craft", 14720, 9200, 1023, 31,
4744471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4745471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD3 =
4746471d1714SBenjamin Tissoires 	{ "Wacom Bamboo 2FG 6x8", 21648, 13700, 1023, 31,
4747471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4748471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD4 =
4749471d1714SBenjamin Tissoires 	{ "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
47503b164a00SPing Cheng 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4751471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD5 =
4752471d1714SBenjamin Tissoires 	{ "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
47533b164a00SPing Cheng 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4754471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD6 =
4755471d1714SBenjamin Tissoires 	{ "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
4756471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4757471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD7 =
4758471d1714SBenjamin Tissoires 	{ "Wacom BambooPT 2FG Small", 14720, 9200, 1023, 31,
4759471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4760471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xD8 =
4761471d1714SBenjamin Tissoires 	{ "Wacom Bamboo Comic 2FG", 21648, 13700, 1023, 31,
4762471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4763471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xDA =
4764471d1714SBenjamin Tissoires 	{ "Wacom Bamboo 2FG 4x5 SE", 14720, 9200, 1023, 31,
4765471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4766471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xDB =
4767471d1714SBenjamin Tissoires 	{ "Wacom Bamboo 2FG 6x8 SE", 21648, 13700, 1023, 31,
4768471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
4769471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xDD =
4770471d1714SBenjamin Tissoires         { "Wacom Bamboo Connect", 14720, 9200, 1023, 31,
4771471d1714SBenjamin Tissoires           BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4772471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xDE =
4773471d1714SBenjamin Tissoires         { "Wacom Bamboo 16FG 4x5", 14720, 9200, 1023, 31,
4774471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
4775471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0xDF =
4776471d1714SBenjamin Tissoires         { "Wacom Bamboo 16FG 6x8", 21648, 13700, 1023, 31,
4777471d1714SBenjamin Tissoires 	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
4778471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x300 =
4779471d1714SBenjamin Tissoires 	{ "Wacom Bamboo One S", 14720, 9225, 1023, 31,
47803b164a00SPing Cheng 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4781471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x301 =
4782471d1714SBenjamin Tissoires 	{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
4783b79cbc55SAaron Armstrong Skomra 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4784471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x302 =
4785471d1714SBenjamin Tissoires 	{ "Wacom Intuos PT S", 15200, 9500, 1023, 31,
4786471d1714SBenjamin Tissoires 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4787471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4788471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x303 =
4789471d1714SBenjamin Tissoires 	{ "Wacom Intuos PT M", 21600, 13500, 1023, 31,
4790471d1714SBenjamin Tissoires 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4791471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4792471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x30E =
4793471d1714SBenjamin Tissoires 	{ "Wacom Intuos S", 15200, 9500, 1023, 31,
4794471d1714SBenjamin Tissoires 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4795471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4796471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x6004 =
4797471d1714SBenjamin Tissoires 	{ "ISD-V4", 12800, 8000, 255, 0,
4798471d1714SBenjamin Tissoires 	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4799471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x307 =
4800e779ef23SJason Gerecke 	{ "Wacom ISDv5 307", 59552, 33848, 2047, 63,
480170ee06c5SAaron Skomra 	  CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4802fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4803e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4804471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
4805471d1714SBenjamin Tissoires static const struct wacom_features wacom_features_0x309 =
4806471d1714SBenjamin Tissoires 	{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
4807471d1714SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10,
4808471d1714SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
480989f2ab55SBenjamin Tissoires static const struct wacom_features wacom_features_0x30A =
4810e779ef23SJason Gerecke 	{ "Wacom ISDv5 30A", 59552, 33848, 2047, 63,
481170ee06c5SAaron Skomra 	  CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
4812fa770340SPing Cheng 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4813e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
481489f2ab55SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C };
481589f2ab55SBenjamin Tissoires static const struct wacom_features wacom_features_0x30C =
481689f2ab55SBenjamin Tissoires 	{ "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */
481789f2ab55SBenjamin Tissoires 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10,
481889f2ab55SBenjamin Tissoires 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
48198c97a765SBenjamin Tissoires static const struct wacom_features wacom_features_0x318 =
48208c97a765SBenjamin Tissoires 	{ "Wacom USB Bamboo PAD", 4095, 4095, /* Touch */
48218c97a765SBenjamin Tissoires 	  .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
48228c97a765SBenjamin Tissoires static const struct wacom_features wacom_features_0x319 =
48238c97a765SBenjamin Tissoires 	{ "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
48248c97a765SBenjamin Tissoires 	  .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
4825f7acb55cSJason Gerecke static const struct wacom_features wacom_features_0x325 =
4826f7acb55cSJason Gerecke 	{ "Wacom ISDv5 325", 59552, 33848, 2047, 63,
4827f7acb55cSJason Gerecke 	  CINTIQ_COMPANION_2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 11,
4828f7acb55cSJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4829e779ef23SJason Gerecke 	  WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
4830f7acb55cSJason Gerecke 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x326 };
4831f7acb55cSJason Gerecke static const struct wacom_features wacom_features_0x326 = /* Touch */
4832f7acb55cSJason Gerecke 	{ "Wacom ISDv5 326", .type = HID_GENERIC, .oVid = USB_VENDOR_ID_WACOM,
4833f7acb55cSJason Gerecke 	  .oPid = 0x325 };
4834fefb391fSPing Cheng static const struct wacom_features wacom_features_0x323 =
4835fefb391fSPing Cheng 	{ "Wacom Intuos P M", 21600, 13500, 1023, 31,
4836fefb391fSPing Cheng 	  INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4837fefb391fSPing Cheng 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
483872b236d6SAaron Skomra static const struct wacom_features wacom_features_0x331 =
48393b164a00SPing Cheng 	{ "Wacom Express Key Remote", .type = REMOTE,
48403b164a00SPing Cheng 	  .numbered_buttons = 18, .check_for_hid_type = true,
484172b236d6SAaron Skomra 	  .hid_type = HID_TYPE_USBNONE };
4842eda01dabSPing Cheng static const struct wacom_features wacom_features_0x33B =
4843eda01dabSPing Cheng 	{ "Wacom Intuos S 2", 15200, 9500, 2047, 63,
4844eda01dabSPing Cheng 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4845eda01dabSPing Cheng 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4846eda01dabSPing Cheng static const struct wacom_features wacom_features_0x33C =
4847eda01dabSPing Cheng 	{ "Wacom Intuos PT S 2", 15200, 9500, 2047, 63,
4848eda01dabSPing Cheng 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4849eda01dabSPing Cheng 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4850eda01dabSPing Cheng static const struct wacom_features wacom_features_0x33D =
4851eda01dabSPing Cheng 	{ "Wacom Intuos P M 2", 21600, 13500, 2047, 63,
4852eda01dabSPing Cheng 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
4853eda01dabSPing Cheng 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4854eda01dabSPing Cheng static const struct wacom_features wacom_features_0x33E =
4855eda01dabSPing Cheng 	{ "Wacom Intuos PT M 2", 21600, 13500, 2047, 63,
4856eda01dabSPing Cheng 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
4857eda01dabSPing Cheng 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
4858e1123fe9SPing Cheng static const struct wacom_features wacom_features_0x343 =
4859e779ef23SJason Gerecke 	{ "Wacom DTK1651", 34816, 19759, 1023, 0,
4860e1123fe9SPing Cheng 	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
4861e779ef23SJason Gerecke 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
4862e1123fe9SPing Cheng 	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
48634922cd26SJason Gerecke static const struct wacom_features wacom_features_0x360 =
48644922cd26SJason Gerecke 	{ "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
486549cc4c21SAaron Armstrong Skomra 	  INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
48664922cd26SJason Gerecke static const struct wacom_features wacom_features_0x361 =
48674922cd26SJason Gerecke 	{ "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
486849cc4c21SAaron Armstrong Skomra 	  INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
486987046b6cSAaron Armstrong Skomra static const struct wacom_features wacom_features_0x377 =
487087046b6cSAaron Armstrong Skomra 	{ "Wacom Intuos BT S", 15200, 9500, 4095, 63,
487187046b6cSAaron Armstrong Skomra 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
487287046b6cSAaron Armstrong Skomra static const struct wacom_features wacom_features_0x379 =
487387046b6cSAaron Armstrong Skomra 	{ "Wacom Intuos BT M", 21600, 13500, 4095, 63,
487487046b6cSAaron Armstrong Skomra 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
4875c9472189SJason Gerecke static const struct wacom_features wacom_features_0x37A =
4876c9472189SJason Gerecke 	{ "Wacom One by Wacom S", 15200, 9500, 2047, 63,
4877c9472189SJason Gerecke 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4878c9472189SJason Gerecke static const struct wacom_features wacom_features_0x37B =
4879c9472189SJason Gerecke 	{ "Wacom One by Wacom M", 21600, 13500, 2047, 63,
4880c9472189SJason Gerecke 	  BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
4881912c6aa6SAaron Armstrong Skomra static const struct wacom_features wacom_features_0x393 =
4882912c6aa6SAaron Armstrong Skomra 	{ "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
4883912c6aa6SAaron Armstrong Skomra 	  INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
4884912c6aa6SAaron Armstrong Skomra 	  .touch_max = 10 };
48850c8fbaa5SJoshua-Dickens static const struct wacom_features wacom_features_0x3c6 =
48860c8fbaa5SJoshua-Dickens 	{ "Wacom Intuos BT S", 15200, 9500, 4095, 63,
48870c8fbaa5SJoshua-Dickens 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
48880c8fbaa5SJoshua-Dickens static const struct wacom_features wacom_features_0x3c8 =
48890c8fbaa5SJoshua-Dickens 	{ "Wacom Intuos BT M", 21600, 13500, 4095, 63,
48900c8fbaa5SJoshua-Dickens 	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
48910627f3dfSPing Cheng static const struct wacom_features wacom_features_0x3dd =
48920627f3dfSPing Cheng 	{ "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
48930627f3dfSPing Cheng 	  INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
48940627f3dfSPing Cheng 	  .touch_max = 10 };
4895471d1714SBenjamin Tissoires 
48967704ac93SBenjamin Tissoires static const struct wacom_features wacom_features_HID_ANY_ID =
489741372d5dSJason Gerecke 	{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
48987704ac93SBenjamin Tissoires 
48991db1f392SJason Gerecke static const struct wacom_features wacom_features_0x94 =
49001db1f392SJason Gerecke 	{ "Wacom Bootloader", .type = BOOTLOADER };
49011db1f392SJason Gerecke 
4902471d1714SBenjamin Tissoires #define USB_DEVICE_WACOM(prod)						\
4903471d1714SBenjamin Tissoires 	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4904471d1714SBenjamin Tissoires 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4905471d1714SBenjamin Tissoires 
4906387142bbSBenjamin Tissoires #define BT_DEVICE_WACOM(prod)						\
4907387142bbSBenjamin Tissoires 	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4908387142bbSBenjamin Tissoires 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4909387142bbSBenjamin Tissoires 
4910eef23a84SMika Westerberg #define I2C_DEVICE_WACOM(prod)						\
4911eef23a84SMika Westerberg 	HID_DEVICE(BUS_I2C, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4912eef23a84SMika Westerberg 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4913eef23a84SMika Westerberg 
4914*9955d406SEven Xu #define PCI_DEVICE_WACOM(prod)						\
4915*9955d406SEven Xu 	HID_DEVICE(BUS_PCI, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
4916*9955d406SEven Xu 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4917*9955d406SEven Xu 
4918471d1714SBenjamin Tissoires #define USB_DEVICE_LENOVO(prod)					\
4919471d1714SBenjamin Tissoires 	HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),			\
4920471d1714SBenjamin Tissoires 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
4921471d1714SBenjamin Tissoires 
4922471d1714SBenjamin Tissoires const struct hid_device_id wacom_ids[] = {
4923471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x00) },
4924471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x03) },
4925471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x10) },
4926471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x11) },
4927471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x12) },
4928471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x13) },
4929471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x14) },
4930471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x15) },
4931471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x16) },
4932471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x17) },
4933471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x18) },
4934471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x19) },
4935471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x20) },
4936471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x21) },
4937471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x22) },
4938471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x23) },
4939471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x24) },
4940471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x26) },
4941471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x27) },
4942471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x28) },
4943471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x29) },
4944471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x2A) },
4945471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x30) },
4946471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x31) },
4947471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x32) },
4948471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x33) },
4949471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x34) },
4950471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x35) },
4951471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x37) },
4952471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x38) },
4953471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x39) },
4954471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x3F) },
4955471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x41) },
4956471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x42) },
4957471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x43) },
4958471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x44) },
4959471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x45) },
4960471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x47) },
4961471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x57) },
4962471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x59) },
4963471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x5B) },
4964471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x5D) },
4965471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x5E) },
4966471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x60) },
4967471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x61) },
4968471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x62) },
4969471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x63) },
4970471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x64) },
4971471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x65) },
4972471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x69) },
4973471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x6A) },
4974471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x6B) },
4975387142bbSBenjamin Tissoires 	{ BT_DEVICE_WACOM(0x81) },
4976471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x84) },
4977471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x90) },
4978471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x93) },
49791db1f392SJason Gerecke 	{ USB_DEVICE_WACOM(0x94) },
4980471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x97) },
4981471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x9A) },
4982471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x9F) },
4983471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB0) },
4984471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB1) },
4985471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB2) },
4986471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB3) },
4987471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB4) },
4988471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB5) },
4989471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB7) },
4990471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB8) },
4991471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xB9) },
4992471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xBA) },
4993471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xBB) },
4994471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xBC) },
499581af7e61SBenjamin Tissoires 	{ BT_DEVICE_WACOM(0xBD) },
4996471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xC0) },
4997471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xC2) },
4998471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xC4) },
4999471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xC5) },
5000471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xC6) },
5001471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xC7) },
5002471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xCC) },
5003471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xCE) },
5004471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD0) },
5005471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD1) },
5006471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD2) },
5007471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD3) },
5008471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD4) },
5009471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD5) },
5010471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD6) },
5011471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD7) },
5012471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xD8) },
5013471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xDA) },
5014471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xDB) },
5015471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xDD) },
5016471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xDE) },
5017471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xDF) },
5018471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xE2) },
5019471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xE3) },
5020471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xE5) },
5021471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xE6) },
5022471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xEC) },
5023471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xED) },
5024471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xEF) },
5025471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xF0) },
5026471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xF4) },
5027471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xF6) },
5028471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xF8) },
5029471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xFA) },
5030471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0xFB) },
5031471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x100) },
5032471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x101) },
5033471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x10D) },
5034471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x10E) },
5035471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x10F) },
5036471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x116) },
5037aeaf50d4SJason Gerecke 	{ USB_DEVICE_WACOM(0x12C) },
5038471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x300) },
5039471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x301) },
5040471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x302) },
5041471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x303) },
5042471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x304) },
5043471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x307) },
5044471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x309) },
504589f2ab55SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x30A) },
504689f2ab55SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x30C) },
5047471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x30E) },
5048471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x314) },
5049471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x315) },
5050471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x317) },
50518c97a765SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x318) },
50528c97a765SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x319) },
5053fefb391fSPing Cheng 	{ USB_DEVICE_WACOM(0x323) },
5054f7acb55cSJason Gerecke 	{ USB_DEVICE_WACOM(0x325) },
5055f7acb55cSJason Gerecke 	{ USB_DEVICE_WACOM(0x326) },
5056500d4160SPing Cheng 	{ USB_DEVICE_WACOM(0x32A) },
5057500d4160SPing Cheng 	{ USB_DEVICE_WACOM(0x32B) },
5058500d4160SPing Cheng 	{ USB_DEVICE_WACOM(0x32C) },
5059fff00bf8SPing Cheng 	{ USB_DEVICE_WACOM(0x32F) },
506072b236d6SAaron Skomra 	{ USB_DEVICE_WACOM(0x331) },
5061b4bf2120SPing Cheng 	{ USB_DEVICE_WACOM(0x333) },
5062b4bf2120SPing Cheng 	{ USB_DEVICE_WACOM(0x335) },
5063007760cfSAaron Skomra 	{ USB_DEVICE_WACOM(0x336) },
5064eda01dabSPing Cheng 	{ USB_DEVICE_WACOM(0x33B) },
5065eda01dabSPing Cheng 	{ USB_DEVICE_WACOM(0x33C) },
5066eda01dabSPing Cheng 	{ USB_DEVICE_WACOM(0x33D) },
5067eda01dabSPing Cheng 	{ USB_DEVICE_WACOM(0x33E) },
5068e1123fe9SPing Cheng 	{ USB_DEVICE_WACOM(0x343) },
50694922cd26SJason Gerecke 	{ BT_DEVICE_WACOM(0x360) },
50704922cd26SJason Gerecke 	{ BT_DEVICE_WACOM(0x361) },
507187046b6cSAaron Armstrong Skomra 	{ BT_DEVICE_WACOM(0x377) },
507287046b6cSAaron Armstrong Skomra 	{ BT_DEVICE_WACOM(0x379) },
5073c9472189SJason Gerecke 	{ USB_DEVICE_WACOM(0x37A) },
5074c9472189SJason Gerecke 	{ USB_DEVICE_WACOM(0x37B) },
5075912c6aa6SAaron Armstrong Skomra 	{ BT_DEVICE_WACOM(0x393) },
50760c8fbaa5SJoshua-Dickens 	{ BT_DEVICE_WACOM(0x3c6) },
50770c8fbaa5SJoshua-Dickens 	{ BT_DEVICE_WACOM(0x3c8) },
50780627f3dfSPing Cheng 	{ BT_DEVICE_WACOM(0x3dd) },
5079471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x4001) },
5080471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x4004) },
5081471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x5000) },
5082471d1714SBenjamin Tissoires 	{ USB_DEVICE_WACOM(0x5002) },
508300d6f227SBenjamin Tissoires 	{ USB_DEVICE_LENOVO(0x6004) },
50847704ac93SBenjamin Tissoires 
50857704ac93SBenjamin Tissoires 	{ USB_DEVICE_WACOM(HID_ANY_ID) },
5086eef23a84SMika Westerberg 	{ I2C_DEVICE_WACOM(HID_ANY_ID) },
5087*9955d406SEven Xu 	{ PCI_DEVICE_WACOM(HID_ANY_ID) },
5088b9e06256SJason Gerecke 	{ BT_DEVICE_WACOM(HID_ANY_ID) },
5089471d1714SBenjamin Tissoires 	{ }
5090471d1714SBenjamin Tissoires };
5091471d1714SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, wacom_ids);
5092