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