xref: /openbmc/linux/drivers/hid/wacom_sys.c (revision 471d17148c8b4174ac5f5283a73316d12c4379bc)
1*471d1714SBenjamin Tissoires /*
2*471d1714SBenjamin Tissoires  * drivers/input/tablet/wacom_sys.c
3*471d1714SBenjamin Tissoires  *
4*471d1714SBenjamin Tissoires  *  USB Wacom tablet support - system specific code
5*471d1714SBenjamin Tissoires  */
6*471d1714SBenjamin Tissoires 
7*471d1714SBenjamin Tissoires /*
8*471d1714SBenjamin Tissoires  * This program is free software; you can redistribute it and/or modify
9*471d1714SBenjamin Tissoires  * it under the terms of the GNU General Public License as published by
10*471d1714SBenjamin Tissoires  * the Free Software Foundation; either version 2 of the License, or
11*471d1714SBenjamin Tissoires  * (at your option) any later version.
12*471d1714SBenjamin Tissoires  */
13*471d1714SBenjamin Tissoires 
14*471d1714SBenjamin Tissoires #include "wacom_wac.h"
15*471d1714SBenjamin Tissoires #include "wacom.h"
16*471d1714SBenjamin Tissoires #include <linux/hid.h>
17*471d1714SBenjamin Tissoires 
18*471d1714SBenjamin Tissoires #define WAC_MSG_RETRIES		5
19*471d1714SBenjamin Tissoires 
20*471d1714SBenjamin Tissoires #define WAC_CMD_LED_CONTROL	0x20
21*471d1714SBenjamin Tissoires #define WAC_CMD_ICON_START	0x21
22*471d1714SBenjamin Tissoires #define WAC_CMD_ICON_XFER	0x23
23*471d1714SBenjamin Tissoires #define WAC_CMD_RETRIES		10
24*471d1714SBenjamin Tissoires 
25*471d1714SBenjamin Tissoires static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
26*471d1714SBenjamin Tissoires 			    void *buf, size_t size, unsigned int retries)
27*471d1714SBenjamin Tissoires {
28*471d1714SBenjamin Tissoires 	int retval;
29*471d1714SBenjamin Tissoires 
30*471d1714SBenjamin Tissoires 	do {
31*471d1714SBenjamin Tissoires 		retval = hid_hw_raw_request(hdev, id, buf, size, type,
32*471d1714SBenjamin Tissoires 				HID_REQ_GET_REPORT);
33*471d1714SBenjamin Tissoires 	} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
34*471d1714SBenjamin Tissoires 
35*471d1714SBenjamin Tissoires 	return retval;
36*471d1714SBenjamin Tissoires }
37*471d1714SBenjamin Tissoires 
38*471d1714SBenjamin Tissoires static int wacom_set_report(struct hid_device *hdev, u8 type, u8 id,
39*471d1714SBenjamin Tissoires 			    void *buf, size_t size, unsigned int retries)
40*471d1714SBenjamin Tissoires {
41*471d1714SBenjamin Tissoires 	int retval;
42*471d1714SBenjamin Tissoires 
43*471d1714SBenjamin Tissoires 	do {
44*471d1714SBenjamin Tissoires 		retval = hid_hw_raw_request(hdev, id, buf, size, type,
45*471d1714SBenjamin Tissoires 				HID_REQ_SET_REPORT);
46*471d1714SBenjamin Tissoires 	} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
47*471d1714SBenjamin Tissoires 
48*471d1714SBenjamin Tissoires 	return retval;
49*471d1714SBenjamin Tissoires }
50*471d1714SBenjamin Tissoires 
51*471d1714SBenjamin Tissoires static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
52*471d1714SBenjamin Tissoires 		u8 *raw_data, int size)
53*471d1714SBenjamin Tissoires {
54*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
55*471d1714SBenjamin Tissoires 
56*471d1714SBenjamin Tissoires 	if (size > WACOM_PKGLEN_MAX)
57*471d1714SBenjamin Tissoires 		return 1;
58*471d1714SBenjamin Tissoires 
59*471d1714SBenjamin Tissoires 	memcpy(wacom->wacom_wac.data, raw_data, size);
60*471d1714SBenjamin Tissoires 
61*471d1714SBenjamin Tissoires 	wacom_wac_irq(&wacom->wacom_wac, size);
62*471d1714SBenjamin Tissoires 
63*471d1714SBenjamin Tissoires 	return 0;
64*471d1714SBenjamin Tissoires }
65*471d1714SBenjamin Tissoires 
66*471d1714SBenjamin Tissoires static int wacom_open(struct input_dev *dev)
67*471d1714SBenjamin Tissoires {
68*471d1714SBenjamin Tissoires 	struct wacom *wacom = input_get_drvdata(dev);
69*471d1714SBenjamin Tissoires 	int retval;
70*471d1714SBenjamin Tissoires 
71*471d1714SBenjamin Tissoires 	mutex_lock(&wacom->lock);
72*471d1714SBenjamin Tissoires 	retval = hid_hw_open(wacom->hdev);
73*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom->lock);
74*471d1714SBenjamin Tissoires 
75*471d1714SBenjamin Tissoires 	return retval;
76*471d1714SBenjamin Tissoires }
77*471d1714SBenjamin Tissoires 
78*471d1714SBenjamin Tissoires static void wacom_close(struct input_dev *dev)
79*471d1714SBenjamin Tissoires {
80*471d1714SBenjamin Tissoires 	struct wacom *wacom = input_get_drvdata(dev);
81*471d1714SBenjamin Tissoires 
82*471d1714SBenjamin Tissoires 	mutex_lock(&wacom->lock);
83*471d1714SBenjamin Tissoires 	hid_hw_close(wacom->hdev);
84*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom->lock);
85*471d1714SBenjamin Tissoires }
86*471d1714SBenjamin Tissoires 
87*471d1714SBenjamin Tissoires /*
88*471d1714SBenjamin Tissoires  * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res.
89*471d1714SBenjamin Tissoires  */
90*471d1714SBenjamin Tissoires static int wacom_calc_hid_res(int logical_extents, int physical_extents,
91*471d1714SBenjamin Tissoires 			       unsigned unit, int exponent)
92*471d1714SBenjamin Tissoires {
93*471d1714SBenjamin Tissoires 	struct hid_field field = {
94*471d1714SBenjamin Tissoires 		.logical_maximum = logical_extents,
95*471d1714SBenjamin Tissoires 		.physical_maximum = physical_extents,
96*471d1714SBenjamin Tissoires 		.unit = unit,
97*471d1714SBenjamin Tissoires 		.unit_exponent = exponent,
98*471d1714SBenjamin Tissoires 	};
99*471d1714SBenjamin Tissoires 
100*471d1714SBenjamin Tissoires 	return hidinput_calc_abs_res(&field, ABS_X);
101*471d1714SBenjamin Tissoires }
102*471d1714SBenjamin Tissoires 
103*471d1714SBenjamin Tissoires static void wacom_feature_mapping(struct hid_device *hdev,
104*471d1714SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage)
105*471d1714SBenjamin Tissoires {
106*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
107*471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->wacom_wac.features;
108*471d1714SBenjamin Tissoires 
109*471d1714SBenjamin Tissoires 	switch (usage->hid) {
110*471d1714SBenjamin Tissoires 	case HID_DG_CONTACTMAX:
111*471d1714SBenjamin Tissoires 		/* leave touch_max as is if predefined */
112*471d1714SBenjamin Tissoires 		if (!features->touch_max)
113*471d1714SBenjamin Tissoires 			features->touch_max = field->value[0];
114*471d1714SBenjamin Tissoires 		break;
115*471d1714SBenjamin Tissoires 	}
116*471d1714SBenjamin Tissoires }
117*471d1714SBenjamin Tissoires 
118*471d1714SBenjamin Tissoires /*
119*471d1714SBenjamin Tissoires  * Interface Descriptor of wacom devices can be incomplete and
120*471d1714SBenjamin Tissoires  * inconsistent so wacom_features table is used to store stylus
121*471d1714SBenjamin Tissoires  * device's packet lengths, various maximum values, and tablet
122*471d1714SBenjamin Tissoires  * resolution based on product ID's.
123*471d1714SBenjamin Tissoires  *
124*471d1714SBenjamin Tissoires  * For devices that contain 2 interfaces, wacom_features table is
125*471d1714SBenjamin Tissoires  * inaccurate for the touch interface.  Since the Interface Descriptor
126*471d1714SBenjamin Tissoires  * for touch interfaces has pretty complete data, this function exists
127*471d1714SBenjamin Tissoires  * to query tablet for this missing information instead of hard coding in
128*471d1714SBenjamin Tissoires  * an additional table.
129*471d1714SBenjamin Tissoires  *
130*471d1714SBenjamin Tissoires  * A typical Interface Descriptor for a stylus will contain a
131*471d1714SBenjamin Tissoires  * boot mouse application collection that is not of interest and this
132*471d1714SBenjamin Tissoires  * function will ignore it.
133*471d1714SBenjamin Tissoires  *
134*471d1714SBenjamin Tissoires  * It also contains a digitizer application collection that also is not
135*471d1714SBenjamin Tissoires  * of interest since any information it contains would be duplicate
136*471d1714SBenjamin Tissoires  * of what is in wacom_features. Usually it defines a report of an array
137*471d1714SBenjamin Tissoires  * of bytes that could be used as max length of the stylus packet returned.
138*471d1714SBenjamin Tissoires  * If it happens to define a Digitizer-Stylus Physical Collection then
139*471d1714SBenjamin Tissoires  * the X and Y logical values contain valid data but it is ignored.
140*471d1714SBenjamin Tissoires  *
141*471d1714SBenjamin Tissoires  * A typical Interface Descriptor for a touch interface will contain a
142*471d1714SBenjamin Tissoires  * Digitizer-Finger Physical Collection which will define both logical
143*471d1714SBenjamin Tissoires  * X/Y maximum as well as the physical size of tablet. Since touch
144*471d1714SBenjamin Tissoires  * interfaces haven't supported pressure or distance, this is enough
145*471d1714SBenjamin Tissoires  * information to override invalid values in the wacom_features table.
146*471d1714SBenjamin Tissoires  *
147*471d1714SBenjamin Tissoires  * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
148*471d1714SBenjamin Tissoires  * data. We deal with them after returning from this function.
149*471d1714SBenjamin Tissoires  */
150*471d1714SBenjamin Tissoires static void wacom_usage_mapping(struct hid_device *hdev,
151*471d1714SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage)
152*471d1714SBenjamin Tissoires {
153*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
154*471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->wacom_wac.features;
155*471d1714SBenjamin Tissoires 	bool finger = (field->logical == HID_DG_FINGER) ||
156*471d1714SBenjamin Tissoires 		      (field->physical == HID_DG_FINGER);
157*471d1714SBenjamin Tissoires 	bool pen = (field->logical == HID_DG_STYLUS) ||
158*471d1714SBenjamin Tissoires 		   (field->physical == HID_DG_STYLUS);
159*471d1714SBenjamin Tissoires 
160*471d1714SBenjamin Tissoires 	/*
161*471d1714SBenjamin Tissoires 	* Requiring Stylus Usage will ignore boot mouse
162*471d1714SBenjamin Tissoires 	* X/Y values and some cases of invalid Digitizer X/Y
163*471d1714SBenjamin Tissoires 	* values commonly reported.
164*471d1714SBenjamin Tissoires 	*/
165*471d1714SBenjamin Tissoires 	if (!pen && !finger)
166*471d1714SBenjamin Tissoires 		return;
167*471d1714SBenjamin Tissoires 
168*471d1714SBenjamin Tissoires 	if (finger && !features->touch_max)
169*471d1714SBenjamin Tissoires 		/* touch device at least supports one touch point */
170*471d1714SBenjamin Tissoires 		features->touch_max = 1;
171*471d1714SBenjamin Tissoires 
172*471d1714SBenjamin Tissoires 	switch (usage->hid) {
173*471d1714SBenjamin Tissoires 	case HID_GD_X:
174*471d1714SBenjamin Tissoires 		features->x_max = field->logical_maximum;
175*471d1714SBenjamin Tissoires 		if (finger) {
176*471d1714SBenjamin Tissoires 			features->device_type = BTN_TOOL_FINGER;
177*471d1714SBenjamin Tissoires 			features->x_phy = field->physical_maximum;
178*471d1714SBenjamin Tissoires 			if (features->type != BAMBOO_PT) {
179*471d1714SBenjamin Tissoires 				features->unit = field->unit;
180*471d1714SBenjamin Tissoires 				features->unitExpo = field->unit_exponent;
181*471d1714SBenjamin Tissoires 			}
182*471d1714SBenjamin Tissoires 		} else {
183*471d1714SBenjamin Tissoires 			features->device_type = BTN_TOOL_PEN;
184*471d1714SBenjamin Tissoires 		}
185*471d1714SBenjamin Tissoires 		break;
186*471d1714SBenjamin Tissoires 	case HID_GD_Y:
187*471d1714SBenjamin Tissoires 		features->y_max = field->logical_maximum;
188*471d1714SBenjamin Tissoires 		if (finger) {
189*471d1714SBenjamin Tissoires 			features->y_phy = field->physical_maximum;
190*471d1714SBenjamin Tissoires 			if (features->type != BAMBOO_PT) {
191*471d1714SBenjamin Tissoires 				features->unit = field->unit;
192*471d1714SBenjamin Tissoires 				features->unitExpo = field->unit_exponent;
193*471d1714SBenjamin Tissoires 			}
194*471d1714SBenjamin Tissoires 		}
195*471d1714SBenjamin Tissoires 		break;
196*471d1714SBenjamin Tissoires 	case HID_DG_TIPPRESSURE:
197*471d1714SBenjamin Tissoires 		if (pen)
198*471d1714SBenjamin Tissoires 			features->pressure_max = field->logical_maximum;
199*471d1714SBenjamin Tissoires 		break;
200*471d1714SBenjamin Tissoires 	}
201*471d1714SBenjamin Tissoires }
202*471d1714SBenjamin Tissoires 
203*471d1714SBenjamin Tissoires static void wacom_parse_hid(struct hid_device *hdev,
204*471d1714SBenjamin Tissoires 			   struct wacom_features *features)
205*471d1714SBenjamin Tissoires {
206*471d1714SBenjamin Tissoires 	struct hid_report_enum *rep_enum;
207*471d1714SBenjamin Tissoires 	struct hid_report *hreport;
208*471d1714SBenjamin Tissoires 	int i, j;
209*471d1714SBenjamin Tissoires 
210*471d1714SBenjamin Tissoires 	/* check features first */
211*471d1714SBenjamin Tissoires 	rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
212*471d1714SBenjamin Tissoires 	list_for_each_entry(hreport, &rep_enum->report_list, list) {
213*471d1714SBenjamin Tissoires 		for (i = 0; i < hreport->maxfield; i++) {
214*471d1714SBenjamin Tissoires 			/* Ignore if report count is out of bounds. */
215*471d1714SBenjamin Tissoires 			if (hreport->field[i]->report_count < 1)
216*471d1714SBenjamin Tissoires 				continue;
217*471d1714SBenjamin Tissoires 
218*471d1714SBenjamin Tissoires 			for (j = 0; j < hreport->field[i]->maxusage; j++) {
219*471d1714SBenjamin Tissoires 				wacom_feature_mapping(hdev, hreport->field[i],
220*471d1714SBenjamin Tissoires 						hreport->field[i]->usage + j);
221*471d1714SBenjamin Tissoires 			}
222*471d1714SBenjamin Tissoires 		}
223*471d1714SBenjamin Tissoires 	}
224*471d1714SBenjamin Tissoires 
225*471d1714SBenjamin Tissoires 	/* now check the input usages */
226*471d1714SBenjamin Tissoires 	rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
227*471d1714SBenjamin Tissoires 	list_for_each_entry(hreport, &rep_enum->report_list, list) {
228*471d1714SBenjamin Tissoires 
229*471d1714SBenjamin Tissoires 		if (!hreport->maxfield)
230*471d1714SBenjamin Tissoires 			continue;
231*471d1714SBenjamin Tissoires 
232*471d1714SBenjamin Tissoires 		for (i = 0; i < hreport->maxfield; i++)
233*471d1714SBenjamin Tissoires 			for (j = 0; j < hreport->field[i]->maxusage; j++)
234*471d1714SBenjamin Tissoires 				wacom_usage_mapping(hdev, hreport->field[i],
235*471d1714SBenjamin Tissoires 						hreport->field[i]->usage + j);
236*471d1714SBenjamin Tissoires 	}
237*471d1714SBenjamin Tissoires }
238*471d1714SBenjamin Tissoires 
239*471d1714SBenjamin Tissoires static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
240*471d1714SBenjamin Tissoires 		int length, int mode)
241*471d1714SBenjamin Tissoires {
242*471d1714SBenjamin Tissoires 	unsigned char *rep_data;
243*471d1714SBenjamin Tissoires 	int error = -ENOMEM, limit = 0;
244*471d1714SBenjamin Tissoires 
245*471d1714SBenjamin Tissoires 	rep_data = kzalloc(length, GFP_KERNEL);
246*471d1714SBenjamin Tissoires 	if (!rep_data)
247*471d1714SBenjamin Tissoires 		return error;
248*471d1714SBenjamin Tissoires 
249*471d1714SBenjamin Tissoires 	do {
250*471d1714SBenjamin Tissoires 		rep_data[0] = report_id;
251*471d1714SBenjamin Tissoires 		rep_data[1] = mode;
252*471d1714SBenjamin Tissoires 
253*471d1714SBenjamin Tissoires 		error = wacom_set_report(hdev, HID_FEATURE_REPORT,
254*471d1714SBenjamin Tissoires 		                         report_id, rep_data, length, 1);
255*471d1714SBenjamin Tissoires 		if (error >= 0)
256*471d1714SBenjamin Tissoires 			error = wacom_get_report(hdev, HID_FEATURE_REPORT,
257*471d1714SBenjamin Tissoires 			                         report_id, rep_data, length, 1);
258*471d1714SBenjamin Tissoires 	} while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
259*471d1714SBenjamin Tissoires 
260*471d1714SBenjamin Tissoires 	kfree(rep_data);
261*471d1714SBenjamin Tissoires 
262*471d1714SBenjamin Tissoires 	return error < 0 ? error : 0;
263*471d1714SBenjamin Tissoires }
264*471d1714SBenjamin Tissoires 
265*471d1714SBenjamin Tissoires /*
266*471d1714SBenjamin Tissoires  * Switch the tablet into its most-capable mode. Wacom tablets are
267*471d1714SBenjamin Tissoires  * typically configured to power-up in a mode which sends mouse-like
268*471d1714SBenjamin Tissoires  * reports to the OS. To get absolute position, pressure data, etc.
269*471d1714SBenjamin Tissoires  * from the tablet, it is necessary to switch the tablet out of this
270*471d1714SBenjamin Tissoires  * mode and into one which sends the full range of tablet data.
271*471d1714SBenjamin Tissoires  */
272*471d1714SBenjamin Tissoires static int wacom_query_tablet_data(struct hid_device *hdev,
273*471d1714SBenjamin Tissoires 		struct wacom_features *features)
274*471d1714SBenjamin Tissoires {
275*471d1714SBenjamin Tissoires 	if (features->device_type == BTN_TOOL_FINGER) {
276*471d1714SBenjamin Tissoires 		if (features->type > TABLETPC) {
277*471d1714SBenjamin Tissoires 			/* MT Tablet PC touch */
278*471d1714SBenjamin Tissoires 			return wacom_set_device_mode(hdev, 3, 4, 4);
279*471d1714SBenjamin Tissoires 		}
280*471d1714SBenjamin Tissoires 		else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
281*471d1714SBenjamin Tissoires 			return wacom_set_device_mode(hdev, 18, 3, 2);
282*471d1714SBenjamin Tissoires 		}
283*471d1714SBenjamin Tissoires 	} else if (features->device_type == BTN_TOOL_PEN) {
284*471d1714SBenjamin Tissoires 		if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
285*471d1714SBenjamin Tissoires 			return wacom_set_device_mode(hdev, 2, 2, 2);
286*471d1714SBenjamin Tissoires 		}
287*471d1714SBenjamin Tissoires 	}
288*471d1714SBenjamin Tissoires 
289*471d1714SBenjamin Tissoires 	return 0;
290*471d1714SBenjamin Tissoires }
291*471d1714SBenjamin Tissoires 
292*471d1714SBenjamin Tissoires static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
293*471d1714SBenjamin Tissoires 					 struct wacom_features *features)
294*471d1714SBenjamin Tissoires {
295*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
296*471d1714SBenjamin Tissoires 	struct usb_interface *intf = wacom->intf;
297*471d1714SBenjamin Tissoires 
298*471d1714SBenjamin Tissoires 	/* default features */
299*471d1714SBenjamin Tissoires 	features->device_type = BTN_TOOL_PEN;
300*471d1714SBenjamin Tissoires 	features->x_fuzz = 4;
301*471d1714SBenjamin Tissoires 	features->y_fuzz = 4;
302*471d1714SBenjamin Tissoires 	features->pressure_fuzz = 0;
303*471d1714SBenjamin Tissoires 	features->distance_fuzz = 0;
304*471d1714SBenjamin Tissoires 
305*471d1714SBenjamin Tissoires 	/*
306*471d1714SBenjamin Tissoires 	 * The wireless device HID is basic and layout conflicts with
307*471d1714SBenjamin Tissoires 	 * other tablets (monitor and touch interface can look like pen).
308*471d1714SBenjamin Tissoires 	 * Skip the query for this type and modify defaults based on
309*471d1714SBenjamin Tissoires 	 * interface number.
310*471d1714SBenjamin Tissoires 	 */
311*471d1714SBenjamin Tissoires 	if (features->type == WIRELESS) {
312*471d1714SBenjamin Tissoires 		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
313*471d1714SBenjamin Tissoires 			features->device_type = 0;
314*471d1714SBenjamin Tissoires 		} else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
315*471d1714SBenjamin Tissoires 			features->device_type = BTN_TOOL_FINGER;
316*471d1714SBenjamin Tissoires 			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
317*471d1714SBenjamin Tissoires 		}
318*471d1714SBenjamin Tissoires 	}
319*471d1714SBenjamin Tissoires 
320*471d1714SBenjamin Tissoires 	/* only devices that support touch need to retrieve the info */
321*471d1714SBenjamin Tissoires 	if (features->type < BAMBOO_PT)
322*471d1714SBenjamin Tissoires 		return;
323*471d1714SBenjamin Tissoires 
324*471d1714SBenjamin Tissoires 	wacom_parse_hid(hdev, features);
325*471d1714SBenjamin Tissoires }
326*471d1714SBenjamin Tissoires 
327*471d1714SBenjamin Tissoires struct wacom_hdev_data {
328*471d1714SBenjamin Tissoires 	struct list_head list;
329*471d1714SBenjamin Tissoires 	struct kref kref;
330*471d1714SBenjamin Tissoires 	struct hid_device *dev;
331*471d1714SBenjamin Tissoires 	struct wacom_shared shared;
332*471d1714SBenjamin Tissoires };
333*471d1714SBenjamin Tissoires 
334*471d1714SBenjamin Tissoires static LIST_HEAD(wacom_udev_list);
335*471d1714SBenjamin Tissoires static DEFINE_MUTEX(wacom_udev_list_lock);
336*471d1714SBenjamin Tissoires 
337*471d1714SBenjamin Tissoires static bool wacom_are_sibling(struct hid_device *hdev,
338*471d1714SBenjamin Tissoires 		struct hid_device *sibling)
339*471d1714SBenjamin Tissoires {
340*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
341*471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->wacom_wac.features;
342*471d1714SBenjamin Tissoires 	int vid = features->oVid;
343*471d1714SBenjamin Tissoires 	int pid = features->oPid;
344*471d1714SBenjamin Tissoires 	int n1,n2;
345*471d1714SBenjamin Tissoires 
346*471d1714SBenjamin Tissoires 	if (vid == 0 && pid == 0) {
347*471d1714SBenjamin Tissoires 		vid = hdev->vendor;
348*471d1714SBenjamin Tissoires 		pid = hdev->product;
349*471d1714SBenjamin Tissoires 	}
350*471d1714SBenjamin Tissoires 
351*471d1714SBenjamin Tissoires 	if (vid != sibling->vendor || pid != sibling->product)
352*471d1714SBenjamin Tissoires 		return false;
353*471d1714SBenjamin Tissoires 
354*471d1714SBenjamin Tissoires 	/* Compare the physical path. */
355*471d1714SBenjamin Tissoires 	n1 = strrchr(hdev->phys, '.') - hdev->phys;
356*471d1714SBenjamin Tissoires 	n2 = strrchr(sibling->phys, '.') - sibling->phys;
357*471d1714SBenjamin Tissoires 	if (n1 != n2 || n1 <= 0 || n2 <= 0)
358*471d1714SBenjamin Tissoires 		return false;
359*471d1714SBenjamin Tissoires 
360*471d1714SBenjamin Tissoires 	return !strncmp(hdev->phys, sibling->phys, n1);
361*471d1714SBenjamin Tissoires }
362*471d1714SBenjamin Tissoires 
363*471d1714SBenjamin Tissoires static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
364*471d1714SBenjamin Tissoires {
365*471d1714SBenjamin Tissoires 	struct wacom_hdev_data *data;
366*471d1714SBenjamin Tissoires 
367*471d1714SBenjamin Tissoires 	list_for_each_entry(data, &wacom_udev_list, list) {
368*471d1714SBenjamin Tissoires 		if (wacom_are_sibling(hdev, data->dev)) {
369*471d1714SBenjamin Tissoires 			kref_get(&data->kref);
370*471d1714SBenjamin Tissoires 			return data;
371*471d1714SBenjamin Tissoires 		}
372*471d1714SBenjamin Tissoires 	}
373*471d1714SBenjamin Tissoires 
374*471d1714SBenjamin Tissoires 	return NULL;
375*471d1714SBenjamin Tissoires }
376*471d1714SBenjamin Tissoires 
377*471d1714SBenjamin Tissoires static int wacom_add_shared_data(struct hid_device *hdev)
378*471d1714SBenjamin Tissoires {
379*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
380*471d1714SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
381*471d1714SBenjamin Tissoires 	struct wacom_hdev_data *data;
382*471d1714SBenjamin Tissoires 	int retval = 0;
383*471d1714SBenjamin Tissoires 
384*471d1714SBenjamin Tissoires 	mutex_lock(&wacom_udev_list_lock);
385*471d1714SBenjamin Tissoires 
386*471d1714SBenjamin Tissoires 	data = wacom_get_hdev_data(hdev);
387*471d1714SBenjamin Tissoires 	if (!data) {
388*471d1714SBenjamin Tissoires 		data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
389*471d1714SBenjamin Tissoires 		if (!data) {
390*471d1714SBenjamin Tissoires 			retval = -ENOMEM;
391*471d1714SBenjamin Tissoires 			goto out;
392*471d1714SBenjamin Tissoires 		}
393*471d1714SBenjamin Tissoires 
394*471d1714SBenjamin Tissoires 		kref_init(&data->kref);
395*471d1714SBenjamin Tissoires 		data->dev = hdev;
396*471d1714SBenjamin Tissoires 		list_add_tail(&data->list, &wacom_udev_list);
397*471d1714SBenjamin Tissoires 	}
398*471d1714SBenjamin Tissoires 
399*471d1714SBenjamin Tissoires 	wacom_wac->shared = &data->shared;
400*471d1714SBenjamin Tissoires 
401*471d1714SBenjamin Tissoires out:
402*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom_udev_list_lock);
403*471d1714SBenjamin Tissoires 	return retval;
404*471d1714SBenjamin Tissoires }
405*471d1714SBenjamin Tissoires 
406*471d1714SBenjamin Tissoires static void wacom_release_shared_data(struct kref *kref)
407*471d1714SBenjamin Tissoires {
408*471d1714SBenjamin Tissoires 	struct wacom_hdev_data *data =
409*471d1714SBenjamin Tissoires 		container_of(kref, struct wacom_hdev_data, kref);
410*471d1714SBenjamin Tissoires 
411*471d1714SBenjamin Tissoires 	mutex_lock(&wacom_udev_list_lock);
412*471d1714SBenjamin Tissoires 	list_del(&data->list);
413*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom_udev_list_lock);
414*471d1714SBenjamin Tissoires 
415*471d1714SBenjamin Tissoires 	kfree(data);
416*471d1714SBenjamin Tissoires }
417*471d1714SBenjamin Tissoires 
418*471d1714SBenjamin Tissoires static void wacom_remove_shared_data(struct wacom_wac *wacom)
419*471d1714SBenjamin Tissoires {
420*471d1714SBenjamin Tissoires 	struct wacom_hdev_data *data;
421*471d1714SBenjamin Tissoires 
422*471d1714SBenjamin Tissoires 	if (wacom->shared) {
423*471d1714SBenjamin Tissoires 		data = container_of(wacom->shared, struct wacom_hdev_data, shared);
424*471d1714SBenjamin Tissoires 		kref_put(&data->kref, wacom_release_shared_data);
425*471d1714SBenjamin Tissoires 		wacom->shared = NULL;
426*471d1714SBenjamin Tissoires 	}
427*471d1714SBenjamin Tissoires }
428*471d1714SBenjamin Tissoires 
429*471d1714SBenjamin Tissoires static int wacom_led_control(struct wacom *wacom)
430*471d1714SBenjamin Tissoires {
431*471d1714SBenjamin Tissoires 	unsigned char *buf;
432*471d1714SBenjamin Tissoires 	int retval;
433*471d1714SBenjamin Tissoires 
434*471d1714SBenjamin Tissoires 	buf = kzalloc(9, GFP_KERNEL);
435*471d1714SBenjamin Tissoires 	if (!buf)
436*471d1714SBenjamin Tissoires 		return -ENOMEM;
437*471d1714SBenjamin Tissoires 
438*471d1714SBenjamin Tissoires 	if (wacom->wacom_wac.features.type >= INTUOS5S &&
439*471d1714SBenjamin Tissoires 	    wacom->wacom_wac.features.type <= INTUOSPL) {
440*471d1714SBenjamin Tissoires 		/*
441*471d1714SBenjamin Tissoires 		 * Touch Ring and crop mark LED luminance may take on
442*471d1714SBenjamin Tissoires 		 * one of four values:
443*471d1714SBenjamin Tissoires 		 *    0 = Low; 1 = Medium; 2 = High; 3 = Off
444*471d1714SBenjamin Tissoires 		 */
445*471d1714SBenjamin Tissoires 		int ring_led = wacom->led.select[0] & 0x03;
446*471d1714SBenjamin Tissoires 		int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
447*471d1714SBenjamin Tissoires 		int crop_lum = 0;
448*471d1714SBenjamin Tissoires 
449*471d1714SBenjamin Tissoires 		buf[0] = WAC_CMD_LED_CONTROL;
450*471d1714SBenjamin Tissoires 		buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
451*471d1714SBenjamin Tissoires 	}
452*471d1714SBenjamin Tissoires 	else {
453*471d1714SBenjamin Tissoires 		int led = wacom->led.select[0] | 0x4;
454*471d1714SBenjamin Tissoires 
455*471d1714SBenjamin Tissoires 		if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
456*471d1714SBenjamin Tissoires 		    wacom->wacom_wac.features.type == WACOM_24HD)
457*471d1714SBenjamin Tissoires 			led |= (wacom->led.select[1] << 4) | 0x40;
458*471d1714SBenjamin Tissoires 
459*471d1714SBenjamin Tissoires 		buf[0] = WAC_CMD_LED_CONTROL;
460*471d1714SBenjamin Tissoires 		buf[1] = led;
461*471d1714SBenjamin Tissoires 		buf[2] = wacom->led.llv;
462*471d1714SBenjamin Tissoires 		buf[3] = wacom->led.hlv;
463*471d1714SBenjamin Tissoires 		buf[4] = wacom->led.img_lum;
464*471d1714SBenjamin Tissoires 	}
465*471d1714SBenjamin Tissoires 
466*471d1714SBenjamin Tissoires 	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
467*471d1714SBenjamin Tissoires 				  WAC_CMD_LED_CONTROL, buf, 9, WAC_CMD_RETRIES);
468*471d1714SBenjamin Tissoires 	kfree(buf);
469*471d1714SBenjamin Tissoires 
470*471d1714SBenjamin Tissoires 	return retval;
471*471d1714SBenjamin Tissoires }
472*471d1714SBenjamin Tissoires 
473*471d1714SBenjamin Tissoires static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
474*471d1714SBenjamin Tissoires {
475*471d1714SBenjamin Tissoires 	unsigned char *buf;
476*471d1714SBenjamin Tissoires 	int i, retval;
477*471d1714SBenjamin Tissoires 
478*471d1714SBenjamin Tissoires 	buf = kzalloc(259, GFP_KERNEL);
479*471d1714SBenjamin Tissoires 	if (!buf)
480*471d1714SBenjamin Tissoires 		return -ENOMEM;
481*471d1714SBenjamin Tissoires 
482*471d1714SBenjamin Tissoires 	/* Send 'start' command */
483*471d1714SBenjamin Tissoires 	buf[0] = WAC_CMD_ICON_START;
484*471d1714SBenjamin Tissoires 	buf[1] = 1;
485*471d1714SBenjamin Tissoires 	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
486*471d1714SBenjamin Tissoires 				  WAC_CMD_ICON_START, buf, 2, WAC_CMD_RETRIES);
487*471d1714SBenjamin Tissoires 	if (retval < 0)
488*471d1714SBenjamin Tissoires 		goto out;
489*471d1714SBenjamin Tissoires 
490*471d1714SBenjamin Tissoires 	buf[0] = WAC_CMD_ICON_XFER;
491*471d1714SBenjamin Tissoires 	buf[1] = button_id & 0x07;
492*471d1714SBenjamin Tissoires 	for (i = 0; i < 4; i++) {
493*471d1714SBenjamin Tissoires 		buf[2] = i;
494*471d1714SBenjamin Tissoires 		memcpy(buf + 3, img + i * 256, 256);
495*471d1714SBenjamin Tissoires 
496*471d1714SBenjamin Tissoires 		retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
497*471d1714SBenjamin Tissoires 					  WAC_CMD_ICON_XFER,
498*471d1714SBenjamin Tissoires 					  buf, 259, WAC_CMD_RETRIES);
499*471d1714SBenjamin Tissoires 		if (retval < 0)
500*471d1714SBenjamin Tissoires 			break;
501*471d1714SBenjamin Tissoires 	}
502*471d1714SBenjamin Tissoires 
503*471d1714SBenjamin Tissoires 	/* Send 'stop' */
504*471d1714SBenjamin Tissoires 	buf[0] = WAC_CMD_ICON_START;
505*471d1714SBenjamin Tissoires 	buf[1] = 0;
506*471d1714SBenjamin Tissoires 	wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, WAC_CMD_ICON_START,
507*471d1714SBenjamin Tissoires 			 buf, 2, WAC_CMD_RETRIES);
508*471d1714SBenjamin Tissoires 
509*471d1714SBenjamin Tissoires out:
510*471d1714SBenjamin Tissoires 	kfree(buf);
511*471d1714SBenjamin Tissoires 	return retval;
512*471d1714SBenjamin Tissoires }
513*471d1714SBenjamin Tissoires 
514*471d1714SBenjamin Tissoires static ssize_t wacom_led_select_store(struct device *dev, int set_id,
515*471d1714SBenjamin Tissoires 				      const char *buf, size_t count)
516*471d1714SBenjamin Tissoires {
517*471d1714SBenjamin Tissoires 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
518*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
519*471d1714SBenjamin Tissoires 	unsigned int id;
520*471d1714SBenjamin Tissoires 	int err;
521*471d1714SBenjamin Tissoires 
522*471d1714SBenjamin Tissoires 	err = kstrtouint(buf, 10, &id);
523*471d1714SBenjamin Tissoires 	if (err)
524*471d1714SBenjamin Tissoires 		return err;
525*471d1714SBenjamin Tissoires 
526*471d1714SBenjamin Tissoires 	mutex_lock(&wacom->lock);
527*471d1714SBenjamin Tissoires 
528*471d1714SBenjamin Tissoires 	wacom->led.select[set_id] = id & 0x3;
529*471d1714SBenjamin Tissoires 	err = wacom_led_control(wacom);
530*471d1714SBenjamin Tissoires 
531*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom->lock);
532*471d1714SBenjamin Tissoires 
533*471d1714SBenjamin Tissoires 	return err < 0 ? err : count;
534*471d1714SBenjamin Tissoires }
535*471d1714SBenjamin Tissoires 
536*471d1714SBenjamin Tissoires #define DEVICE_LED_SELECT_ATTR(SET_ID)					\
537*471d1714SBenjamin Tissoires static ssize_t wacom_led##SET_ID##_select_store(struct device *dev,	\
538*471d1714SBenjamin Tissoires 	struct device_attribute *attr, const char *buf, size_t count)	\
539*471d1714SBenjamin Tissoires {									\
540*471d1714SBenjamin Tissoires 	return wacom_led_select_store(dev, SET_ID, buf, count);		\
541*471d1714SBenjamin Tissoires }									\
542*471d1714SBenjamin Tissoires static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,	\
543*471d1714SBenjamin Tissoires 	struct device_attribute *attr, char *buf)			\
544*471d1714SBenjamin Tissoires {									\
545*471d1714SBenjamin Tissoires 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
546*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);			\
547*471d1714SBenjamin Tissoires 	return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]);	\
548*471d1714SBenjamin Tissoires }									\
549*471d1714SBenjamin Tissoires static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR,	\
550*471d1714SBenjamin Tissoires 		    wacom_led##SET_ID##_select_show,			\
551*471d1714SBenjamin Tissoires 		    wacom_led##SET_ID##_select_store)
552*471d1714SBenjamin Tissoires 
553*471d1714SBenjamin Tissoires DEVICE_LED_SELECT_ATTR(0);
554*471d1714SBenjamin Tissoires DEVICE_LED_SELECT_ATTR(1);
555*471d1714SBenjamin Tissoires 
556*471d1714SBenjamin Tissoires static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
557*471d1714SBenjamin Tissoires 				     const char *buf, size_t count)
558*471d1714SBenjamin Tissoires {
559*471d1714SBenjamin Tissoires 	unsigned int value;
560*471d1714SBenjamin Tissoires 	int err;
561*471d1714SBenjamin Tissoires 
562*471d1714SBenjamin Tissoires 	err = kstrtouint(buf, 10, &value);
563*471d1714SBenjamin Tissoires 	if (err)
564*471d1714SBenjamin Tissoires 		return err;
565*471d1714SBenjamin Tissoires 
566*471d1714SBenjamin Tissoires 	mutex_lock(&wacom->lock);
567*471d1714SBenjamin Tissoires 
568*471d1714SBenjamin Tissoires 	*dest = value & 0x7f;
569*471d1714SBenjamin Tissoires 	err = wacom_led_control(wacom);
570*471d1714SBenjamin Tissoires 
571*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom->lock);
572*471d1714SBenjamin Tissoires 
573*471d1714SBenjamin Tissoires 	return err < 0 ? err : count;
574*471d1714SBenjamin Tissoires }
575*471d1714SBenjamin Tissoires 
576*471d1714SBenjamin Tissoires #define DEVICE_LUMINANCE_ATTR(name, field)				\
577*471d1714SBenjamin Tissoires static ssize_t wacom_##name##_luminance_store(struct device *dev,	\
578*471d1714SBenjamin Tissoires 	struct device_attribute *attr, const char *buf, size_t count)	\
579*471d1714SBenjamin Tissoires {									\
580*471d1714SBenjamin Tissoires 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
581*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);			\
582*471d1714SBenjamin Tissoires 									\
583*471d1714SBenjamin Tissoires 	return wacom_luminance_store(wacom, &wacom->led.field,		\
584*471d1714SBenjamin Tissoires 				     buf, count);			\
585*471d1714SBenjamin Tissoires }									\
586*471d1714SBenjamin Tissoires static DEVICE_ATTR(name##_luminance, S_IWUSR,				\
587*471d1714SBenjamin Tissoires 		   NULL, wacom_##name##_luminance_store)
588*471d1714SBenjamin Tissoires 
589*471d1714SBenjamin Tissoires DEVICE_LUMINANCE_ATTR(status0, llv);
590*471d1714SBenjamin Tissoires DEVICE_LUMINANCE_ATTR(status1, hlv);
591*471d1714SBenjamin Tissoires DEVICE_LUMINANCE_ATTR(buttons, img_lum);
592*471d1714SBenjamin Tissoires 
593*471d1714SBenjamin Tissoires static ssize_t wacom_button_image_store(struct device *dev, int button_id,
594*471d1714SBenjamin Tissoires 					const char *buf, size_t count)
595*471d1714SBenjamin Tissoires {
596*471d1714SBenjamin Tissoires 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
597*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
598*471d1714SBenjamin Tissoires 	int err;
599*471d1714SBenjamin Tissoires 
600*471d1714SBenjamin Tissoires 	if (count != 1024)
601*471d1714SBenjamin Tissoires 		return -EINVAL;
602*471d1714SBenjamin Tissoires 
603*471d1714SBenjamin Tissoires 	mutex_lock(&wacom->lock);
604*471d1714SBenjamin Tissoires 
605*471d1714SBenjamin Tissoires 	err = wacom_led_putimage(wacom, button_id, buf);
606*471d1714SBenjamin Tissoires 
607*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom->lock);
608*471d1714SBenjamin Tissoires 
609*471d1714SBenjamin Tissoires 	return err < 0 ? err : count;
610*471d1714SBenjamin Tissoires }
611*471d1714SBenjamin Tissoires 
612*471d1714SBenjamin Tissoires #define DEVICE_BTNIMG_ATTR(BUTTON_ID)					\
613*471d1714SBenjamin Tissoires static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev,	\
614*471d1714SBenjamin Tissoires 	struct device_attribute *attr, const char *buf, size_t count)	\
615*471d1714SBenjamin Tissoires {									\
616*471d1714SBenjamin Tissoires 	return wacom_button_image_store(dev, BUTTON_ID, buf, count);	\
617*471d1714SBenjamin Tissoires }									\
618*471d1714SBenjamin Tissoires static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR,			\
619*471d1714SBenjamin Tissoires 		   NULL, wacom_btnimg##BUTTON_ID##_store)
620*471d1714SBenjamin Tissoires 
621*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(0);
622*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(1);
623*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(2);
624*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(3);
625*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(4);
626*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(5);
627*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(6);
628*471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(7);
629*471d1714SBenjamin Tissoires 
630*471d1714SBenjamin Tissoires static struct attribute *cintiq_led_attrs[] = {
631*471d1714SBenjamin Tissoires 	&dev_attr_status_led0_select.attr,
632*471d1714SBenjamin Tissoires 	&dev_attr_status_led1_select.attr,
633*471d1714SBenjamin Tissoires 	NULL
634*471d1714SBenjamin Tissoires };
635*471d1714SBenjamin Tissoires 
636*471d1714SBenjamin Tissoires static struct attribute_group cintiq_led_attr_group = {
637*471d1714SBenjamin Tissoires 	.name = "wacom_led",
638*471d1714SBenjamin Tissoires 	.attrs = cintiq_led_attrs,
639*471d1714SBenjamin Tissoires };
640*471d1714SBenjamin Tissoires 
641*471d1714SBenjamin Tissoires static struct attribute *intuos4_led_attrs[] = {
642*471d1714SBenjamin Tissoires 	&dev_attr_status0_luminance.attr,
643*471d1714SBenjamin Tissoires 	&dev_attr_status1_luminance.attr,
644*471d1714SBenjamin Tissoires 	&dev_attr_status_led0_select.attr,
645*471d1714SBenjamin Tissoires 	&dev_attr_buttons_luminance.attr,
646*471d1714SBenjamin Tissoires 	&dev_attr_button0_rawimg.attr,
647*471d1714SBenjamin Tissoires 	&dev_attr_button1_rawimg.attr,
648*471d1714SBenjamin Tissoires 	&dev_attr_button2_rawimg.attr,
649*471d1714SBenjamin Tissoires 	&dev_attr_button3_rawimg.attr,
650*471d1714SBenjamin Tissoires 	&dev_attr_button4_rawimg.attr,
651*471d1714SBenjamin Tissoires 	&dev_attr_button5_rawimg.attr,
652*471d1714SBenjamin Tissoires 	&dev_attr_button6_rawimg.attr,
653*471d1714SBenjamin Tissoires 	&dev_attr_button7_rawimg.attr,
654*471d1714SBenjamin Tissoires 	NULL
655*471d1714SBenjamin Tissoires };
656*471d1714SBenjamin Tissoires 
657*471d1714SBenjamin Tissoires static struct attribute_group intuos4_led_attr_group = {
658*471d1714SBenjamin Tissoires 	.name = "wacom_led",
659*471d1714SBenjamin Tissoires 	.attrs = intuos4_led_attrs,
660*471d1714SBenjamin Tissoires };
661*471d1714SBenjamin Tissoires 
662*471d1714SBenjamin Tissoires static struct attribute *intuos5_led_attrs[] = {
663*471d1714SBenjamin Tissoires 	&dev_attr_status0_luminance.attr,
664*471d1714SBenjamin Tissoires 	&dev_attr_status_led0_select.attr,
665*471d1714SBenjamin Tissoires 	NULL
666*471d1714SBenjamin Tissoires };
667*471d1714SBenjamin Tissoires 
668*471d1714SBenjamin Tissoires static struct attribute_group intuos5_led_attr_group = {
669*471d1714SBenjamin Tissoires 	.name = "wacom_led",
670*471d1714SBenjamin Tissoires 	.attrs = intuos5_led_attrs,
671*471d1714SBenjamin Tissoires };
672*471d1714SBenjamin Tissoires 
673*471d1714SBenjamin Tissoires static int wacom_initialize_leds(struct wacom *wacom)
674*471d1714SBenjamin Tissoires {
675*471d1714SBenjamin Tissoires 	int error;
676*471d1714SBenjamin Tissoires 
677*471d1714SBenjamin Tissoires 	/* Initialize default values */
678*471d1714SBenjamin Tissoires 	switch (wacom->wacom_wac.features.type) {
679*471d1714SBenjamin Tissoires 	case INTUOS4S:
680*471d1714SBenjamin Tissoires 	case INTUOS4:
681*471d1714SBenjamin Tissoires 	case INTUOS4L:
682*471d1714SBenjamin Tissoires 		wacom->led.select[0] = 0;
683*471d1714SBenjamin Tissoires 		wacom->led.select[1] = 0;
684*471d1714SBenjamin Tissoires 		wacom->led.llv = 10;
685*471d1714SBenjamin Tissoires 		wacom->led.hlv = 20;
686*471d1714SBenjamin Tissoires 		wacom->led.img_lum = 10;
687*471d1714SBenjamin Tissoires 		error = sysfs_create_group(&wacom->hdev->dev.kobj,
688*471d1714SBenjamin Tissoires 					   &intuos4_led_attr_group);
689*471d1714SBenjamin Tissoires 		break;
690*471d1714SBenjamin Tissoires 
691*471d1714SBenjamin Tissoires 	case WACOM_24HD:
692*471d1714SBenjamin Tissoires 	case WACOM_21UX2:
693*471d1714SBenjamin Tissoires 		wacom->led.select[0] = 0;
694*471d1714SBenjamin Tissoires 		wacom->led.select[1] = 0;
695*471d1714SBenjamin Tissoires 		wacom->led.llv = 0;
696*471d1714SBenjamin Tissoires 		wacom->led.hlv = 0;
697*471d1714SBenjamin Tissoires 		wacom->led.img_lum = 0;
698*471d1714SBenjamin Tissoires 
699*471d1714SBenjamin Tissoires 		error = sysfs_create_group(&wacom->hdev->dev.kobj,
700*471d1714SBenjamin Tissoires 					   &cintiq_led_attr_group);
701*471d1714SBenjamin Tissoires 		break;
702*471d1714SBenjamin Tissoires 
703*471d1714SBenjamin Tissoires 	case INTUOS5S:
704*471d1714SBenjamin Tissoires 	case INTUOS5:
705*471d1714SBenjamin Tissoires 	case INTUOS5L:
706*471d1714SBenjamin Tissoires 	case INTUOSPS:
707*471d1714SBenjamin Tissoires 	case INTUOSPM:
708*471d1714SBenjamin Tissoires 	case INTUOSPL:
709*471d1714SBenjamin Tissoires 		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) {
710*471d1714SBenjamin Tissoires 			wacom->led.select[0] = 0;
711*471d1714SBenjamin Tissoires 			wacom->led.select[1] = 0;
712*471d1714SBenjamin Tissoires 			wacom->led.llv = 32;
713*471d1714SBenjamin Tissoires 			wacom->led.hlv = 0;
714*471d1714SBenjamin Tissoires 			wacom->led.img_lum = 0;
715*471d1714SBenjamin Tissoires 
716*471d1714SBenjamin Tissoires 			error = sysfs_create_group(&wacom->hdev->dev.kobj,
717*471d1714SBenjamin Tissoires 						  &intuos5_led_attr_group);
718*471d1714SBenjamin Tissoires 		} else
719*471d1714SBenjamin Tissoires 			return 0;
720*471d1714SBenjamin Tissoires 		break;
721*471d1714SBenjamin Tissoires 
722*471d1714SBenjamin Tissoires 	default:
723*471d1714SBenjamin Tissoires 		return 0;
724*471d1714SBenjamin Tissoires 	}
725*471d1714SBenjamin Tissoires 
726*471d1714SBenjamin Tissoires 	if (error) {
727*471d1714SBenjamin Tissoires 		hid_err(wacom->hdev,
728*471d1714SBenjamin Tissoires 			"cannot create sysfs group err: %d\n", error);
729*471d1714SBenjamin Tissoires 		return error;
730*471d1714SBenjamin Tissoires 	}
731*471d1714SBenjamin Tissoires 	wacom_led_control(wacom);
732*471d1714SBenjamin Tissoires 
733*471d1714SBenjamin Tissoires 	return 0;
734*471d1714SBenjamin Tissoires }
735*471d1714SBenjamin Tissoires 
736*471d1714SBenjamin Tissoires static void wacom_destroy_leds(struct wacom *wacom)
737*471d1714SBenjamin Tissoires {
738*471d1714SBenjamin Tissoires 	switch (wacom->wacom_wac.features.type) {
739*471d1714SBenjamin Tissoires 	case INTUOS4S:
740*471d1714SBenjamin Tissoires 	case INTUOS4:
741*471d1714SBenjamin Tissoires 	case INTUOS4L:
742*471d1714SBenjamin Tissoires 		sysfs_remove_group(&wacom->hdev->dev.kobj,
743*471d1714SBenjamin Tissoires 				   &intuos4_led_attr_group);
744*471d1714SBenjamin Tissoires 		break;
745*471d1714SBenjamin Tissoires 
746*471d1714SBenjamin Tissoires 	case WACOM_24HD:
747*471d1714SBenjamin Tissoires 	case WACOM_21UX2:
748*471d1714SBenjamin Tissoires 		sysfs_remove_group(&wacom->hdev->dev.kobj,
749*471d1714SBenjamin Tissoires 				   &cintiq_led_attr_group);
750*471d1714SBenjamin Tissoires 		break;
751*471d1714SBenjamin Tissoires 
752*471d1714SBenjamin Tissoires 	case INTUOS5S:
753*471d1714SBenjamin Tissoires 	case INTUOS5:
754*471d1714SBenjamin Tissoires 	case INTUOS5L:
755*471d1714SBenjamin Tissoires 	case INTUOSPS:
756*471d1714SBenjamin Tissoires 	case INTUOSPM:
757*471d1714SBenjamin Tissoires 	case INTUOSPL:
758*471d1714SBenjamin Tissoires 		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN)
759*471d1714SBenjamin Tissoires 			sysfs_remove_group(&wacom->hdev->dev.kobj,
760*471d1714SBenjamin Tissoires 					   &intuos5_led_attr_group);
761*471d1714SBenjamin Tissoires 		break;
762*471d1714SBenjamin Tissoires 	}
763*471d1714SBenjamin Tissoires }
764*471d1714SBenjamin Tissoires 
765*471d1714SBenjamin Tissoires static enum power_supply_property wacom_battery_props[] = {
766*471d1714SBenjamin Tissoires 	POWER_SUPPLY_PROP_SCOPE,
767*471d1714SBenjamin Tissoires 	POWER_SUPPLY_PROP_CAPACITY
768*471d1714SBenjamin Tissoires };
769*471d1714SBenjamin Tissoires 
770*471d1714SBenjamin Tissoires static int wacom_battery_get_property(struct power_supply *psy,
771*471d1714SBenjamin Tissoires 				      enum power_supply_property psp,
772*471d1714SBenjamin Tissoires 				      union power_supply_propval *val)
773*471d1714SBenjamin Tissoires {
774*471d1714SBenjamin Tissoires 	struct wacom *wacom = container_of(psy, struct wacom, battery);
775*471d1714SBenjamin Tissoires 	int ret = 0;
776*471d1714SBenjamin Tissoires 
777*471d1714SBenjamin Tissoires 	switch (psp) {
778*471d1714SBenjamin Tissoires 		case POWER_SUPPLY_PROP_SCOPE:
779*471d1714SBenjamin Tissoires 			val->intval = POWER_SUPPLY_SCOPE_DEVICE;
780*471d1714SBenjamin Tissoires 			break;
781*471d1714SBenjamin Tissoires 		case POWER_SUPPLY_PROP_CAPACITY:
782*471d1714SBenjamin Tissoires 			val->intval =
783*471d1714SBenjamin Tissoires 				wacom->wacom_wac.battery_capacity * 100 / 31;
784*471d1714SBenjamin Tissoires 			break;
785*471d1714SBenjamin Tissoires 		default:
786*471d1714SBenjamin Tissoires 			ret = -EINVAL;
787*471d1714SBenjamin Tissoires 			break;
788*471d1714SBenjamin Tissoires 	}
789*471d1714SBenjamin Tissoires 
790*471d1714SBenjamin Tissoires 	return ret;
791*471d1714SBenjamin Tissoires }
792*471d1714SBenjamin Tissoires 
793*471d1714SBenjamin Tissoires static int wacom_initialize_battery(struct wacom *wacom)
794*471d1714SBenjamin Tissoires {
795*471d1714SBenjamin Tissoires 	int error = 0;
796*471d1714SBenjamin Tissoires 
797*471d1714SBenjamin Tissoires 	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR) {
798*471d1714SBenjamin Tissoires 		wacom->battery.properties = wacom_battery_props;
799*471d1714SBenjamin Tissoires 		wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
800*471d1714SBenjamin Tissoires 		wacom->battery.get_property = wacom_battery_get_property;
801*471d1714SBenjamin Tissoires 		wacom->battery.name = "wacom_battery";
802*471d1714SBenjamin Tissoires 		wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
803*471d1714SBenjamin Tissoires 		wacom->battery.use_for_apm = 0;
804*471d1714SBenjamin Tissoires 
805*471d1714SBenjamin Tissoires 		error = power_supply_register(&wacom->hdev->dev,
806*471d1714SBenjamin Tissoires 					      &wacom->battery);
807*471d1714SBenjamin Tissoires 
808*471d1714SBenjamin Tissoires 		if (!error)
809*471d1714SBenjamin Tissoires 			power_supply_powers(&wacom->battery,
810*471d1714SBenjamin Tissoires 					    &wacom->hdev->dev);
811*471d1714SBenjamin Tissoires 	}
812*471d1714SBenjamin Tissoires 
813*471d1714SBenjamin Tissoires 	return error;
814*471d1714SBenjamin Tissoires }
815*471d1714SBenjamin Tissoires 
816*471d1714SBenjamin Tissoires static void wacom_destroy_battery(struct wacom *wacom)
817*471d1714SBenjamin Tissoires {
818*471d1714SBenjamin Tissoires 	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR &&
819*471d1714SBenjamin Tissoires 	    wacom->battery.dev) {
820*471d1714SBenjamin Tissoires 		power_supply_unregister(&wacom->battery);
821*471d1714SBenjamin Tissoires 		wacom->battery.dev = NULL;
822*471d1714SBenjamin Tissoires 	}
823*471d1714SBenjamin Tissoires }
824*471d1714SBenjamin Tissoires 
825*471d1714SBenjamin Tissoires static struct input_dev *wacom_allocate_input(struct wacom *wacom)
826*471d1714SBenjamin Tissoires {
827*471d1714SBenjamin Tissoires 	struct input_dev *input_dev;
828*471d1714SBenjamin Tissoires 	struct hid_device *hdev = wacom->hdev;
829*471d1714SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
830*471d1714SBenjamin Tissoires 
831*471d1714SBenjamin Tissoires 	input_dev = input_allocate_device();
832*471d1714SBenjamin Tissoires 	if (!input_dev)
833*471d1714SBenjamin Tissoires 		return NULL;
834*471d1714SBenjamin Tissoires 
835*471d1714SBenjamin Tissoires 	input_dev->name = wacom_wac->name;
836*471d1714SBenjamin Tissoires 	input_dev->phys = hdev->phys;
837*471d1714SBenjamin Tissoires 	input_dev->dev.parent = &hdev->dev;
838*471d1714SBenjamin Tissoires 	input_dev->open = wacom_open;
839*471d1714SBenjamin Tissoires 	input_dev->close = wacom_close;
840*471d1714SBenjamin Tissoires 	input_dev->uniq = hdev->uniq;
841*471d1714SBenjamin Tissoires 	input_dev->id.bustype = hdev->bus;
842*471d1714SBenjamin Tissoires 	input_dev->id.vendor  = hdev->vendor;
843*471d1714SBenjamin Tissoires 	input_dev->id.product = hdev->product;
844*471d1714SBenjamin Tissoires 	input_dev->id.version = hdev->version;
845*471d1714SBenjamin Tissoires 	input_set_drvdata(input_dev, wacom);
846*471d1714SBenjamin Tissoires 
847*471d1714SBenjamin Tissoires 	return input_dev;
848*471d1714SBenjamin Tissoires }
849*471d1714SBenjamin Tissoires 
850*471d1714SBenjamin Tissoires static void wacom_unregister_inputs(struct wacom *wacom)
851*471d1714SBenjamin Tissoires {
852*471d1714SBenjamin Tissoires 	if (wacom->wacom_wac.input)
853*471d1714SBenjamin Tissoires 		input_unregister_device(wacom->wacom_wac.input);
854*471d1714SBenjamin Tissoires 	if (wacom->wacom_wac.pad_input)
855*471d1714SBenjamin Tissoires 		input_unregister_device(wacom->wacom_wac.pad_input);
856*471d1714SBenjamin Tissoires 	wacom->wacom_wac.input = NULL;
857*471d1714SBenjamin Tissoires 	wacom->wacom_wac.pad_input = NULL;
858*471d1714SBenjamin Tissoires }
859*471d1714SBenjamin Tissoires 
860*471d1714SBenjamin Tissoires static int wacom_register_inputs(struct wacom *wacom)
861*471d1714SBenjamin Tissoires {
862*471d1714SBenjamin Tissoires 	struct input_dev *input_dev, *pad_input_dev;
863*471d1714SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
864*471d1714SBenjamin Tissoires 	int error;
865*471d1714SBenjamin Tissoires 
866*471d1714SBenjamin Tissoires 	input_dev = wacom_allocate_input(wacom);
867*471d1714SBenjamin Tissoires 	pad_input_dev = wacom_allocate_input(wacom);
868*471d1714SBenjamin Tissoires 	if (!input_dev || !pad_input_dev) {
869*471d1714SBenjamin Tissoires 		error = -ENOMEM;
870*471d1714SBenjamin Tissoires 		goto fail1;
871*471d1714SBenjamin Tissoires 	}
872*471d1714SBenjamin Tissoires 
873*471d1714SBenjamin Tissoires 	wacom_wac->input = input_dev;
874*471d1714SBenjamin Tissoires 	wacom_wac->pad_input = pad_input_dev;
875*471d1714SBenjamin Tissoires 	wacom_wac->pad_input->name = wacom_wac->pad_name;
876*471d1714SBenjamin Tissoires 
877*471d1714SBenjamin Tissoires 	error = wacom_setup_input_capabilities(input_dev, wacom_wac);
878*471d1714SBenjamin Tissoires 	if (error)
879*471d1714SBenjamin Tissoires 		goto fail2;
880*471d1714SBenjamin Tissoires 
881*471d1714SBenjamin Tissoires 	error = input_register_device(input_dev);
882*471d1714SBenjamin Tissoires 	if (error)
883*471d1714SBenjamin Tissoires 		goto fail2;
884*471d1714SBenjamin Tissoires 
885*471d1714SBenjamin Tissoires 	error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
886*471d1714SBenjamin Tissoires 	if (error) {
887*471d1714SBenjamin Tissoires 		/* no pad in use on this interface */
888*471d1714SBenjamin Tissoires 		input_free_device(pad_input_dev);
889*471d1714SBenjamin Tissoires 		wacom_wac->pad_input = NULL;
890*471d1714SBenjamin Tissoires 		pad_input_dev = NULL;
891*471d1714SBenjamin Tissoires 	} else {
892*471d1714SBenjamin Tissoires 		error = input_register_device(pad_input_dev);
893*471d1714SBenjamin Tissoires 		if (error)
894*471d1714SBenjamin Tissoires 			goto fail3;
895*471d1714SBenjamin Tissoires 	}
896*471d1714SBenjamin Tissoires 
897*471d1714SBenjamin Tissoires 	return 0;
898*471d1714SBenjamin Tissoires 
899*471d1714SBenjamin Tissoires fail3:
900*471d1714SBenjamin Tissoires 	input_unregister_device(input_dev);
901*471d1714SBenjamin Tissoires 	input_dev = NULL;
902*471d1714SBenjamin Tissoires fail2:
903*471d1714SBenjamin Tissoires 	wacom_wac->input = NULL;
904*471d1714SBenjamin Tissoires 	wacom_wac->pad_input = NULL;
905*471d1714SBenjamin Tissoires fail1:
906*471d1714SBenjamin Tissoires 	if (input_dev)
907*471d1714SBenjamin Tissoires 		input_free_device(input_dev);
908*471d1714SBenjamin Tissoires 	if (pad_input_dev)
909*471d1714SBenjamin Tissoires 		input_free_device(pad_input_dev);
910*471d1714SBenjamin Tissoires 	return error;
911*471d1714SBenjamin Tissoires }
912*471d1714SBenjamin Tissoires 
913*471d1714SBenjamin Tissoires static void wacom_wireless_work(struct work_struct *work)
914*471d1714SBenjamin Tissoires {
915*471d1714SBenjamin Tissoires 	struct wacom *wacom = container_of(work, struct wacom, work);
916*471d1714SBenjamin Tissoires 	struct usb_device *usbdev = wacom->usbdev;
917*471d1714SBenjamin Tissoires 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
918*471d1714SBenjamin Tissoires 	struct hid_device *hdev1, *hdev2;
919*471d1714SBenjamin Tissoires 	struct wacom *wacom1, *wacom2;
920*471d1714SBenjamin Tissoires 	struct wacom_wac *wacom_wac1, *wacom_wac2;
921*471d1714SBenjamin Tissoires 	int error;
922*471d1714SBenjamin Tissoires 
923*471d1714SBenjamin Tissoires 	/*
924*471d1714SBenjamin Tissoires 	 * Regardless if this is a disconnect or a new tablet,
925*471d1714SBenjamin Tissoires 	 * remove any existing input and battery devices.
926*471d1714SBenjamin Tissoires 	 */
927*471d1714SBenjamin Tissoires 
928*471d1714SBenjamin Tissoires 	wacom_destroy_battery(wacom);
929*471d1714SBenjamin Tissoires 
930*471d1714SBenjamin Tissoires 	/* Stylus interface */
931*471d1714SBenjamin Tissoires 	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
932*471d1714SBenjamin Tissoires 	wacom1 = hid_get_drvdata(hdev1);
933*471d1714SBenjamin Tissoires 	wacom_wac1 = &(wacom1->wacom_wac);
934*471d1714SBenjamin Tissoires 	wacom_unregister_inputs(wacom1);
935*471d1714SBenjamin Tissoires 
936*471d1714SBenjamin Tissoires 	/* Touch interface */
937*471d1714SBenjamin Tissoires 	hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
938*471d1714SBenjamin Tissoires 	wacom2 = hid_get_drvdata(hdev2);
939*471d1714SBenjamin Tissoires 	wacom_wac2 = &(wacom2->wacom_wac);
940*471d1714SBenjamin Tissoires 	wacom_unregister_inputs(wacom2);
941*471d1714SBenjamin Tissoires 
942*471d1714SBenjamin Tissoires 	if (wacom_wac->pid == 0) {
943*471d1714SBenjamin Tissoires 		hid_info(wacom->hdev, "wireless tablet disconnected\n");
944*471d1714SBenjamin Tissoires 	} else {
945*471d1714SBenjamin Tissoires 		const struct hid_device_id *id = wacom_ids;
946*471d1714SBenjamin Tissoires 
947*471d1714SBenjamin Tissoires 		hid_info(wacom->hdev, "wireless tablet connected with PID %x\n",
948*471d1714SBenjamin Tissoires 			 wacom_wac->pid);
949*471d1714SBenjamin Tissoires 
950*471d1714SBenjamin Tissoires 		while (id->bus) {
951*471d1714SBenjamin Tissoires 			if (id->vendor == USB_VENDOR_ID_WACOM &&
952*471d1714SBenjamin Tissoires 			    id->product == wacom_wac->pid)
953*471d1714SBenjamin Tissoires 				break;
954*471d1714SBenjamin Tissoires 			id++;
955*471d1714SBenjamin Tissoires 		}
956*471d1714SBenjamin Tissoires 
957*471d1714SBenjamin Tissoires 		if (!id->bus) {
958*471d1714SBenjamin Tissoires 			hid_info(wacom->hdev, "ignoring unknown PID.\n");
959*471d1714SBenjamin Tissoires 			return;
960*471d1714SBenjamin Tissoires 		}
961*471d1714SBenjamin Tissoires 
962*471d1714SBenjamin Tissoires 		/* Stylus interface */
963*471d1714SBenjamin Tissoires 		wacom_wac1->features =
964*471d1714SBenjamin Tissoires 			*((struct wacom_features *)id->driver_data);
965*471d1714SBenjamin Tissoires 		wacom_wac1->features.device_type = BTN_TOOL_PEN;
966*471d1714SBenjamin Tissoires 		snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
967*471d1714SBenjamin Tissoires 			 wacom_wac1->features.name);
968*471d1714SBenjamin Tissoires 		snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
969*471d1714SBenjamin Tissoires 			 wacom_wac1->features.name);
970*471d1714SBenjamin Tissoires 		wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
971*471d1714SBenjamin Tissoires 		wacom_wac1->shared->type = wacom_wac1->features.type;
972*471d1714SBenjamin Tissoires 		error = wacom_register_inputs(wacom1);
973*471d1714SBenjamin Tissoires 		if (error)
974*471d1714SBenjamin Tissoires 			goto fail;
975*471d1714SBenjamin Tissoires 
976*471d1714SBenjamin Tissoires 		/* Touch interface */
977*471d1714SBenjamin Tissoires 		if (wacom_wac1->features.touch_max ||
978*471d1714SBenjamin Tissoires 		    wacom_wac1->features.type == INTUOSHT) {
979*471d1714SBenjamin Tissoires 			wacom_wac2->features =
980*471d1714SBenjamin Tissoires 				*((struct wacom_features *)id->driver_data);
981*471d1714SBenjamin Tissoires 			wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
982*471d1714SBenjamin Tissoires 			wacom_wac2->features.device_type = BTN_TOOL_FINGER;
983*471d1714SBenjamin Tissoires 			wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
984*471d1714SBenjamin Tissoires 			if (wacom_wac2->features.touch_max)
985*471d1714SBenjamin Tissoires 				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
986*471d1714SBenjamin Tissoires 					 "%s (WL) Finger",wacom_wac2->features.name);
987*471d1714SBenjamin Tissoires 			else
988*471d1714SBenjamin Tissoires 				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
989*471d1714SBenjamin Tissoires 					 "%s (WL) Pad",wacom_wac2->features.name);
990*471d1714SBenjamin Tissoires 			snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
991*471d1714SBenjamin Tissoires 				 "%s (WL) Pad", wacom_wac2->features.name);
992*471d1714SBenjamin Tissoires 			error = wacom_register_inputs(wacom2);
993*471d1714SBenjamin Tissoires 			if (error)
994*471d1714SBenjamin Tissoires 				goto fail;
995*471d1714SBenjamin Tissoires 
996*471d1714SBenjamin Tissoires 			if (wacom_wac1->features.type == INTUOSHT &&
997*471d1714SBenjamin Tissoires 			    wacom_wac1->features.touch_max)
998*471d1714SBenjamin Tissoires 				wacom_wac->shared->touch_input = wacom_wac2->input;
999*471d1714SBenjamin Tissoires 		}
1000*471d1714SBenjamin Tissoires 
1001*471d1714SBenjamin Tissoires 		error = wacom_initialize_battery(wacom);
1002*471d1714SBenjamin Tissoires 		if (error)
1003*471d1714SBenjamin Tissoires 			goto fail;
1004*471d1714SBenjamin Tissoires 	}
1005*471d1714SBenjamin Tissoires 
1006*471d1714SBenjamin Tissoires 	return;
1007*471d1714SBenjamin Tissoires 
1008*471d1714SBenjamin Tissoires fail:
1009*471d1714SBenjamin Tissoires 	wacom_unregister_inputs(wacom1);
1010*471d1714SBenjamin Tissoires 	wacom_unregister_inputs(wacom2);
1011*471d1714SBenjamin Tissoires 	return;
1012*471d1714SBenjamin Tissoires }
1013*471d1714SBenjamin Tissoires 
1014*471d1714SBenjamin Tissoires /*
1015*471d1714SBenjamin Tissoires  * Not all devices report physical dimensions from HID.
1016*471d1714SBenjamin Tissoires  * Compute the default from hardcoded logical dimension
1017*471d1714SBenjamin Tissoires  * and resolution before driver overwrites them.
1018*471d1714SBenjamin Tissoires  */
1019*471d1714SBenjamin Tissoires static void wacom_set_default_phy(struct wacom_features *features)
1020*471d1714SBenjamin Tissoires {
1021*471d1714SBenjamin Tissoires 	if (features->x_resolution) {
1022*471d1714SBenjamin Tissoires 		features->x_phy = (features->x_max * 100) /
1023*471d1714SBenjamin Tissoires 					features->x_resolution;
1024*471d1714SBenjamin Tissoires 		features->y_phy = (features->y_max * 100) /
1025*471d1714SBenjamin Tissoires 					features->y_resolution;
1026*471d1714SBenjamin Tissoires 	}
1027*471d1714SBenjamin Tissoires }
1028*471d1714SBenjamin Tissoires 
1029*471d1714SBenjamin Tissoires static void wacom_calculate_res(struct wacom_features *features)
1030*471d1714SBenjamin Tissoires {
1031*471d1714SBenjamin Tissoires 	features->x_resolution = wacom_calc_hid_res(features->x_max,
1032*471d1714SBenjamin Tissoires 						    features->x_phy,
1033*471d1714SBenjamin Tissoires 						    features->unit,
1034*471d1714SBenjamin Tissoires 						    features->unitExpo);
1035*471d1714SBenjamin Tissoires 	features->y_resolution = wacom_calc_hid_res(features->y_max,
1036*471d1714SBenjamin Tissoires 						    features->y_phy,
1037*471d1714SBenjamin Tissoires 						    features->unit,
1038*471d1714SBenjamin Tissoires 						    features->unitExpo);
1039*471d1714SBenjamin Tissoires }
1040*471d1714SBenjamin Tissoires 
1041*471d1714SBenjamin Tissoires static int wacom_hid_report_len(struct hid_report *report)
1042*471d1714SBenjamin Tissoires {
1043*471d1714SBenjamin Tissoires 	/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
1044*471d1714SBenjamin Tissoires 	return ((report->size - 1) >> 3) + 1 + (report->id > 0);
1045*471d1714SBenjamin Tissoires }
1046*471d1714SBenjamin Tissoires 
1047*471d1714SBenjamin Tissoires static size_t wacom_compute_pktlen(struct hid_device *hdev)
1048*471d1714SBenjamin Tissoires {
1049*471d1714SBenjamin Tissoires 	struct hid_report_enum *report_enum;
1050*471d1714SBenjamin Tissoires 	struct hid_report *report;
1051*471d1714SBenjamin Tissoires 	size_t size = 0;
1052*471d1714SBenjamin Tissoires 
1053*471d1714SBenjamin Tissoires 	report_enum = hdev->report_enum + HID_INPUT_REPORT;
1054*471d1714SBenjamin Tissoires 
1055*471d1714SBenjamin Tissoires 	list_for_each_entry(report, &report_enum->report_list, list) {
1056*471d1714SBenjamin Tissoires 		size_t report_size = wacom_hid_report_len(report);
1057*471d1714SBenjamin Tissoires 		if (report_size > size)
1058*471d1714SBenjamin Tissoires 			size = report_size;
1059*471d1714SBenjamin Tissoires 	}
1060*471d1714SBenjamin Tissoires 
1061*471d1714SBenjamin Tissoires 	return size;
1062*471d1714SBenjamin Tissoires }
1063*471d1714SBenjamin Tissoires 
1064*471d1714SBenjamin Tissoires static int wacom_probe(struct hid_device *hdev,
1065*471d1714SBenjamin Tissoires 		const struct hid_device_id *id)
1066*471d1714SBenjamin Tissoires {
1067*471d1714SBenjamin Tissoires 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
1068*471d1714SBenjamin Tissoires 	struct usb_device *dev = interface_to_usbdev(intf);
1069*471d1714SBenjamin Tissoires 	struct wacom *wacom;
1070*471d1714SBenjamin Tissoires 	struct wacom_wac *wacom_wac;
1071*471d1714SBenjamin Tissoires 	struct wacom_features *features;
1072*471d1714SBenjamin Tissoires 	int error;
1073*471d1714SBenjamin Tissoires 
1074*471d1714SBenjamin Tissoires 	if (!id->driver_data)
1075*471d1714SBenjamin Tissoires 		return -EINVAL;
1076*471d1714SBenjamin Tissoires 
1077*471d1714SBenjamin Tissoires 	wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
1078*471d1714SBenjamin Tissoires 	if (!wacom)
1079*471d1714SBenjamin Tissoires 		return -ENOMEM;
1080*471d1714SBenjamin Tissoires 
1081*471d1714SBenjamin Tissoires 	hid_set_drvdata(hdev, wacom);
1082*471d1714SBenjamin Tissoires 	wacom->hdev = hdev;
1083*471d1714SBenjamin Tissoires 
1084*471d1714SBenjamin Tissoires 	/* ask for the report descriptor to be loaded by HID */
1085*471d1714SBenjamin Tissoires 	error = hid_parse(hdev);
1086*471d1714SBenjamin Tissoires 	if (error) {
1087*471d1714SBenjamin Tissoires 		hid_err(hdev, "parse failed\n");
1088*471d1714SBenjamin Tissoires 		goto fail1;
1089*471d1714SBenjamin Tissoires 	}
1090*471d1714SBenjamin Tissoires 
1091*471d1714SBenjamin Tissoires 	wacom_wac = &wacom->wacom_wac;
1092*471d1714SBenjamin Tissoires 	wacom_wac->features = *((struct wacom_features *)id->driver_data);
1093*471d1714SBenjamin Tissoires 	features = &wacom_wac->features;
1094*471d1714SBenjamin Tissoires 	features->pktlen = wacom_compute_pktlen(hdev);
1095*471d1714SBenjamin Tissoires 	if (features->pktlen > WACOM_PKGLEN_MAX) {
1096*471d1714SBenjamin Tissoires 		error = -EINVAL;
1097*471d1714SBenjamin Tissoires 		goto fail1;
1098*471d1714SBenjamin Tissoires 	}
1099*471d1714SBenjamin Tissoires 
1100*471d1714SBenjamin Tissoires 	if (features->check_for_hid_type && features->hid_type != hdev->type) {
1101*471d1714SBenjamin Tissoires 		error = -ENODEV;
1102*471d1714SBenjamin Tissoires 		goto fail1;
1103*471d1714SBenjamin Tissoires 	}
1104*471d1714SBenjamin Tissoires 
1105*471d1714SBenjamin Tissoires 	wacom->usbdev = dev;
1106*471d1714SBenjamin Tissoires 	wacom->intf = intf;
1107*471d1714SBenjamin Tissoires 	mutex_init(&wacom->lock);
1108*471d1714SBenjamin Tissoires 	INIT_WORK(&wacom->work, wacom_wireless_work);
1109*471d1714SBenjamin Tissoires 
1110*471d1714SBenjamin Tissoires 	/* set the default size in case we do not get them from hid */
1111*471d1714SBenjamin Tissoires 	wacom_set_default_phy(features);
1112*471d1714SBenjamin Tissoires 
1113*471d1714SBenjamin Tissoires 	/* Retrieve the physical and logical size for touch devices */
1114*471d1714SBenjamin Tissoires 	wacom_retrieve_hid_descriptor(hdev, features);
1115*471d1714SBenjamin Tissoires 
1116*471d1714SBenjamin Tissoires 	/*
1117*471d1714SBenjamin Tissoires 	 * Intuos5 has no useful data about its touch interface in its
1118*471d1714SBenjamin Tissoires 	 * HID descriptor. If this is the touch interface (PacketSize
1119*471d1714SBenjamin Tissoires 	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.
1120*471d1714SBenjamin Tissoires 	 */
1121*471d1714SBenjamin Tissoires 	if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
1122*471d1714SBenjamin Tissoires 		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
1123*471d1714SBenjamin Tissoires 			features->device_type = BTN_TOOL_FINGER;
1124*471d1714SBenjamin Tissoires 
1125*471d1714SBenjamin Tissoires 			features->x_max = 4096;
1126*471d1714SBenjamin Tissoires 			features->y_max = 4096;
1127*471d1714SBenjamin Tissoires 		} else {
1128*471d1714SBenjamin Tissoires 			features->device_type = BTN_TOOL_PEN;
1129*471d1714SBenjamin Tissoires 		}
1130*471d1714SBenjamin Tissoires 	}
1131*471d1714SBenjamin Tissoires 
1132*471d1714SBenjamin Tissoires 	/*
1133*471d1714SBenjamin Tissoires 	 * Same thing for Bamboo 3rd gen.
1134*471d1714SBenjamin Tissoires 	 */
1135*471d1714SBenjamin Tissoires 	if ((features->type == BAMBOO_PT) &&
1136*471d1714SBenjamin Tissoires 	    (features->pktlen == WACOM_PKGLEN_BBTOUCH3) &&
1137*471d1714SBenjamin Tissoires 	    (features->device_type == BTN_TOOL_PEN)) {
1138*471d1714SBenjamin Tissoires 		features->device_type = BTN_TOOL_FINGER;
1139*471d1714SBenjamin Tissoires 
1140*471d1714SBenjamin Tissoires 		features->x_max = 4096;
1141*471d1714SBenjamin Tissoires 		features->y_max = 4096;
1142*471d1714SBenjamin Tissoires 	}
1143*471d1714SBenjamin Tissoires 
1144*471d1714SBenjamin Tissoires 	wacom_setup_device_quirks(features);
1145*471d1714SBenjamin Tissoires 
1146*471d1714SBenjamin Tissoires 	/* set unit to "100th of a mm" for devices not reported by HID */
1147*471d1714SBenjamin Tissoires 	if (!features->unit) {
1148*471d1714SBenjamin Tissoires 		features->unit = 0x11;
1149*471d1714SBenjamin Tissoires 		features->unitExpo = -3;
1150*471d1714SBenjamin Tissoires 	}
1151*471d1714SBenjamin Tissoires 	wacom_calculate_res(features);
1152*471d1714SBenjamin Tissoires 
1153*471d1714SBenjamin Tissoires 	strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
1154*471d1714SBenjamin Tissoires 	snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
1155*471d1714SBenjamin Tissoires 		"%s Pad", features->name);
1156*471d1714SBenjamin Tissoires 
1157*471d1714SBenjamin Tissoires 	if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
1158*471d1714SBenjamin Tissoires 		/* Append the device type to the name */
1159*471d1714SBenjamin Tissoires 		if (features->device_type != BTN_TOOL_FINGER)
1160*471d1714SBenjamin Tissoires 			strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
1161*471d1714SBenjamin Tissoires 		else if (features->touch_max)
1162*471d1714SBenjamin Tissoires 			strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
1163*471d1714SBenjamin Tissoires 		else
1164*471d1714SBenjamin Tissoires 			strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
1165*471d1714SBenjamin Tissoires 
1166*471d1714SBenjamin Tissoires 		error = wacom_add_shared_data(hdev);
1167*471d1714SBenjamin Tissoires 		if (error)
1168*471d1714SBenjamin Tissoires 			goto fail1;
1169*471d1714SBenjamin Tissoires 	}
1170*471d1714SBenjamin Tissoires 
1171*471d1714SBenjamin Tissoires 	error = wacom_initialize_leds(wacom);
1172*471d1714SBenjamin Tissoires 	if (error)
1173*471d1714SBenjamin Tissoires 		goto fail2;
1174*471d1714SBenjamin Tissoires 
1175*471d1714SBenjamin Tissoires 	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
1176*471d1714SBenjamin Tissoires 		error = wacom_register_inputs(wacom);
1177*471d1714SBenjamin Tissoires 		if (error)
1178*471d1714SBenjamin Tissoires 			goto fail3;
1179*471d1714SBenjamin Tissoires 	}
1180*471d1714SBenjamin Tissoires 
1181*471d1714SBenjamin Tissoires 	/* Note that if query fails it is not a hard failure */
1182*471d1714SBenjamin Tissoires 	wacom_query_tablet_data(hdev, features);
1183*471d1714SBenjamin Tissoires 
1184*471d1714SBenjamin Tissoires 	/* Regular HID work starts now */
1185*471d1714SBenjamin Tissoires 	error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
1186*471d1714SBenjamin Tissoires 	if (error) {
1187*471d1714SBenjamin Tissoires 		hid_err(hdev, "hw start failed\n");
1188*471d1714SBenjamin Tissoires 		goto fail4;
1189*471d1714SBenjamin Tissoires 	}
1190*471d1714SBenjamin Tissoires 
1191*471d1714SBenjamin Tissoires 	if (features->quirks & WACOM_QUIRK_MONITOR)
1192*471d1714SBenjamin Tissoires 		error = hid_hw_open(hdev);
1193*471d1714SBenjamin Tissoires 
1194*471d1714SBenjamin Tissoires 	if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) {
1195*471d1714SBenjamin Tissoires 		if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
1196*471d1714SBenjamin Tissoires 			wacom_wac->shared->touch_input = wacom_wac->input;
1197*471d1714SBenjamin Tissoires 	}
1198*471d1714SBenjamin Tissoires 
1199*471d1714SBenjamin Tissoires 	return 0;
1200*471d1714SBenjamin Tissoires 
1201*471d1714SBenjamin Tissoires  fail4:	wacom_unregister_inputs(wacom);
1202*471d1714SBenjamin Tissoires  fail3:	wacom_destroy_leds(wacom);
1203*471d1714SBenjamin Tissoires  fail2:	wacom_remove_shared_data(wacom_wac);
1204*471d1714SBenjamin Tissoires  fail1:	kfree(wacom);
1205*471d1714SBenjamin Tissoires 	hid_set_drvdata(hdev, NULL);
1206*471d1714SBenjamin Tissoires 	return error;
1207*471d1714SBenjamin Tissoires }
1208*471d1714SBenjamin Tissoires 
1209*471d1714SBenjamin Tissoires static void wacom_remove(struct hid_device *hdev)
1210*471d1714SBenjamin Tissoires {
1211*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
1212*471d1714SBenjamin Tissoires 
1213*471d1714SBenjamin Tissoires 	hid_hw_stop(hdev);
1214*471d1714SBenjamin Tissoires 
1215*471d1714SBenjamin Tissoires 	cancel_work_sync(&wacom->work);
1216*471d1714SBenjamin Tissoires 	wacom_unregister_inputs(wacom);
1217*471d1714SBenjamin Tissoires 	wacom_destroy_battery(wacom);
1218*471d1714SBenjamin Tissoires 	wacom_destroy_leds(wacom);
1219*471d1714SBenjamin Tissoires 	wacom_remove_shared_data(&wacom->wacom_wac);
1220*471d1714SBenjamin Tissoires 
1221*471d1714SBenjamin Tissoires 	hid_set_drvdata(hdev, NULL);
1222*471d1714SBenjamin Tissoires 	kfree(wacom);
1223*471d1714SBenjamin Tissoires }
1224*471d1714SBenjamin Tissoires 
1225*471d1714SBenjamin Tissoires static int wacom_resume(struct hid_device *hdev)
1226*471d1714SBenjamin Tissoires {
1227*471d1714SBenjamin Tissoires 	struct wacom *wacom = hid_get_drvdata(hdev);
1228*471d1714SBenjamin Tissoires 	struct wacom_features *features = &wacom->wacom_wac.features;
1229*471d1714SBenjamin Tissoires 
1230*471d1714SBenjamin Tissoires 	mutex_lock(&wacom->lock);
1231*471d1714SBenjamin Tissoires 
1232*471d1714SBenjamin Tissoires 	/* switch to wacom mode first */
1233*471d1714SBenjamin Tissoires 	wacom_query_tablet_data(hdev, features);
1234*471d1714SBenjamin Tissoires 	wacom_led_control(wacom);
1235*471d1714SBenjamin Tissoires 
1236*471d1714SBenjamin Tissoires 	mutex_unlock(&wacom->lock);
1237*471d1714SBenjamin Tissoires 
1238*471d1714SBenjamin Tissoires 	return 0;
1239*471d1714SBenjamin Tissoires }
1240*471d1714SBenjamin Tissoires 
1241*471d1714SBenjamin Tissoires static int wacom_reset_resume(struct hid_device *hdev)
1242*471d1714SBenjamin Tissoires {
1243*471d1714SBenjamin Tissoires 	return wacom_resume(hdev);
1244*471d1714SBenjamin Tissoires }
1245*471d1714SBenjamin Tissoires 
1246*471d1714SBenjamin Tissoires static struct hid_driver wacom_driver = {
1247*471d1714SBenjamin Tissoires 	.name =		"wacom",
1248*471d1714SBenjamin Tissoires 	.id_table =	wacom_ids,
1249*471d1714SBenjamin Tissoires 	.probe =	wacom_probe,
1250*471d1714SBenjamin Tissoires 	.remove =	wacom_remove,
1251*471d1714SBenjamin Tissoires #ifdef CONFIG_PM
1252*471d1714SBenjamin Tissoires 	.resume =	wacom_resume,
1253*471d1714SBenjamin Tissoires 	.reset_resume =	wacom_reset_resume,
1254*471d1714SBenjamin Tissoires #endif
1255*471d1714SBenjamin Tissoires 	.raw_event =	wacom_raw_event,
1256*471d1714SBenjamin Tissoires };
1257*471d1714SBenjamin Tissoires module_hid_driver(wacom_driver);
1258