Blame view

drivers/hid/wacom_sys.c 72.5 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
3bea733ab   Ping Cheng   USB: wacom tablet...
2
  /*
4104d13fe   Dmitry Torokhov   Input: move USB t...
3
   * drivers/input/tablet/wacom_sys.c
3bea733ab   Ping Cheng   USB: wacom tablet...
4
   *
232f5693e   Ping Cheng   Input: wacom - en...
5
   *  USB Wacom tablet support - system specific code
3bea733ab   Ping Cheng   USB: wacom tablet...
6
7
8
   */
  
  /*
3bea733ab   Ping Cheng   USB: wacom tablet...
9
   */
3bea733ab   Ping Cheng   USB: wacom tablet...
10
  #include "wacom_wac.h"
51269fe86   Dmitry Torokhov   Input: wacom - do...
11
  #include "wacom.h"
b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
12
  #include <linux/input/mt.h>
3bea733ab   Ping Cheng   USB: wacom tablet...
13

a417ea443   Ping Cheng   Input: wacom - ad...
14
  #define WAC_MSG_RETRIES		5
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
15
  #define WAC_CMD_RETRIES		10
e0984bc37   Ping Cheng   HID: wacom - Add ...
16
17
  #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
  #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
72b236d60   Aaron Skomra   HID: wacom: Add s...
18
  #define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP)
e0984bc37   Ping Cheng   HID: wacom - Add ...
19

c64d88347   Ping Cheng   HID: wacom - remo...
20
21
  static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf,
  			    size_t size, unsigned int retries)
3bea733ab   Ping Cheng   USB: wacom tablet...
22
  {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
23
24
25
  	int retval;
  
  	do {
c64d88347   Ping Cheng   HID: wacom - remo...
26
  		retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
27b20a9de   Benjamin Tissoires   Input: wacom - us...
27
  				HID_REQ_GET_REPORT);
aef3156d7   Jason Gerecke   HID: wacom: Have ...
28
29
30
31
32
33
  	} while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries);
  
  	if (retval < 0)
  		hid_err(hdev, "wacom_get_report: ran out of retries "
  			"(last error = %d)
  ", retval);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
34
35
  
  	return retval;
3bea733ab   Ping Cheng   USB: wacom tablet...
36
  }
296b73787   Przemo Firszt   Input: wacom - re...
37
38
  static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf,
  			    size_t size, unsigned int retries)
3bea733ab   Ping Cheng   USB: wacom tablet...
39
  {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
40
41
42
  	int retval;
  
  	do {
296b73787   Przemo Firszt   Input: wacom - re...
43
  		retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
27b20a9de   Benjamin Tissoires   Input: wacom - us...
44
  				HID_REQ_SET_REPORT);
aef3156d7   Jason Gerecke   HID: wacom: Have ...
45
46
47
48
49
50
  	} while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries);
  
  	if (retval < 0)
  		hid_err(hdev, "wacom_set_report: ran out of retries "
  			"(last error = %d)
  ", retval);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
51
52
  
  	return retval;
3bea733ab   Ping Cheng   USB: wacom tablet...
53
  }
834172064   Jason Gerecke   HID: wacom: Queue...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  static void wacom_wac_queue_insert(struct hid_device *hdev,
  				   struct kfifo_rec_ptr_2 *fifo,
  				   u8 *raw_data, int size)
  {
  	bool warned = false;
  
  	while (kfifo_avail(fifo) < size) {
  		if (!warned)
  			hid_warn(hdev, "%s: kfifo has filled, starting to drop events
  ", __func__);
  		warned = true;
  
  		kfifo_skip(fifo);
  	}
  
  	kfifo_in(fifo, raw_data, size);
  }
  
  static void wacom_wac_queue_flush(struct hid_device *hdev,
  				  struct kfifo_rec_ptr_2 *fifo)
  {
  	while (!kfifo_is_empty(fifo)) {
  		u8 buf[WACOM_PKGLEN_MAX];
  		int size;
  		int err;
  
  		size = kfifo_out(fifo, buf, sizeof(buf));
  		err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false);
  		if (err) {
  			hid_warn(hdev, "%s: unable to flush event due to error %d
  ",
  				 __func__, err);
  		}
  	}
  }
  
  static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
073b50bcc   Jason Gerecke   HID: wacom: Fix s...
91
  		struct hid_report *report, u8 *raw_data, int report_size)
834172064   Jason Gerecke   HID: wacom: Queue...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  {
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct wacom_features *features = &wacom_wac->features;
  	bool flush = false;
  	bool insert = false;
  	int i, j;
  
  	if (wacom_wac->serial[0] || !(features->quirks & WACOM_QUIRK_TOOLSERIAL))
  		return 0;
  
  	/* Queue events which have invalid tool type or serial number */
  	for (i = 0; i < report->maxfield; i++) {
  		for (j = 0; j < report->field[i]->maxusage; j++) {
  			struct hid_field *field = report->field[i];
  			struct hid_usage *usage = &field->usage[j];
  			unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
  			unsigned int offset;
  			unsigned int size;
  			unsigned int value;
  
  			if (equivalent_usage != HID_DG_INRANGE &&
  			    equivalent_usage != HID_DG_TOOLSERIALNUMBER &&
  			    equivalent_usage != WACOM_HID_WD_SERIALHI &&
  			    equivalent_usage != WACOM_HID_WD_TOOLTYPE)
  				continue;
  
  			offset = field->report_offset;
  			size = field->report_size;
  			value = hid_field_extract(hdev, raw_data+1, offset + j * size, size);
  
  			/* If we go out of range, we need to flush the queue ASAP */
  			if (equivalent_usage == HID_DG_INRANGE)
  				value = !value;
  
  			if (value) {
  				flush = true;
  				switch (equivalent_usage) {
  				case HID_DG_TOOLSERIALNUMBER:
  					wacom_wac->serial[0] = value;
  					break;
  
  				case WACOM_HID_WD_SERIALHI:
  					wacom_wac->serial[0] |= ((__u64)value) << 32;
  					break;
  
  				case WACOM_HID_WD_TOOLTYPE:
  					wacom_wac->id[0] = value;
  					break;
  				}
  			}
  			else {
  				insert = true;
  			}
  		}
  	}
  
  	if (flush)
  		wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
  	else if (insert)
073b50bcc   Jason Gerecke   HID: wacom: Fix s...
152
153
  		wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo,
  				       raw_data, report_size);
834172064   Jason Gerecke   HID: wacom: Queue...
154
155
156
  
  	return insert && !flush;
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
157
158
  static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
  		u8 *raw_data, int size)
3bea733ab   Ping Cheng   USB: wacom tablet...
159
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
160
  	struct wacom *wacom = hid_get_drvdata(hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
161

29b473913   Benjamin Tissoires   Input: wacom - sw...
162
163
  	if (size > WACOM_PKGLEN_MAX)
  		return 1;
3bea733ab   Ping Cheng   USB: wacom tablet...
164

834172064   Jason Gerecke   HID: wacom: Queue...
165
166
  	if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size))
  		return -1;
29b473913   Benjamin Tissoires   Input: wacom - sw...
167
  	memcpy(wacom->wacom_wac.data, raw_data, size);
3bea733ab   Ping Cheng   USB: wacom tablet...
168

29b473913   Benjamin Tissoires   Input: wacom - sw...
169
170
171
  	wacom_wac_irq(&wacom->wacom_wac, size);
  
  	return 0;
3bea733ab   Ping Cheng   USB: wacom tablet...
172
  }
3bea733ab   Ping Cheng   USB: wacom tablet...
173
174
  static int wacom_open(struct input_dev *dev)
  {
7791bdae7   Dmitry Torokhov   Input: drivers/us...
175
  	struct wacom *wacom = input_get_drvdata(dev);
29b473913   Benjamin Tissoires   Input: wacom - sw...
176

dff674168   Benjamin Tissoires   HID: wacom: fix f...
177
  	return hid_hw_open(wacom->hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
178
179
180
181
  }
  
  static void wacom_close(struct input_dev *dev)
  {
7791bdae7   Dmitry Torokhov   Input: drivers/us...
182
  	struct wacom *wacom = input_get_drvdata(dev);
3bea733ab   Ping Cheng   USB: wacom tablet...
183

3dad188e6   Benjamin Tissoires   HID: wacom: switc...
184
185
186
187
188
189
  	/*
  	 * wacom->hdev should never be null, but surprisingly, I had the case
  	 * once while unplugging the Wacom Wireless Receiver.
  	 */
  	if (wacom->hdev)
  		hid_hw_close(wacom->hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
190
  }
16bf288c4   Chris Bagwell   Input: wacom - cr...
191
  /*
198fdee28   Benjamin Tissoires   Input: wacom - us...
192
   * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res.
115d5e12a   Jason Gerecke   Input: wacom - in...
193
194
   */
  static int wacom_calc_hid_res(int logical_extents, int physical_extents,
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
195
  			       unsigned unit, int exponent)
115d5e12a   Jason Gerecke   Input: wacom - in...
196
  {
198fdee28   Benjamin Tissoires   Input: wacom - us...
197
198
199
200
201
202
203
204
  	struct hid_field field = {
  		.logical_maximum = logical_extents,
  		.physical_maximum = physical_extents,
  		.unit = unit,
  		.unit_exponent = exponent,
  	};
  
  	return hidinput_calc_abs_res(&field, ABS_X);
115d5e12a   Jason Gerecke   Input: wacom - in...
205
  }
578325120   Jason Gerecke   HID: wacom: Move ...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
  static void wacom_hid_usage_quirk(struct hid_device *hdev,
  		struct hid_field *field, struct hid_usage *usage)
  {
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
  	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
  
  	/*
  	 * The Dell Canvas 27 needs to be switched to its vendor-defined
  	 * report to provide the best resolution.
  	 */
  	if (hdev->vendor == USB_VENDOR_ID_WACOM &&
  	    hdev->product == 0x4200 &&
  	    field->application == HID_UP_MSVENDOR) {
  		wacom->wacom_wac.mode_report = field->report->id;
  		wacom->wacom_wac.mode_value = 2;
  	}
  
  	/*
  	 * ISDv4 devices which predate HID's adoption of the
  	 * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its
  	 * position instead. We can accurately detect if a
  	 * usage with that value should be HID_DG_BARRELSWITCH2
  	 * based on the surrounding usages, which have remained
  	 * constant across generations.
  	 */
  	if (features->type == HID_GENERIC &&
  	    usage->hid == 0x000D0000 &&
  	    field->application == HID_DG_PEN &&
  	    field->physical == HID_DG_STYLUS) {
  		int i = usage->usage_index;
  
  		if (i-4 >= 0 && i+1 < field->maxusage &&
  		    field->usage[i-4].hid == HID_DG_TIPSWITCH &&
  		    field->usage[i-3].hid == HID_DG_BARRELSWITCH &&
  		    field->usage[i-2].hid == HID_DG_ERASER &&
  		    field->usage[i-1].hid == HID_DG_INVERT &&
  		    field->usage[i+1].hid == HID_DG_INRANGE) {
  			usage->hid = HID_DG_BARRELSWITCH2;
  		}
  	}
e9fe0d492   Jason Gerecke   HID: wacom: Move ...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  	/*
  	 * Wacom's AES devices use different vendor-defined usages to
  	 * report serial number information compared to their branded
  	 * hardware. The usages are also sometimes ill-defined and do
  	 * not have the correct logical min/max values set. Lets patch
  	 * the descriptor to use the branded usage convention and fix
  	 * the errors.
  	 */
  	if (usage->hid == WACOM_HID_WT_SERIALNUMBER &&
  	    field->report_size == 16 &&
  	    field->index + 2 < field->report->maxfield) {
  		struct hid_field *a = field->report->field[field->index + 1];
  		struct hid_field *b = field->report->field[field->index + 2];
  
  		if (a->maxusage > 0 &&
  		    a->usage[0].hid == HID_DG_TOOLSERIALNUMBER &&
  		    a->report_size == 32 &&
  		    b->maxusage > 0 &&
  		    b->usage[0].hid == 0xFF000000 &&
  		    b->report_size == 8) {
  			features->quirks |= WACOM_QUIRK_AESPEN;
  			usage->hid = WACOM_HID_WD_TOOLTYPE;
  			field->logical_minimum = S16_MIN;
  			field->logical_maximum = S16_MAX;
  			a->logical_minimum = S32_MIN;
  			a->logical_maximum = S32_MAX;
  			b->usage[0].hid = WACOM_HID_WD_SERIALHI;
  			b->logical_minimum = 0;
  			b->logical_maximum = U8_MAX;
  		}
  	}
578325120   Jason Gerecke   HID: wacom: Move ...
278
279
280
281
282
283
284
285
  	/* 2nd-generation Intuos Pro Large has incorrect Y maximum */
  	if (hdev->vendor == USB_VENDOR_ID_WACOM &&
  	    hdev->product == 0x0358 &&
  	    WACOM_PEN_FIELD(field) &&
  	    equivalent_usage == HID_GD_Y) {
  		field->logical_maximum = 43200;
  	}
  }
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
286
287
  static void wacom_feature_mapping(struct hid_device *hdev,
  		struct hid_field *field, struct hid_usage *usage)
f393ee2b8   Ping Cheng   Input: wacom - re...
288
  {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
289
290
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
291
  	struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
ac2423c97   Aaron Armstrong Skomra   HID: wacom: gener...
292
  	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
293
294
  	u8 *data;
  	int ret;
3064a03b9   Aaron Ma   HID: Fix hid_repo...
295
  	u32 n;
f393ee2b8   Ping Cheng   Input: wacom - re...
296

578325120   Jason Gerecke   HID: wacom: Move ...
297
  	wacom_hid_usage_quirk(hdev, field, usage);
ac2423c97   Aaron Armstrong Skomra   HID: wacom: gener...
298
  	switch (equivalent_usage) {
d8e980600   Aaron Armstrong Skomra   HID: wacom: gener...
299
300
301
  	case WACOM_HID_WD_TOUCH_RING_SETTING:
  		wacom->generic_has_leds = true;
  		break;
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
302
303
  	case HID_DG_CONTACTMAX:
  		/* leave touch_max as is if predefined */
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
304
305
  		if (!features->touch_max) {
  			/* read manually */
184eccd40   Aaron Armstrong Skomra   HID: wacom: gener...
306
307
  			n = hid_report_len(field->report);
  			data = hid_alloc_report_buf(field->report, GFP_KERNEL);
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
308
309
310
311
  			if (!data)
  				break;
  			data[0] = field->report->id;
  			ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
184eccd40   Aaron Armstrong Skomra   HID: wacom: gener...
312
  					       data, n, WAC_CMD_RETRIES);
778fbf417   Jason Gerecke   HID: wacom: Read ...
313
  			if (ret == n && features->type == HID_GENERIC) {
184eccd40   Aaron Armstrong Skomra   HID: wacom: gener...
314
315
  				ret = hid_report_raw_event(hdev,
  					HID_FEATURE_REPORT, data, n, 0);
778fbf417   Jason Gerecke   HID: wacom: Read ...
316
317
  			} else if (ret == 2 && features->type != HID_GENERIC) {
  				features->touch_max = data[1];
05e8fd920   Jason Gerecke   HID: wacom: Handl...
318
319
320
321
322
323
324
325
  			} else {
  				features->touch_max = 16;
  				hid_warn(hdev, "wacom_feature_mapping: "
  					 "could not get HID_DG_CONTACTMAX, "
  					 "defaulting to %d
  ",
  					  features->touch_max);
  			}
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
326
327
  			kfree(data);
  		}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
328
  		break;
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
329
330
331
332
333
334
335
336
337
338
339
  	case HID_DG_INPUTMODE:
  		/* Ignore if value index is out of bounds. */
  		if (usage->usage_index >= field->report_count) {
  			dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range
  ");
  			break;
  		}
  
  		hid_data->inputmode = field->report->id;
  		hid_data->inputmode_index = usage->usage_index;
  		break;
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
340
341
342
  
  	case HID_UP_DIGITIZER:
  		if (field->report->id == 0x0B &&
8de82280e   Jason Gerecke   HID: wacom: Updat...
343
344
  		    (field->application == WACOM_HID_G9_PEN ||
  		     field->application == WACOM_HID_G11_PEN)) {
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
345
346
347
348
  			wacom->wacom_wac.mode_report = field->report->id;
  			wacom->wacom_wac.mode_value = 0;
  		}
  		break;
c9c095874   Jason Gerecke   HID: wacom: gener...
349
350
351
352
  	case WACOM_HID_WD_DATAMODE:
  		wacom->wacom_wac.mode_report = field->report->id;
  		wacom->wacom_wac.mode_value = 2;
  		break;
8de82280e   Jason Gerecke   HID: wacom: Updat...
353
354
  	case WACOM_HID_UP_G9:
  	case WACOM_HID_UP_G11:
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
355
  		if (field->report->id == 0x03 &&
8de82280e   Jason Gerecke   HID: wacom: Updat...
356
357
  		    (field->application == WACOM_HID_G9_TOUCHSCREEN ||
  		     field->application == WACOM_HID_G11_TOUCHSCREEN)) {
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
358
359
360
361
  			wacom->wacom_wac.mode_report = field->report->id;
  			wacom->wacom_wac.mode_value = 0;
  		}
  		break;
345857bb4   Jason Gerecke   HID: wacom: gener...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	case WACOM_HID_WD_OFFSETLEFT:
  	case WACOM_HID_WD_OFFSETTOP:
  	case WACOM_HID_WD_OFFSETRIGHT:
  	case WACOM_HID_WD_OFFSETBOTTOM:
  		/* read manually */
  		n = hid_report_len(field->report);
  		data = hid_alloc_report_buf(field->report, GFP_KERNEL);
  		if (!data)
  			break;
  		data[0] = field->report->id;
  		ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
  					data, n, WAC_CMD_RETRIES);
  		if (ret == n) {
  			ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT,
  						   data, n, 0);
  		} else {
  			hid_warn(hdev, "%s: could not retrieve sensor offsets
  ",
  				 __func__);
  		}
  		kfree(data);
  		break;
f393ee2b8   Ping Cheng   Input: wacom - re...
384
385
  	}
  }
428f85884   Chris Bagwell   Input: wacom - ad...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
  /*
   * Interface Descriptor of wacom devices can be incomplete and
   * inconsistent so wacom_features table is used to store stylus
   * device's packet lengths, various maximum values, and tablet
   * resolution based on product ID's.
   *
   * For devices that contain 2 interfaces, wacom_features table is
   * inaccurate for the touch interface.  Since the Interface Descriptor
   * for touch interfaces has pretty complete data, this function exists
   * to query tablet for this missing information instead of hard coding in
   * an additional table.
   *
   * A typical Interface Descriptor for a stylus will contain a
   * boot mouse application collection that is not of interest and this
   * function will ignore it.
   *
   * It also contains a digitizer application collection that also is not
   * of interest since any information it contains would be duplicate
   * of what is in wacom_features. Usually it defines a report of an array
   * of bytes that could be used as max length of the stylus packet returned.
   * If it happens to define a Digitizer-Stylus Physical Collection then
   * the X and Y logical values contain valid data but it is ignored.
   *
   * A typical Interface Descriptor for a touch interface will contain a
   * Digitizer-Finger Physical Collection which will define both logical
   * X/Y maximum as well as the physical size of tablet. Since touch
   * interfaces haven't supported pressure or distance, this is enough
   * information to override invalid values in the wacom_features table.
4134361af   Chris Bagwell   Input: wacom - re...
414
   *
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
415
416
   * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
   * data. We deal with them after returning from this function.
428f85884   Chris Bagwell   Input: wacom - ad...
417
   */
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
418
419
  static void wacom_usage_mapping(struct hid_device *hdev,
  		struct hid_field *field, struct hid_usage *usage)
545f4e99d   Ping Cheng   Input: wacom - ad...
420
  {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
421
422
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
d97a55221   Benjamin Tissoires   HID: wacom: use W...
423
424
  	bool finger = WACOM_FINGER_FIELD(field);
  	bool pen = WACOM_PEN_FIELD(field);
418b573b4   Ping Cheng   HID: wacom: conve...
425
  	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
e9fc413f4   Jason Gerecke   Input: wacom - ov...
426

c669fb2b9   Benjamin Tissoires   Input: wacom - us...
427
428
429
430
431
  	/*
  	* Requiring Stylus Usage will ignore boot mouse
  	* X/Y values and some cases of invalid Digitizer X/Y
  	* values commonly reported.
  	*/
042628abd   Jason Gerecke   HID: wacom: Disco...
432
  	if (pen)
aa86b18cc   Jason Gerecke   HID: wacom: Treat...
433
  		features->device_type |= WACOM_DEVICETYPE_PEN;
042628abd   Jason Gerecke   HID: wacom: Disco...
434
  	else if (finger)
aa86b18cc   Jason Gerecke   HID: wacom: Treat...
435
  		features->device_type |= WACOM_DEVICETYPE_TOUCH;
042628abd   Jason Gerecke   HID: wacom: Disco...
436
  	else
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
437
  		return;
578325120   Jason Gerecke   HID: wacom: Move ...
438
  	wacom_hid_usage_quirk(hdev, field, usage);
d471b6b22   Jason Gerecke   HID: wacom: Corre...
439

418b573b4   Ping Cheng   HID: wacom: conve...
440
  	switch (equivalent_usage) {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
441
442
443
  	case HID_GD_X:
  		features->x_max = field->logical_maximum;
  		if (finger) {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
444
  			features->x_phy = field->physical_maximum;
3b164a00a   Ping Cheng   HID: wacom: Clean...
445
446
  			if ((features->type != BAMBOO_PT) &&
  			    (features->type != BAMBOO_TOUCH)) {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
447
448
  				features->unit = field->unit;
  				features->unitExpo = field->unit_exponent;
545f4e99d   Ping Cheng   Input: wacom - ad...
449
  			}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
450
451
452
453
454
455
  		}
  		break;
  	case HID_GD_Y:
  		features->y_max = field->logical_maximum;
  		if (finger) {
  			features->y_phy = field->physical_maximum;
3b164a00a   Ping Cheng   HID: wacom: Clean...
456
457
  			if ((features->type != BAMBOO_PT) &&
  			    (features->type != BAMBOO_TOUCH)) {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
458
459
460
461
462
463
464
465
466
467
  				features->unit = field->unit;
  				features->unitExpo = field->unit_exponent;
  			}
  		}
  		break;
  	case HID_DG_TIPPRESSURE:
  		if (pen)
  			features->pressure_max = field->logical_maximum;
  		break;
  	}
7704ac937   Benjamin Tissoires   HID: wacom: imple...
468
469
470
  
  	if (features->type == HID_GENERIC)
  		wacom_wac_usage_mapping(hdev, field, usage);
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
471
  }
4134361af   Chris Bagwell   Input: wacom - re...
472

b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
473
474
475
476
477
478
479
480
  static void wacom_post_parse_hid(struct hid_device *hdev,
  				 struct wacom_features *features)
  {
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  
  	if (features->type == HID_GENERIC) {
  		/* Any last-minute generic device setup */
4082da80f   Benjamin Tissoires   HID: wacom: gener...
481
482
483
484
485
486
  		if (wacom_wac->has_mode_change) {
  			if (wacom_wac->is_direct_mode)
  				features->device_type |= WACOM_DEVICETYPE_DIRECT;
  			else
  				features->device_type &= ~WACOM_DEVICETYPE_DIRECT;
  		}
b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
487
  		if (features->touch_max > 1) {
ac2423c97   Aaron Armstrong Skomra   HID: wacom: gener...
488
489
490
491
492
493
494
495
  			if (features->device_type & WACOM_DEVICETYPE_DIRECT)
  				input_mt_init_slots(wacom_wac->touch_input,
  						    wacom_wac->features.touch_max,
  						    INPUT_MT_DIRECT);
  			else
  				input_mt_init_slots(wacom_wac->touch_input,
  						    wacom_wac->features.touch_max,
  						    INPUT_MT_POINTER);
b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
496
497
498
  		}
  	}
  }
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  static void wacom_parse_hid(struct hid_device *hdev,
  			   struct wacom_features *features)
  {
  	struct hid_report_enum *rep_enum;
  	struct hid_report *hreport;
  	int i, j;
  
  	/* check features first */
  	rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
  	list_for_each_entry(hreport, &rep_enum->report_list, list) {
  		for (i = 0; i < hreport->maxfield; i++) {
  			/* Ignore if report count is out of bounds. */
  			if (hreport->field[i]->report_count < 1)
  				continue;
  
  			for (j = 0; j < hreport->field[i]->maxusage; j++) {
  				wacom_feature_mapping(hdev, hreport->field[i],
  						hreport->field[i]->usage + j);
4134361af   Chris Bagwell   Input: wacom - re...
517
  			}
545f4e99d   Ping Cheng   Input: wacom - ad...
518
519
  		}
  	}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
520
521
522
523
524
525
526
527
528
529
530
531
  	/* now check the input usages */
  	rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
  	list_for_each_entry(hreport, &rep_enum->report_list, list) {
  
  		if (!hreport->maxfield)
  			continue;
  
  		for (i = 0; i < hreport->maxfield; i++)
  			for (j = 0; j < hreport->field[i]->maxusage; j++)
  				wacom_usage_mapping(hdev, hreport->field[i],
  						hreport->field[i]->usage + j);
  	}
b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
532
533
  
  	wacom_post_parse_hid(hdev, features);
545f4e99d   Ping Cheng   Input: wacom - ad...
534
  }
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  static int wacom_hid_set_device_mode(struct hid_device *hdev)
  {
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
  	struct hid_report *r;
  	struct hid_report_enum *re;
  
  	if (hid_data->inputmode < 0)
  		return 0;
  
  	re = &(hdev->report_enum[HID_FEATURE_REPORT]);
  	r = re->report_id_hash[hid_data->inputmode];
  	if (r) {
  		r->field[0]->value[hid_data->inputmode_index] = 2;
  		hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
  	}
  	return 0;
  }
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
553
554
  static int wacom_set_device_mode(struct hid_device *hdev,
  				 struct wacom_wac *wacom_wac)
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
555
  {
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
556
557
558
  	u8 *rep_data;
  	struct hid_report *r;
  	struct hid_report_enum *re;
3064a03b9   Aaron Ma   HID: Fix hid_repo...
559
  	u32 length;
fe494bc2f   Jason Gerecke   Input: wacom - cl...
560
  	int error = -ENOMEM, limit = 0;
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
561

326ea2a90   Jason Gerecke   HID: wacom: Suppo...
562
563
564
565
566
567
568
569
570
  	if (wacom_wac->mode_report < 0)
  		return 0;
  
  	re = &(hdev->report_enum[HID_FEATURE_REPORT]);
  	r = re->report_id_hash[wacom_wac->mode_report];
  	if (!r)
  		return -EINVAL;
  
  	rep_data = hid_alloc_report_buf(r, GFP_KERNEL);
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
571
  	if (!rep_data)
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
572
573
574
  		return -ENOMEM;
  
  	length = hid_report_len(r);
ec67bbedc   Ping Cheng   Input: wacom - ad...
575

fe494bc2f   Jason Gerecke   Input: wacom - cl...
576
  	do {
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
577
578
  		rep_data[0] = wacom_wac->mode_report;
  		rep_data[1] = wacom_wac->mode_value;
9937c0268   Chris Bagwell   Input: wacom - fi...
579

296b73787   Przemo Firszt   Input: wacom - re...
580
581
  		error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
  					 length, 1);
3cb83157e   Benjamin Tissoires   Input: Revert "wa...
582
  		if (error >= 0)
27b20a9de   Benjamin Tissoires   Input: wacom - us...
583
  			error = wacom_get_report(hdev, HID_FEATURE_REPORT,
c64d88347   Ping Cheng   HID: wacom - remo...
584
  			                         rep_data, length, 1);
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
585
586
587
  	} while (error >= 0 &&
  		 rep_data[1] != wacom_wac->mode_report &&
  		 limit++ < WAC_MSG_RETRIES);
fe494bc2f   Jason Gerecke   Input: wacom - cl...
588
589
590
591
592
  
  	kfree(rep_data);
  
  	return error < 0 ? error : 0;
  }
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
593
594
595
  static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
  		struct wacom_features *features)
  {
387142bb8   Benjamin Tissoires   Input: wacom - ha...
596
597
598
599
600
601
602
603
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	int ret;
  	u8 rep_data[2];
  
  	switch (features->type) {
  	case GRAPHIRE_BT:
  		rep_data[0] = 0x03;
  		rep_data[1] = 0x00;
296b73787   Przemo Firszt   Input: wacom - re...
604
605
  		ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
  					3);
387142bb8   Benjamin Tissoires   Input: wacom - ha...
606
607
608
609
610
611
  
  		if (ret >= 0) {
  			rep_data[0] = speed == 0 ? 0x05 : 0x06;
  			rep_data[1] = 0x00;
  
  			ret = wacom_set_report(hdev, HID_FEATURE_REPORT,
296b73787   Przemo Firszt   Input: wacom - re...
612
  						rep_data, 2, 3);
387142bb8   Benjamin Tissoires   Input: wacom - ha...
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  
  			if (ret >= 0) {
  				wacom->wacom_wac.bt_high_speed = speed;
  				return 0;
  			}
  		}
  
  		/*
  		 * Note that if the raw queries fail, it's not a hard failure
  		 * and it is safe to continue
  		 */
  		hid_warn(hdev, "failed to poke device, command %d, err %d
  ",
  			 rep_data[0], ret);
  		break;
81af7e61a   Benjamin Tissoires   Input: wacom - ha...
628
629
630
631
632
633
634
635
  	case INTUOS4WL:
  		if (speed == 1)
  			wacom->wacom_wac.bt_features &= ~0x20;
  		else
  			wacom->wacom_wac.bt_features |= 0x20;
  
  		rep_data[0] = 0x03;
  		rep_data[1] = wacom->wacom_wac.bt_features;
296b73787   Przemo Firszt   Input: wacom - re...
636
637
  		ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
  					1);
81af7e61a   Benjamin Tissoires   Input: wacom - ha...
638
639
640
  		if (ret >= 0)
  			wacom->wacom_wac.bt_high_speed = speed;
  		break;
387142bb8   Benjamin Tissoires   Input: wacom - ha...
641
  	}
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
642
643
  	return 0;
  }
fe494bc2f   Jason Gerecke   Input: wacom - cl...
644
645
646
647
648
649
650
  /*
   * Switch the tablet into its most-capable mode. Wacom tablets are
   * typically configured to power-up in a mode which sends mouse-like
   * reports to the OS. To get absolute position, pressure data, etc.
   * from the tablet, it is necessary to switch the tablet out of this
   * mode and into one which sends the full range of tablet data.
   */
a544c619a   Benjamin Tissoires   HID: wacom: do no...
651
  static int _wacom_query_tablet_data(struct wacom *wacom)
fe494bc2f   Jason Gerecke   Input: wacom - cl...
652
  {
a544c619a   Benjamin Tissoires   HID: wacom: do no...
653
  	struct hid_device *hdev = wacom->hdev;
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
654
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
a544c619a   Benjamin Tissoires   HID: wacom: do no...
655
  	struct wacom_features *features = &wacom_wac->features;
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
656

f81a1295c   Benjamin Tissoires   Input: wacom - pr...
657
658
  	if (hdev->bus == BUS_BLUETOOTH)
  		return wacom_bt_query_tablet_data(hdev, 1, features);
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  	if (features->type != HID_GENERIC) {
  		if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
  			if (features->type > TABLETPC) {
  				/* MT Tablet PC touch */
  				wacom_wac->mode_report = 3;
  				wacom_wac->mode_value = 4;
  			} else if (features->type == WACOM_24HDT) {
  				wacom_wac->mode_report = 18;
  				wacom_wac->mode_value = 2;
  			} else if (features->type == WACOM_27QHDT) {
  				wacom_wac->mode_report = 131;
  				wacom_wac->mode_value = 2;
  			} else if (features->type == BAMBOO_PAD) {
  				wacom_wac->mode_report = 2;
  				wacom_wac->mode_value = 2;
  			}
  		} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
  			if (features->type <= BAMBOO_PT) {
  				wacom_wac->mode_report = 2;
  				wacom_wac->mode_value = 2;
  			}
1963518b9   Ping Cheng   Input: wacom - ad...
680
  		}
ec67bbedc   Ping Cheng   Input: wacom - ad...
681
  	}
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
682

326ea2a90   Jason Gerecke   HID: wacom: Suppo...
683
684
685
686
  	wacom_set_device_mode(hdev, wacom_wac);
  
  	if (features->type == HID_GENERIC)
  		return wacom_hid_set_device_mode(hdev);
fe494bc2f   Jason Gerecke   Input: wacom - cl...
687
  	return 0;
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
688
  }
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
689
  static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
1963518b9   Ping Cheng   Input: wacom - ad...
690
  					 struct wacom_features *features)
ec67bbedc   Ping Cheng   Input: wacom - ad...
691
  {
27b20a9de   Benjamin Tissoires   Input: wacom - us...
692
693
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct usb_interface *intf = wacom->intf;
ec67bbedc   Ping Cheng   Input: wacom - ad...
694

fed87e655   Henrik Rydberg   Input: wacom - ad...
695
  	/* default features */
fed87e655   Henrik Rydberg   Input: wacom - ad...
696
697
698
  	features->x_fuzz = 4;
  	features->y_fuzz = 4;
  	features->pressure_fuzz = 0;
bef7e2000   Jason Gerecke   HID: wacom: Add f...
699
700
  	features->distance_fuzz = 1;
  	features->tilt_fuzz = 1;
ec67bbedc   Ping Cheng   Input: wacom - ad...
701

d3825d51c   Chris Bagwell   Input: wacom - wi...
702
703
704
705
706
707
708
  	/*
  	 * The wireless device HID is basic and layout conflicts with
  	 * other tablets (monitor and touch interface can look like pen).
  	 * Skip the query for this type and modify defaults based on
  	 * interface number.
  	 */
  	if (features->type == WIRELESS) {
3f14a63a5   Jason Gerecke   HID: wacom: Remov...
709
  		if (intf->cur_altsetting->desc.bInterfaceNumber == 0)
ccad85cc1   Jason Gerecke   HID: wacom: Repla...
710
  			features->device_type = WACOM_DEVICETYPE_WL_MONITOR;
3f14a63a5   Jason Gerecke   HID: wacom: Remov...
711
  		else
aa86b18cc   Jason Gerecke   HID: wacom: Treat...
712
  			features->device_type = WACOM_DEVICETYPE_NONE;
3f14a63a5   Jason Gerecke   HID: wacom: Remov...
713
  		return;
d3825d51c   Chris Bagwell   Input: wacom - wi...
714
  	}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
715
  	wacom_parse_hid(hdev, features);
ec67bbedc   Ping Cheng   Input: wacom - ad...
716
  }
4451e088c   Benjamin Tissoires   Input: wacom - re...
717
  struct wacom_hdev_data {
4492effff   Ping Cheng   Input: wacom - sh...
718
719
  	struct list_head list;
  	struct kref kref;
4451e088c   Benjamin Tissoires   Input: wacom - re...
720
  	struct hid_device *dev;
4492effff   Ping Cheng   Input: wacom - sh...
721
722
723
724
725
  	struct wacom_shared shared;
  };
  
  static LIST_HEAD(wacom_udev_list);
  static DEFINE_MUTEX(wacom_udev_list_lock);
4451e088c   Benjamin Tissoires   Input: wacom - re...
726
727
  static bool wacom_are_sibling(struct hid_device *hdev,
  		struct hid_device *sibling)
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
728
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
729
730
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
41372d5d4   Jason Gerecke   HID: wacom: Augme...
731
732
733
734
  	struct wacom *sibling_wacom = hid_get_drvdata(sibling);
  	struct wacom_features *sibling_features = &sibling_wacom->wacom_wac.features;
  	__u32 oVid = features->oVid ? features->oVid : hdev->vendor;
  	__u32 oPid = features->oPid ? features->oPid : hdev->product;
4451e088c   Benjamin Tissoires   Input: wacom - re...
735

41372d5d4   Jason Gerecke   HID: wacom: Augme...
736
737
738
739
740
741
742
743
744
745
746
747
  	/* The defined oVid/oPid must match that of the sibling */
  	if (features->oVid != HID_ANY_ID && sibling->vendor != oVid)
  		return false;
  	if (features->oPid != HID_ANY_ID && sibling->product != oPid)
  		return false;
  
  	/*
  	 * Devices with the same VID/PID must share the same physical
  	 * device path, while those with different VID/PID must share
  	 * the same physical parent device path.
  	 */
  	if (hdev->vendor == sibling->vendor && hdev->product == sibling->product) {
1a8861f11   Daniel M. Lambea   HID: cougar: make...
748
  		if (!hid_compare_device_paths(hdev, sibling, '/'))
41372d5d4   Jason Gerecke   HID: wacom: Augme...
749
750
  			return false;
  	} else {
1a8861f11   Daniel M. Lambea   HID: cougar: make...
751
  		if (!hid_compare_device_paths(hdev, sibling, '.'))
41372d5d4   Jason Gerecke   HID: wacom: Augme...
752
  			return false;
4451e088c   Benjamin Tissoires   Input: wacom - re...
753
  	}
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
754

41372d5d4   Jason Gerecke   HID: wacom: Augme...
755
756
757
758
759
760
761
762
763
764
  	/* Skip the remaining heuristics unless you are a HID_GENERIC device */
  	if (features->type != HID_GENERIC)
  		return true;
  
  	/*
  	 * Direct-input devices may not be siblings of indirect-input
  	 * devices.
  	 */
  	if ((features->device_type & WACOM_DEVICETYPE_DIRECT) &&
  	    !(sibling_features->device_type & WACOM_DEVICETYPE_DIRECT))
4451e088c   Benjamin Tissoires   Input: wacom - re...
765
  		return false;
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
766

41372d5d4   Jason Gerecke   HID: wacom: Augme...
767
768
769
770
771
772
  	/*
  	 * Indirect-input devices may not be siblings of direct-input
  	 * devices.
  	 */
  	if (!(features->device_type & WACOM_DEVICETYPE_DIRECT) &&
  	    (sibling_features->device_type & WACOM_DEVICETYPE_DIRECT))
4451e088c   Benjamin Tissoires   Input: wacom - re...
773
  		return false;
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
774

41372d5d4   Jason Gerecke   HID: wacom: Augme...
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
  	/* Pen devices may only be siblings of touch devices */
  	if ((features->device_type & WACOM_DEVICETYPE_PEN) &&
  	    !(sibling_features->device_type & WACOM_DEVICETYPE_TOUCH))
  		return false;
  
  	/* Touch devices may only be siblings of pen devices */
  	if ((features->device_type & WACOM_DEVICETYPE_TOUCH) &&
  	    !(sibling_features->device_type & WACOM_DEVICETYPE_PEN))
  		return false;
  
  	/*
  	 * No reason could be found for these two devices to NOT be
  	 * siblings, so there's a good chance they ARE siblings
  	 */
  	return true;
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
790
  }
4451e088c   Benjamin Tissoires   Input: wacom - re...
791
  static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
4492effff   Ping Cheng   Input: wacom - sh...
792
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
793
  	struct wacom_hdev_data *data;
4492effff   Ping Cheng   Input: wacom - sh...
794

41372d5d4   Jason Gerecke   HID: wacom: Augme...
795
796
  	/* Try to find an already-probed interface from the same device */
  	list_for_each_entry(data, &wacom_udev_list, list) {
1a8861f11   Daniel M. Lambea   HID: cougar: make...
797
  		if (hid_compare_device_paths(hdev, data->dev, '/')) {
2a5e597c6   Jason Gerecke   HID: wacom: Alway...
798
  			kref_get(&data->kref);
41372d5d4   Jason Gerecke   HID: wacom: Augme...
799
  			return data;
2a5e597c6   Jason Gerecke   HID: wacom: Alway...
800
  		}
41372d5d4   Jason Gerecke   HID: wacom: Augme...
801
802
803
  	}
  
  	/* Fallback to finding devices that appear to be "siblings" */
4492effff   Ping Cheng   Input: wacom - sh...
804
  	list_for_each_entry(data, &wacom_udev_list, list) {
4451e088c   Benjamin Tissoires   Input: wacom - re...
805
  		if (wacom_are_sibling(hdev, data->dev)) {
4492effff   Ping Cheng   Input: wacom - sh...
806
807
808
809
810
811
812
  			kref_get(&data->kref);
  			return data;
  		}
  	}
  
  	return NULL;
  }
1c817c83e   Benjamin Tissoires   HID: wacom: devre...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
  static void wacom_release_shared_data(struct kref *kref)
  {
  	struct wacom_hdev_data *data =
  		container_of(kref, struct wacom_hdev_data, kref);
  
  	mutex_lock(&wacom_udev_list_lock);
  	list_del(&data->list);
  	mutex_unlock(&wacom_udev_list_lock);
  
  	kfree(data);
  }
  
  static void wacom_remove_shared_data(void *res)
  {
  	struct wacom *wacom = res;
  	struct wacom_hdev_data *data;
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  
  	if (wacom_wac->shared) {
  		data = container_of(wacom_wac->shared, struct wacom_hdev_data,
  				    shared);
  
  		if (wacom_wac->shared->touch == wacom->hdev)
  			wacom_wac->shared->touch = NULL;
  		else if (wacom_wac->shared->pen == wacom->hdev)
  			wacom_wac->shared->pen = NULL;
  
  		kref_put(&data->kref, wacom_release_shared_data);
  		wacom_wac->shared = NULL;
  	}
  }
4451e088c   Benjamin Tissoires   Input: wacom - re...
844
  static int wacom_add_shared_data(struct hid_device *hdev)
4492effff   Ping Cheng   Input: wacom - sh...
845
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
846
847
848
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct wacom_hdev_data *data;
4492effff   Ping Cheng   Input: wacom - sh...
849
850
851
  	int retval = 0;
  
  	mutex_lock(&wacom_udev_list_lock);
4451e088c   Benjamin Tissoires   Input: wacom - re...
852
  	data = wacom_get_hdev_data(hdev);
4492effff   Ping Cheng   Input: wacom - sh...
853
  	if (!data) {
4451e088c   Benjamin Tissoires   Input: wacom - re...
854
  		data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
4492effff   Ping Cheng   Input: wacom - sh...
855
856
857
858
859
860
  		if (!data) {
  			retval = -ENOMEM;
  			goto out;
  		}
  
  		kref_init(&data->kref);
4451e088c   Benjamin Tissoires   Input: wacom - re...
861
  		data->dev = hdev;
4492effff   Ping Cheng   Input: wacom - sh...
862
863
  		list_add_tail(&data->list, &wacom_udev_list);
  	}
4451e088c   Benjamin Tissoires   Input: wacom - re...
864
  	wacom_wac->shared = &data->shared;
4492effff   Ping Cheng   Input: wacom - sh...
865

1c817c83e   Benjamin Tissoires   HID: wacom: devre...
866
867
868
869
870
871
  	retval = devm_add_action(&hdev->dev, wacom_remove_shared_data, wacom);
  	if (retval) {
  		mutex_unlock(&wacom_udev_list_lock);
  		wacom_remove_shared_data(wacom);
  		return retval;
  	}
a9ce7856c   Jason Gerecke   HID: wacom: Fix s...
872
873
874
875
  	if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
  		wacom_wac->shared->touch = hdev;
  	else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
  		wacom_wac->shared->pen = hdev;
4492effff   Ping Cheng   Input: wacom - sh...
876
877
878
879
  out:
  	mutex_unlock(&wacom_udev_list_lock);
  	return retval;
  }
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
880
881
882
  static int wacom_led_control(struct wacom *wacom)
  {
  	unsigned char *buf;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
883
  	int retval;
912ca216b   Ping Cheng   HID: wacom - enab...
884
885
  	unsigned char report_id = WAC_CMD_LED_CONTROL;
  	int buf_size = 9;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
886

a50aac719   Benjamin Tissoires   HID: wacom: leds:...
887
888
  	if (!wacom->led.groups)
  		return -ENOTSUPP;
74aebed6d   Aaron Armstrong Skomra   HID: wacom: leds:...
889
890
  	if (wacom->wacom_wac.features.type == REMOTE)
  		return -ENOTSUPP;
912ca216b   Ping Cheng   HID: wacom - enab...
891
892
893
894
  	if (wacom->wacom_wac.pid) { /* wireless connected */
  		report_id = WAC_CMD_WL_LED_CONTROL;
  		buf_size = 13;
  	}
4922cd26f   Jason Gerecke   HID: wacom: Suppo...
895
896
897
898
  	else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
  		report_id = WAC_CMD_WL_INTUOSP2;
  		buf_size = 51;
  	}
912ca216b   Ping Cheng   HID: wacom - enab...
899
  	buf = kzalloc(buf_size, GFP_KERNEL);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
900
901
  	if (!buf)
  		return -ENOMEM;
10c55cacb   Aaron Armstrong Skomra   HID: wacom: gener...
902
903
904
905
906
907
908
  	if (wacom->wacom_wac.features.type == HID_GENERIC) {
  		buf[0] = WAC_CMD_LED_CONTROL_GENERIC;
  		buf[1] = wacom->led.llv;
  		buf[2] = wacom->led.groups[0].select & 0x03;
  
  	} else if ((wacom->wacom_wac.features.type >= INTUOS5S &&
  	    wacom->wacom_wac.features.type <= INTUOSPL)) {
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
909
910
911
912
913
  		/*
  		 * Touch Ring and crop mark LED luminance may take on
  		 * one of four values:
  		 *    0 = Low; 1 = Medium; 2 = High; 3 = Off
  		 */
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
914
  		int ring_led = wacom->led.groups[0].select & 0x03;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
915
916
  		int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
  		int crop_lum = 0;
912ca216b   Ping Cheng   HID: wacom - enab...
917
918
919
920
921
922
923
924
925
926
  		unsigned char led_bits = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
  
  		buf[0] = report_id;
  		if (wacom->wacom_wac.pid) {
  			wacom_get_report(wacom->hdev, HID_FEATURE_REPORT,
  					 buf, buf_size, WAC_CMD_RETRIES);
  			buf[0] = report_id;
  			buf[4] = led_bits;
  		} else
  			buf[1] = led_bits;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
927
  	}
4922cd26f   Jason Gerecke   HID: wacom: Suppo...
928
929
930
931
932
933
934
935
936
937
  	else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
  		buf[0] = report_id;
  		buf[4] = 100; // Power Connection LED (ORANGE)
  		buf[5] = 100; // BT Connection LED (BLUE)
  		buf[6] = 100; // Paper Mode (RED?)
  		buf[7] = 100; // Paper Mode (GREEN?)
  		buf[8] = 100; // Paper Mode (BLUE?)
  		buf[9] = wacom->led.llv;
  		buf[10] = wacom->led.groups[0].select & 0x03;
  	}
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
938
  	else {
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
939
  		int led = wacom->led.groups[0].select | 0x4;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
940
941
942
  
  		if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
  		    wacom->wacom_wac.features.type == WACOM_24HD)
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
943
  			led |= (wacom->led.groups[1].select << 4) | 0x40;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
944

912ca216b   Ping Cheng   HID: wacom - enab...
945
  		buf[0] = report_id;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
946
947
948
949
950
  		buf[1] = led;
  		buf[2] = wacom->led.llv;
  		buf[3] = wacom->led.hlv;
  		buf[4] = wacom->led.img_lum;
  	}
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
951

912ca216b   Ping Cheng   HID: wacom - enab...
952
  	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, buf_size,
296b73787   Przemo Firszt   Input: wacom - re...
953
  				  WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
954
955
956
957
  	kfree(buf);
  
  	return retval;
  }
849e2f067   Benjamin Tissoires   Input: wacom - ch...
958
959
  static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id,
  		const unsigned len, const void *img)
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
960
961
962
  {
  	unsigned char *buf;
  	int i, retval;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
963
  	const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
964

849e2f067   Benjamin Tissoires   Input: wacom - ch...
965
  	buf = kzalloc(chunk_len + 3 , GFP_KERNEL);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
966
967
968
969
970
971
  	if (!buf)
  		return -ENOMEM;
  
  	/* Send 'start' command */
  	buf[0] = WAC_CMD_ICON_START;
  	buf[1] = 1;
296b73787   Przemo Firszt   Input: wacom - re...
972
973
  	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
  				  WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
974
975
  	if (retval < 0)
  		goto out;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
976
  	buf[0] = xfer_id;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
977
978
979
  	buf[1] = button_id & 0x07;
  	for (i = 0; i < 4; i++) {
  		buf[2] = i;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
980
  		memcpy(buf + 3, img + i * chunk_len, chunk_len);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
981

27b20a9de   Benjamin Tissoires   Input: wacom - us...
982
  		retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
296b73787   Przemo Firszt   Input: wacom - re...
983
  					  buf, chunk_len + 3, WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
984
985
986
987
988
989
990
  		if (retval < 0)
  			break;
  	}
  
  	/* Send 'stop' */
  	buf[0] = WAC_CMD_ICON_START;
  	buf[1] = 0;
296b73787   Przemo Firszt   Input: wacom - re...
991
992
  	wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
  			 WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
993
994
995
996
997
  
  out:
  	kfree(buf);
  	return retval;
  }
09e7d9410   Ping Cheng   Input: wacom - ad...
998
  static ssize_t wacom_led_select_store(struct device *dev, int set_id,
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
999
1000
  				      const char *buf, size_t count)
  {
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1001
  	struct hid_device *hdev = to_hid_device(dev);
29b473913   Benjamin Tissoires   Input: wacom - sw...
1002
  	struct wacom *wacom = hid_get_drvdata(hdev);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1003
1004
1005
1006
1007
1008
1009
1010
  	unsigned int id;
  	int err;
  
  	err = kstrtouint(buf, 10, &id);
  	if (err)
  		return err;
  
  	mutex_lock(&wacom->lock);
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1011
  	wacom->led.groups[set_id].select = id & 0x3;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1012
1013
1014
1015
1016
1017
  	err = wacom_led_control(wacom);
  
  	mutex_unlock(&wacom->lock);
  
  	return err < 0 ? err : count;
  }
09e7d9410   Ping Cheng   Input: wacom - ad...
1018
1019
1020
1021
1022
1023
  #define DEVICE_LED_SELECT_ATTR(SET_ID)					\
  static ssize_t wacom_led##SET_ID##_select_store(struct device *dev,	\
  	struct device_attribute *attr, const char *buf, size_t count)	\
  {									\
  	return wacom_led_select_store(dev, SET_ID, buf, count);		\
  }									\
04c59abd3   Ping Cheng   Input: wacom - ma...
1024
1025
1026
  static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,	\
  	struct device_attribute *attr, char *buf)			\
  {									\
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1027
  	struct hid_device *hdev = to_hid_device(dev);\
29b473913   Benjamin Tissoires   Input: wacom - sw...
1028
  	struct wacom *wacom = hid_get_drvdata(hdev);			\
37449adc5   Ping Cheng   HID: wacom - Clea...
1029
1030
  	return scnprintf(buf, PAGE_SIZE, "%d
  ",			\
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1031
  			 wacom->led.groups[SET_ID].select);		\
04c59abd3   Ping Cheng   Input: wacom - ma...
1032
  }									\
e0984bc37   Ping Cheng   HID: wacom - Add ...
1033
  static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM,	\
04c59abd3   Ping Cheng   Input: wacom - ma...
1034
  		    wacom_led##SET_ID##_select_show,			\
09e7d9410   Ping Cheng   Input: wacom - ad...
1035
1036
1037
1038
  		    wacom_led##SET_ID##_select_store)
  
  DEVICE_LED_SELECT_ATTR(0);
  DEVICE_LED_SELECT_ATTR(1);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  
  static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
  				     const char *buf, size_t count)
  {
  	unsigned int value;
  	int err;
  
  	err = kstrtouint(buf, 10, &value);
  	if (err)
  		return err;
  
  	mutex_lock(&wacom->lock);
  
  	*dest = value & 0x7f;
  	err = wacom_led_control(wacom);
  
  	mutex_unlock(&wacom->lock);
  
  	return err < 0 ? err : count;
  }
  
  #define DEVICE_LUMINANCE_ATTR(name, field)				\
  static ssize_t wacom_##name##_luminance_store(struct device *dev,	\
  	struct device_attribute *attr, const char *buf, size_t count)	\
  {									\
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1064
  	struct hid_device *hdev = to_hid_device(dev);\
29b473913   Benjamin Tissoires   Input: wacom - sw...
1065
  	struct wacom *wacom = hid_get_drvdata(hdev);			\
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1066
1067
1068
1069
  									\
  	return wacom_luminance_store(wacom, &wacom->led.field,		\
  				     buf, count);			\
  }									\
37449adc5   Ping Cheng   HID: wacom - Clea...
1070
1071
1072
1073
1074
1075
1076
  static ssize_t wacom_##name##_luminance_show(struct device *dev,	\
  	struct device_attribute *attr, char *buf)			\
  {									\
  	struct wacom *wacom = dev_get_drvdata(dev);			\
  	return scnprintf(buf, PAGE_SIZE, "%d
  ", wacom->led.field);	\
  }									\
e0984bc37   Ping Cheng   HID: wacom - Add ...
1077
  static DEVICE_ATTR(name##_luminance, DEV_ATTR_RW_PERM,			\
37449adc5   Ping Cheng   HID: wacom - Clea...
1078
1079
  		   wacom_##name##_luminance_show,			\
  		   wacom_##name##_luminance_store)
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1080
1081
1082
1083
1084
1085
1086
1087
  
  DEVICE_LUMINANCE_ATTR(status0, llv);
  DEVICE_LUMINANCE_ATTR(status1, hlv);
  DEVICE_LUMINANCE_ATTR(buttons, img_lum);
  
  static ssize_t wacom_button_image_store(struct device *dev, int button_id,
  					const char *buf, size_t count)
  {
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1088
  	struct hid_device *hdev = to_hid_device(dev);
29b473913   Benjamin Tissoires   Input: wacom - sw...
1089
  	struct wacom *wacom = hid_get_drvdata(hdev);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1090
  	int err;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  	unsigned len;
  	u8 xfer_id;
  
  	if (hdev->bus == BUS_BLUETOOTH) {
  		len = 256;
  		xfer_id = WAC_CMD_ICON_BT_XFER;
  	} else {
  		len = 1024;
  		xfer_id = WAC_CMD_ICON_XFER;
  	}
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1101

849e2f067   Benjamin Tissoires   Input: wacom - ch...
1102
  	if (count != len)
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1103
1104
1105
  		return -EINVAL;
  
  	mutex_lock(&wacom->lock);
849e2f067   Benjamin Tissoires   Input: wacom - ch...
1106
  	err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  
  	mutex_unlock(&wacom->lock);
  
  	return err < 0 ? err : count;
  }
  
  #define DEVICE_BTNIMG_ATTR(BUTTON_ID)					\
  static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev,	\
  	struct device_attribute *attr, const char *buf, size_t count)	\
  {									\
  	return wacom_button_image_store(dev, BUTTON_ID, buf, count);	\
  }									\
e0984bc37   Ping Cheng   HID: wacom - Add ...
1119
  static DEVICE_ATTR(button##BUTTON_ID##_rawimg, DEV_ATTR_WO_PERM,	\
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
  		   NULL, wacom_btnimg##BUTTON_ID##_store)
  
  DEVICE_BTNIMG_ATTR(0);
  DEVICE_BTNIMG_ATTR(1);
  DEVICE_BTNIMG_ATTR(2);
  DEVICE_BTNIMG_ATTR(3);
  DEVICE_BTNIMG_ATTR(4);
  DEVICE_BTNIMG_ATTR(5);
  DEVICE_BTNIMG_ATTR(6);
  DEVICE_BTNIMG_ATTR(7);
09e7d9410   Ping Cheng   Input: wacom - ad...
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
  static struct attribute *cintiq_led_attrs[] = {
  	&dev_attr_status_led0_select.attr,
  	&dev_attr_status_led1_select.attr,
  	NULL
  };
  
  static struct attribute_group cintiq_led_attr_group = {
  	.name = "wacom_led",
  	.attrs = cintiq_led_attrs,
  };
  
  static struct attribute *intuos4_led_attrs[] = {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1142
1143
  	&dev_attr_status0_luminance.attr,
  	&dev_attr_status1_luminance.attr,
09e7d9410   Ping Cheng   Input: wacom - ad...
1144
  	&dev_attr_status_led0_select.attr,
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
  	&dev_attr_buttons_luminance.attr,
  	&dev_attr_button0_rawimg.attr,
  	&dev_attr_button1_rawimg.attr,
  	&dev_attr_button2_rawimg.attr,
  	&dev_attr_button3_rawimg.attr,
  	&dev_attr_button4_rawimg.attr,
  	&dev_attr_button5_rawimg.attr,
  	&dev_attr_button6_rawimg.attr,
  	&dev_attr_button7_rawimg.attr,
  	NULL
  };
09e7d9410   Ping Cheng   Input: wacom - ad...
1156
  static struct attribute_group intuos4_led_attr_group = {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1157
  	.name = "wacom_led",
09e7d9410   Ping Cheng   Input: wacom - ad...
1158
  	.attrs = intuos4_led_attrs,
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1159
  };
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  static struct attribute *intuos5_led_attrs[] = {
  	&dev_attr_status0_luminance.attr,
  	&dev_attr_status_led0_select.attr,
  	NULL
  };
  
  static struct attribute_group intuos5_led_attr_group = {
  	.name = "wacom_led",
  	.attrs = intuos5_led_attrs,
  };
10c55cacb   Aaron Armstrong Skomra   HID: wacom: gener...
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
  static struct attribute *generic_led_attrs[] = {
  	&dev_attr_status0_luminance.attr,
  	&dev_attr_status_led0_select.attr,
  	NULL
  };
  
  static struct attribute_group generic_led_attr_group = {
  	.name = "wacom_led",
  	.attrs = generic_led_attrs,
  };
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
  struct wacom_sysfs_group_devres {
  	struct attribute_group *group;
  	struct kobject *root;
  };
  
  static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
  {
  	struct wacom_sysfs_group_devres *devres = res;
  	struct kobject *kobj = devres->root;
  
  	dev_dbg(dev, "%s: dropping reference to %s
  ",
  		__func__, devres->group->name);
  	sysfs_remove_group(kobj, devres->group);
  }
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
1195
1196
1197
  static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
  					   struct kobject *root,
  					   struct attribute_group *group)
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  {
  	struct wacom_sysfs_group_devres *devres;
  	int error;
  
  	devres = devres_alloc(wacom_devm_sysfs_group_release,
  			      sizeof(struct wacom_sysfs_group_devres),
  			      GFP_KERNEL);
  	if (!devres)
  		return -ENOMEM;
  
  	devres->group = group;
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
1209
  	devres->root = root;
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1210
1211
  
  	error = sysfs_create_group(devres->root, group);
097b8f62d   Arvind Yadav   HID: wacom: Relea...
1212
1213
  	if (error) {
  		devres_free(devres);
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1214
  		return error;
097b8f62d   Arvind Yadav   HID: wacom: Relea...
1215
  	}
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1216
1217
1218
1219
1220
  
  	devres_add(&wacom->hdev->dev, devres);
  
  	return 0;
  }
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
1221
1222
1223
1224
1225
1226
  static int wacom_devm_sysfs_create_group(struct wacom *wacom,
  					 struct attribute_group *group)
  {
  	return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj,
  					       group);
  }
797c128d3   Ping Cheng   HID: wacom: Fix m...
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
  static void wacom_devm_kfifo_release(struct device *dev, void *res)
  {
  	struct kfifo_rec_ptr_2 *devres = res;
  
  	kfifo_free(devres);
  }
  
  static int wacom_devm_kfifo_alloc(struct wacom *wacom)
  {
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct kfifo_rec_ptr_2 *pen_fifo = &wacom_wac->pen_fifo;
  	int error;
  
  	pen_fifo = devres_alloc(wacom_devm_kfifo_release,
  			      sizeof(struct kfifo_rec_ptr_2),
  			      GFP_KERNEL);
  
  	if (!pen_fifo)
  		return -ENOMEM;
  
  	error = kfifo_alloc(pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
  	if (error) {
  		devres_free(pen_fifo);
  		return error;
  	}
  
  	devres_add(&wacom->hdev->dev, pen_fifo);
  
  	return 0;
  }
34736aa96   Benjamin Tissoires   HID: wacom: leds:...
1257
  enum led_brightness wacom_leds_brightness_get(struct wacom_led *led)
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  {
  	struct wacom *wacom = led->wacom;
  
  	if (wacom->led.max_hlv)
  		return led->hlv * LED_FULL / wacom->led.max_hlv;
  
  	if (wacom->led.max_llv)
  		return led->llv * LED_FULL / wacom->led.max_llv;
  
  	/* device doesn't support brightness tuning */
  	return LED_FULL;
  }
  
  static enum led_brightness __wacom_led_brightness_get(struct led_classdev *cdev)
  {
  	struct wacom_led *led = container_of(cdev, struct wacom_led, cdev);
  	struct wacom *wacom = led->wacom;
  
  	if (wacom->led.groups[led->group].select != led->id)
  		return LED_OFF;
  
  	return wacom_leds_brightness_get(led);
  }
  
  static int wacom_led_brightness_set(struct led_classdev *cdev,
  				    enum led_brightness brightness)
  {
  	struct wacom_led *led = container_of(cdev, struct wacom_led, cdev);
  	struct wacom *wacom = led->wacom;
  	int error;
  
  	mutex_lock(&wacom->lock);
  
  	if (!wacom->led.groups || (brightness == LED_OFF &&
  	    wacom->led.groups[led->group].select != led->id)) {
  		error = 0;
  		goto out;
  	}
  
  	led->llv = wacom->led.llv = wacom->led.max_llv * brightness / LED_FULL;
  	led->hlv = wacom->led.hlv = wacom->led.max_hlv * brightness / LED_FULL;
  
  	wacom->led.groups[led->group].select = led->id;
  
  	error = wacom_led_control(wacom);
  
  out:
  	mutex_unlock(&wacom->lock);
  
  	return error;
  }
  
  static void wacom_led_readonly_brightness_set(struct led_classdev *cdev,
  					       enum led_brightness brightness)
  {
  }
  
  static int wacom_led_register_one(struct device *dev, struct wacom *wacom,
  				  struct wacom_led *led, unsigned int group,
  				  unsigned int id, bool read_only)
  {
  	int error;
  	char *name;
  
  	name = devm_kasprintf(dev, GFP_KERNEL,
  			      "%s::wacom-%d.%d",
  			      dev_name(dev),
  			      group,
  			      id);
  	if (!name)
  		return -ENOMEM;
34736aa96   Benjamin Tissoires   HID: wacom: leds:...
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  	if (!read_only) {
  		led->trigger.name = name;
  		error = devm_led_trigger_register(dev, &led->trigger);
  		if (error) {
  			hid_err(wacom->hdev,
  				"failed to register LED trigger %s: %d
  ",
  				led->cdev.name, error);
  			return error;
  		}
  	}
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1340
1341
1342
1343
1344
1345
1346
1347
1348
  	led->group = group;
  	led->id = id;
  	led->wacom = wacom;
  	led->llv = wacom->led.llv;
  	led->hlv = wacom->led.hlv;
  	led->cdev.name = name;
  	led->cdev.max_brightness = LED_FULL;
  	led->cdev.flags = LED_HW_PLUGGABLE;
  	led->cdev.brightness_get = __wacom_led_brightness_get;
34736aa96   Benjamin Tissoires   HID: wacom: leds:...
1349
  	if (!read_only) {
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1350
  		led->cdev.brightness_set_blocking = wacom_led_brightness_set;
34736aa96   Benjamin Tissoires   HID: wacom: leds:...
1351
1352
  		led->cdev.default_trigger = led->cdev.name;
  	} else {
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1353
  		led->cdev.brightness_set = wacom_led_readonly_brightness_set;
34736aa96   Benjamin Tissoires   HID: wacom: leds:...
1354
  	}
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  
  	error = devm_led_classdev_register(dev, &led->cdev);
  	if (error) {
  		hid_err(wacom->hdev,
  			"failed to register LED %s: %d
  ",
  			led->cdev.name, error);
  		led->cdev.name = NULL;
  		return error;
  	}
  
  	return 0;
  }
589e50602   Benjamin Tissoires   HID: wacom: leds:...
1368
1369
1370
1371
1372
1373
  static void wacom_led_groups_release_one(void *data)
  {
  	struct wacom_group_leds *group = data;
  
  	devres_release_group(group->dev, group);
  }
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
  static int wacom_led_groups_alloc_and_register_one(struct device *dev,
  						   struct wacom *wacom,
  						   int group_id, int count,
  						   bool read_only)
  {
  	struct wacom_led *leds;
  	int i, error;
  
  	if (group_id >= wacom->led.count || count <= 0)
  		return -EINVAL;
  
  	if (!devres_open_group(dev, &wacom->led.groups[group_id], GFP_KERNEL))
  		return -ENOMEM;
a86854d0c   Kees Cook   treewide: devm_kz...
1387
  	leds = devm_kcalloc(dev, count, sizeof(struct wacom_led), GFP_KERNEL);
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
  	if (!leds) {
  		error = -ENOMEM;
  		goto err;
  	}
  
  	wacom->led.groups[group_id].leds = leds;
  	wacom->led.groups[group_id].count = count;
  
  	for (i = 0; i < count; i++) {
  		error = wacom_led_register_one(dev, wacom, &leds[i],
  					       group_id, i, read_only);
  		if (error)
  			goto err;
  	}
589e50602   Benjamin Tissoires   HID: wacom: leds:...
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
  	wacom->led.groups[group_id].dev = dev;
  
  	devres_close_group(dev, &wacom->led.groups[group_id]);
  
  	/*
  	 * There is a bug (?) in devm_led_classdev_register() in which its
  	 * increments the refcount of the parent. If the parent is an input
  	 * device, that means the ref count never reaches 0 when
  	 * devm_input_device_release() gets called.
  	 * This means that the LEDs are still there after disconnect.
  	 * Manually force the release of the group so that the leds are released
  	 * once we are done using them.
  	 */
  	error = devm_add_action_or_reset(&wacom->hdev->dev,
  					 wacom_led_groups_release_one,
  					 &wacom->led.groups[group_id]);
  	if (error)
  		return error;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1420
1421
1422
1423
1424
1425
  	return 0;
  
  err:
  	devres_release_group(dev, &wacom->led.groups[group_id]);
  	return error;
  }
34736aa96   Benjamin Tissoires   HID: wacom: leds:...
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
  struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group_id,
  				 unsigned int id)
  {
  	struct wacom_group_leds *group;
  
  	if (group_id >= wacom->led.count)
  		return NULL;
  
  	group = &wacom->led.groups[group_id];
  
  	if (!group->leds)
  		return NULL;
  
  	id %= group->count;
  
  	return &group->leds[id];
  }
  
  /**
   * wacom_led_next: gives the next available led with a wacom trigger.
   *
   * returns the next available struct wacom_led which has its default trigger
   * or the current one if none is available.
   */
  struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur)
  {
  	struct wacom_led *next_led;
  	int group, next;
  
  	if (!wacom || !cur)
  		return NULL;
  
  	group = cur->group;
  	next = cur->id;
  
  	do {
  		next_led = wacom_led_find(wacom, group, ++next);
  		if (!next_led || next_led == cur)
  			return next_led;
  	} while (next_led->cdev.trigger != &next_led->trigger);
  
  	return next_led;
  }
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1469
1470
1471
1472
1473
  static void wacom_led_groups_release(void *data)
  {
  	struct wacom *wacom = data;
  
  	wacom->led.groups = NULL;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1474
  	wacom->led.count = 0;
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1475
1476
1477
1478
  }
  
  static int wacom_led_groups_allocate(struct wacom *wacom, int count)
  {
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1479
  	struct device *dev = &wacom->hdev->dev;
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1480
1481
  	struct wacom_group_leds *groups;
  	int error;
a86854d0c   Kees Cook   treewide: devm_kz...
1482
  	groups = devm_kcalloc(dev, count, sizeof(struct wacom_group_leds),
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1483
1484
1485
  			      GFP_KERNEL);
  	if (!groups)
  		return -ENOMEM;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1486
  	error = devm_add_action_or_reset(dev, wacom_led_groups_release, wacom);
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1487
1488
1489
1490
  	if (error)
  		return error;
  
  	wacom->led.groups = groups;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  	wacom->led.count = count;
  
  	return 0;
  }
  
  static int wacom_leds_alloc_and_register(struct wacom *wacom, int group_count,
  					 int led_per_group, bool read_only)
  {
  	struct device *dev;
  	int i, error;
  
  	if (!wacom->wacom_wac.pad_input)
  		return -EINVAL;
  
  	dev = &wacom->wacom_wac.pad_input->dev;
  
  	error = wacom_led_groups_allocate(wacom, group_count);
  	if (error)
  		return error;
  
  	for (i = 0; i < group_count; i++) {
  		error = wacom_led_groups_alloc_and_register_one(dev, wacom, i,
  								led_per_group,
  								read_only);
  		if (error)
  			return error;
  	}
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1518
1519
1520
  
  	return 0;
  }
10c55cacb   Aaron Armstrong Skomra   HID: wacom: gener...
1521
  int wacom_initialize_leds(struct wacom *wacom)
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1522
1523
  {
  	int error;
862cf5535   Jason Gerecke   HID: wacom: Intro...
1524
1525
  	if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD))
  		return 0;
09e7d9410   Ping Cheng   Input: wacom - ad...
1526
1527
  	/* Initialize default values */
  	switch (wacom->wacom_wac.features.type) {
10c55cacb   Aaron Armstrong Skomra   HID: wacom: gener...
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
  	case HID_GENERIC:
  		if (!wacom->generic_has_leds)
  			return 0;
  		wacom->led.llv = 100;
  		wacom->led.max_llv = 100;
  
  		error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
  		if (error) {
  			hid_err(wacom->hdev,
  				"cannot create leds err: %d
  ", error);
  			return error;
  		}
  
  		error = wacom_devm_sysfs_create_group(wacom,
  						      &generic_led_attr_group);
  		break;
a19fc9868   Jason Gerecke   Input: wacom - in...
1545
  	case INTUOS4S:
09e7d9410   Ping Cheng   Input: wacom - ad...
1546
  	case INTUOS4:
81af7e61a   Benjamin Tissoires   Input: wacom - ha...
1547
  	case INTUOS4WL:
09e7d9410   Ping Cheng   Input: wacom - ad...
1548
  	case INTUOS4L:
f4fa9a6d8   Ping Cheng   Input: wacom - lo...
1549
  		wacom->led.llv = 10;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1550
  		wacom->led.hlv = 20;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1551
1552
  		wacom->led.max_llv = 127;
  		wacom->led.max_hlv = 127;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1553
  		wacom->led.img_lum = 10;
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1554

97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1555
  		error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1556
1557
1558
1559
1560
1561
  		if (error) {
  			hid_err(wacom->hdev,
  				"cannot create leds err: %d
  ", error);
  			return error;
  		}
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1562
1563
  		error = wacom_devm_sysfs_create_group(wacom,
  						      &intuos4_led_attr_group);
09e7d9410   Ping Cheng   Input: wacom - ad...
1564
  		break;
246835fcc   Jason Gerecke   Input: wacom - ad...
1565
  	case WACOM_24HD:
09e7d9410   Ping Cheng   Input: wacom - ad...
1566
  	case WACOM_21UX2:
09e7d9410   Ping Cheng   Input: wacom - ad...
1567
1568
1569
  		wacom->led.llv = 0;
  		wacom->led.hlv = 0;
  		wacom->led.img_lum = 0;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1570

97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1571
  		error = wacom_leds_alloc_and_register(wacom, 2, 4, false);
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1572
1573
1574
1575
1576
1577
  		if (error) {
  			hid_err(wacom->hdev,
  				"cannot create leds err: %d
  ", error);
  			return error;
  		}
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1578
1579
  		error = wacom_devm_sysfs_create_group(wacom,
  						      &cintiq_led_attr_group);
09e7d9410   Ping Cheng   Input: wacom - ad...
1580
  		break;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
1581
1582
1583
  	case INTUOS5S:
  	case INTUOS5:
  	case INTUOS5L:
9a35c411f   Ping Cheng   Input: wacom - ad...
1584
1585
1586
  	case INTUOSPS:
  	case INTUOSPM:
  	case INTUOSPL:
862cf5535   Jason Gerecke   HID: wacom: Intro...
1587
  		wacom->led.llv = 32;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1588
  		wacom->led.max_llv = 96;
862cf5535   Jason Gerecke   HID: wacom: Intro...
1589

97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1590
  		error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1591
1592
1593
1594
1595
1596
  		if (error) {
  			hid_err(wacom->hdev,
  				"cannot create leds err: %d
  ", error);
  			return error;
  		}
2df68a886   Benjamin Tissoires   HID: wacom: conve...
1597
1598
  		error = wacom_devm_sysfs_create_group(wacom,
  						      &intuos5_led_attr_group);
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
1599
  		break;
4922cd26f   Jason Gerecke   HID: wacom: Suppo...
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
  	case INTUOSP2_BT:
  		wacom->led.llv = 50;
  		wacom->led.max_llv = 100;
  		error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
  		if (error) {
  			hid_err(wacom->hdev,
  				"cannot create leds err: %d
  ", error);
  			return error;
  		}
  		return 0;
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1611
  	case REMOTE:
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
1612
1613
  		wacom->led.llv = 255;
  		wacom->led.max_llv = 255;
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1614
1615
1616
1617
1618
1619
1620
1621
  		error = wacom_led_groups_allocate(wacom, 5);
  		if (error) {
  			hid_err(wacom->hdev,
  				"cannot create leds err: %d
  ", error);
  			return error;
  		}
  		return 0;
09e7d9410   Ping Cheng   Input: wacom - ad...
1622
1623
  	default:
  		return 0;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1624
  	}
09e7d9410   Ping Cheng   Input: wacom - ad...
1625
  	if (error) {
c31a408f7   Benjamin Tissoires   Input: wacom - in...
1626
  		hid_err(wacom->hdev,
09e7d9410   Ping Cheng   Input: wacom - ad...
1627
1628
1629
1630
  			"cannot create sysfs group err: %d
  ", error);
  		return error;
  	}
09e7d9410   Ping Cheng   Input: wacom - ad...
1631

5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1632
1633
  	return 0;
  }
a544c619a   Benjamin Tissoires   HID: wacom: do no...
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
  static void wacom_init_work(struct work_struct *work)
  {
  	struct wacom *wacom = container_of(work, struct wacom, init_work.work);
  
  	_wacom_query_tablet_data(wacom);
  	wacom_led_control(wacom);
  }
  
  static void wacom_query_tablet_data(struct wacom *wacom)
  {
  	schedule_delayed_work(&wacom->init_work, msecs_to_jiffies(1000));
  }
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1646
  static enum power_supply_property wacom_battery_props[] = {
9956953ec   Benjamin Tissoires   HID: wacom: power...
1647
  	POWER_SUPPLY_PROP_MODEL_NAME,
71fa641eb   Jason Gerecke   HID: wacom: Add b...
1648
  	POWER_SUPPLY_PROP_PRESENT,
ac8d10101   Benjamin Tissoires   Input: wacom - en...
1649
  	POWER_SUPPLY_PROP_STATUS,
6e2a6e806   Bastien Nocera   Input: wacom - ex...
1650
  	POWER_SUPPLY_PROP_SCOPE,
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1651
1652
1653
1654
1655
1656
1657
  	POWER_SUPPLY_PROP_CAPACITY
  };
  
  static int wacom_battery_get_property(struct power_supply *psy,
  				      enum power_supply_property psp,
  				      union power_supply_propval *val)
  {
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1658
  	struct wacom_battery *battery = power_supply_get_drvdata(psy);
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1659
1660
1661
  	int ret = 0;
  
  	switch (psp) {
9956953ec   Benjamin Tissoires   HID: wacom: power...
1662
1663
1664
  		case POWER_SUPPLY_PROP_MODEL_NAME:
  			val->strval = battery->wacom->wacom_wac.name;
  			break;
71fa641eb   Jason Gerecke   HID: wacom: Add b...
1665
  		case POWER_SUPPLY_PROP_PRESENT:
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1666
  			val->intval = battery->bat_connected;
71fa641eb   Jason Gerecke   HID: wacom: Add b...
1667
  			break;
6e2a6e806   Bastien Nocera   Input: wacom - ex...
1668
1669
1670
  		case POWER_SUPPLY_PROP_SCOPE:
  			val->intval = POWER_SUPPLY_SCOPE_DEVICE;
  			break;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1671
  		case POWER_SUPPLY_PROP_CAPACITY:
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1672
  			val->intval = battery->battery_capacity;
ac8d10101   Benjamin Tissoires   Input: wacom - en...
1673
1674
  			break;
  		case POWER_SUPPLY_PROP_STATUS:
16e459890   Jason Gerecke   HID: wacom: Add a...
1675
1676
1677
  			if (battery->bat_status != WACOM_POWER_SUPPLY_STATUS_AUTO)
  				val->intval = battery->bat_status;
  			else if (battery->bat_charging)
ac8d10101   Benjamin Tissoires   Input: wacom - en...
1678
  				val->intval = POWER_SUPPLY_STATUS_CHARGING;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1679
1680
  			else if (battery->battery_capacity == 100 &&
  				    battery->ps_connected)
ac8d10101   Benjamin Tissoires   Input: wacom - en...
1681
  				val->intval = POWER_SUPPLY_STATUS_FULL;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1682
  			else if (battery->ps_connected)
b0882cb79   Jason Gerecke   HID: wacom: Statu...
1683
  				val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
ac8d10101   Benjamin Tissoires   Input: wacom - en...
1684
1685
  			else
  				val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1686
1687
1688
1689
1690
1691
1692
1693
  			break;
  		default:
  			ret = -EINVAL;
  			break;
  	}
  
  	return ret;
  }
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1694
1695
  static int __wacom_initialize_battery(struct wacom *wacom,
  				      struct wacom_battery *battery)
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1696
  {
d70420b91   Benjamin Tissoires   Input: wacom - us...
1697
  	static atomic_t battery_no = ATOMIC_INIT(0);
b189da901   Benjamin Tissoires   HID: wacom: switc...
1698
  	struct device *dev = &wacom->hdev->dev;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1699
  	struct power_supply_config psy_cfg = { .drv_data = battery, };
136ae5e9b   Benjamin Tissoires   HID: wacom: power...
1700
  	struct power_supply *ps_bat;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1701
  	struct power_supply_desc *bat_desc = &battery->bat_desc;
d70420b91   Benjamin Tissoires   Input: wacom - us...
1702
  	unsigned long n;
b189da901   Benjamin Tissoires   HID: wacom: switc...
1703
1704
1705
1706
  	int error;
  
  	if (!devres_open_group(dev, bat_desc, GFP_KERNEL))
  		return -ENOMEM;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1707

9956953ec   Benjamin Tissoires   HID: wacom: power...
1708
  	battery->wacom = wacom;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1709
1710
1711
1712
1713
1714
1715
  	n = atomic_inc_return(&battery_no) - 1;
  
  	bat_desc->properties = wacom_battery_props;
  	bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props);
  	bat_desc->get_property = wacom_battery_get_property;
  	sprintf(battery->bat_name, "wacom_battery_%ld", n);
  	bat_desc->name = battery->bat_name;
969832962   Benjamin Tissoires   HID: wacom: power...
1716
  	bat_desc->type = POWER_SUPPLY_TYPE_USB;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1717
  	bat_desc->use_for_apm = 0;
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1718
1719
1720
1721
1722
  	ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg);
  	if (IS_ERR(ps_bat)) {
  		error = PTR_ERR(ps_bat);
  		goto err;
  	}
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
1723

59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1724
  	power_supply_powers(ps_bat, &wacom->hdev->dev);
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
1725

59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1726
  	battery->battery = ps_bat;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1727

b189da901   Benjamin Tissoires   HID: wacom: switc...
1728
  	devres_close_group(dev, bat_desc);
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
1729
  	return 0;
b189da901   Benjamin Tissoires   HID: wacom: switc...
1730
1731
1732
1733
  
  err:
  	devres_release_group(dev, bat_desc);
  	return error;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1734
  }
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1735
1736
1737
1738
1739
1740
1741
  static int wacom_initialize_battery(struct wacom *wacom)
  {
  	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY)
  		return __wacom_initialize_battery(wacom, &wacom->battery);
  
  	return 0;
  }
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1742
1743
  static void wacom_destroy_battery(struct wacom *wacom)
  {
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
1744
1745
1746
1747
  	if (wacom->battery.battery) {
  		devres_release_group(&wacom->hdev->dev,
  				     &wacom->battery.bat_desc);
  		wacom->battery.battery = NULL;
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1748
  	}
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1749
  }
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1750
1751
1752
1753
  static ssize_t wacom_show_speed(struct device *dev,
  				struct device_attribute
  				*attr, char *buf)
  {
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1754
  	struct hid_device *hdev = to_hid_device(dev);
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
  	struct wacom *wacom = hid_get_drvdata(hdev);
  
  	return snprintf(buf, PAGE_SIZE, "%i
  ", wacom->wacom_wac.bt_high_speed);
  }
  
  static ssize_t wacom_store_speed(struct device *dev,
  				struct device_attribute *attr,
  				const char *buf, size_t count)
  {
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1765
  	struct hid_device *hdev = to_hid_device(dev);
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	u8 new_speed;
  
  	if (kstrtou8(buf, 0, &new_speed))
  		return -EINVAL;
  
  	if (new_speed != 0 && new_speed != 1)
  		return -EINVAL;
  
  	wacom_bt_query_tablet_data(hdev, new_speed, &wacom->wacom_wac.features);
  
  	return count;
  }
e0984bc37   Ping Cheng   HID: wacom - Add ...
1779
  static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM,
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1780
  		wacom_show_speed, wacom_store_speed);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1781
1782
1783
1784
1785
  
  static ssize_t wacom_show_remote_mode(struct kobject *kobj,
  				      struct kobj_attribute *kattr,
  				      char *buf, int index)
  {
2cf83833f   Geliang Tang   HID: use kobj_to_...
1786
  	struct device *dev = kobj_to_dev(kobj->parent);
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1787
  	struct hid_device *hdev = to_hid_device(dev);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1788
1789
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	u8 mode;
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1790
  	mode = wacom->led.groups[index].select;
bc35f73aa   Christos Gkekas   HID: wacom: Remov...
1791
1792
  	return sprintf(buf, "%d
  ", mode < 3 ? mode : -1);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  }
  
  #define DEVICE_EKR_ATTR_GROUP(SET_ID)					\
  static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj,	\
  			       struct kobj_attribute *kattr, char *buf)	\
  {									\
  	return wacom_show_remote_mode(kobj, kattr, buf, SET_ID);	\
  }									\
  static struct kobj_attribute remote##SET_ID##_mode_attr = {		\
  	.attr = {.name = "remote_mode",					\
  		.mode = DEV_ATTR_RO_PERM},				\
  	.show = wacom_show_remote##SET_ID##_mode,			\
  };									\
  static struct attribute *remote##SET_ID##_serial_attrs[] = {		\
  	&remote##SET_ID##_mode_attr.attr,				\
  	NULL								\
  };									\
  static struct attribute_group remote##SET_ID##_serial_group = {		\
  	.name = NULL,							\
  	.attrs = remote##SET_ID##_serial_attrs,				\
  }
  
  DEVICE_EKR_ATTR_GROUP(0);
  DEVICE_EKR_ATTR_GROUP(1);
  DEVICE_EKR_ATTR_GROUP(2);
  DEVICE_EKR_ATTR_GROUP(3);
  DEVICE_EKR_ATTR_GROUP(4);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
1820
1821
  static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
  					  int index)
72b236d60   Aaron Skomra   HID: wacom: Add s...
1822
1823
  {
  	int error = 0;
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1824
  	struct wacom_remote *remote = wacom->remote;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1825

e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
1826
  	remote->remotes[index].group.name = devm_kasprintf(&wacom->hdev->dev,
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1827
1828
  							  GFP_KERNEL,
  							  "%d", serial);
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
1829
  	if (!remote->remotes[index].group.name)
72b236d60   Aaron Skomra   HID: wacom: Add s...
1830
  		return -ENOMEM;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1831

f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
1832
  	error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
1833
  						&remote->remotes[index].group);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1834
  	if (error) {
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
1835
  		remote->remotes[index].group.name = NULL;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1836
1837
1838
  		hid_err(wacom->hdev,
  			"cannot create sysfs group err: %d
  ", error);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1839
1840
1841
1842
1843
  		return error;
  	}
  
  	return 0;
  }
72b236d60   Aaron Skomra   HID: wacom: Add s...
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
  static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
  {
  	const size_t buf_size = 2;
  	unsigned char *buf;
  	int retval;
  
  	buf = kzalloc(buf_size, GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  
  	buf[0] = WAC_CMD_DELETE_PAIRING;
  	buf[1] = selector;
  
  	retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf,
  				  buf_size, WAC_CMD_RETRIES);
  	kfree(buf);
  
  	return retval;
  }
  
  static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
  					 struct kobj_attribute *attr,
  					 const char *buf, size_t count)
  {
  	unsigned char selector = 0;
2cf83833f   Geliang Tang   HID: use kobj_to_...
1869
  	struct device *dev = kobj_to_dev(kobj->parent);
ee79a8f84   Geliang Tang   HID: use to_hid_d...
1870
  	struct hid_device *hdev = to_hid_device(dev);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	int err;
  
  	if (!strncmp(buf, "*
  ", 2)) {
  		selector = WAC_CMD_UNPAIR_ALL;
  	} else {
  		hid_info(wacom->hdev, "remote: unrecognized unpair code: %s
  ",
  			 buf);
  		return -1;
  	}
  
  	mutex_lock(&wacom->lock);
  
  	err = wacom_cmd_unpair_remote(wacom, selector);
  	mutex_unlock(&wacom->lock);
  
  	return err < 0 ? err : count;
  }
  
  static struct kobj_attribute unpair_remote_attr = {
  	.attr = {.name = "unpair_remote", .mode = 0200},
  	.store = wacom_store_unpair_remote,
  };
  
  static const struct attribute *remote_unpair_attrs[] = {
  	&unpair_remote_attr.attr,
  	NULL
  };
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
  static void wacom_remotes_destroy(void *data)
  {
  	struct wacom *wacom = data;
  	struct wacom_remote *remote = wacom->remote;
  
  	if (!remote)
  		return;
  
  	kobject_put(remote->remote_dir);
  	kfifo_free(&remote->remote_fifo);
  	wacom->remote = NULL;
  }
  
  static int wacom_initialize_remotes(struct wacom *wacom)
72b236d60   Aaron Skomra   HID: wacom: Add s...
1915
1916
  {
  	int error = 0;
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1917
  	struct wacom_remote *remote;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1918
1919
1920
1921
  	int i;
  
  	if (wacom->wacom_wac.features.type != REMOTE)
  		return 0;
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1922
1923
1924
1925
  	remote = devm_kzalloc(&wacom->hdev->dev, sizeof(*wacom->remote),
  			      GFP_KERNEL);
  	if (!remote)
  		return -ENOMEM;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1926

83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
  	wacom->remote = remote;
  
  	spin_lock_init(&remote->remote_lock);
  
  	error = kfifo_alloc(&remote->remote_fifo,
  			5 * sizeof(struct wacom_remote_data),
  			GFP_KERNEL);
  	if (error) {
  		hid_err(wacom->hdev, "failed allocating remote_fifo
  ");
72b236d60   Aaron Skomra   HID: wacom: Add s...
1937
  		return -ENOMEM;
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1938
  	}
72b236d60   Aaron Skomra   HID: wacom: Add s...
1939

e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
1940
1941
1942
1943
1944
  	remote->remotes[0].group = remote0_serial_group;
  	remote->remotes[1].group = remote1_serial_group;
  	remote->remotes[2].group = remote2_serial_group;
  	remote->remotes[3].group = remote3_serial_group;
  	remote->remotes[4].group = remote4_serial_group;
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1945
1946
1947
1948
1949
1950
1951
  
  	remote->remote_dir = kobject_create_and_add("wacom_remote",
  						    &wacom->hdev->dev.kobj);
  	if (!remote->remote_dir)
  		return -ENOMEM;
  
  	error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);
72b236d60   Aaron Skomra   HID: wacom: Add s...
1952
1953
1954
1955
1956
1957
1958
1959
1960
  
  	if (error) {
  		hid_err(wacom->hdev,
  			"cannot create sysfs group err: %d
  ", error);
  		return error;
  	}
  
  	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
a50aac719   Benjamin Tissoires   HID: wacom: leds:...
1961
  		wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
1962
  		remote->remotes[i].serial = 0;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1963
  	}
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
1964
1965
1966
1967
  	error = devm_add_action_or_reset(&wacom->hdev->dev,
  					 wacom_remotes_destroy, wacom);
  	if (error)
  		return error;
72b236d60   Aaron Skomra   HID: wacom: Add s...
1968
1969
  	return 0;
  }
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1970
  static struct input_dev *wacom_allocate_input(struct wacom *wacom)
3aac0ef10   Chris Bagwell   Input: wacom - is...
1971
1972
  {
  	struct input_dev *input_dev;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1973
  	struct hid_device *hdev = wacom->hdev;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1974
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
3aac0ef10   Chris Bagwell   Input: wacom - is...
1975

3dad188e6   Benjamin Tissoires   HID: wacom: switc...
1976
  	input_dev = devm_input_allocate_device(&hdev->dev);
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1977
1978
  	if (!input_dev)
  		return NULL;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1979

2bdd163cf   Jason Gerecke   HID: wacom: Set d...
1980
  	input_dev->name = wacom_wac->features.name;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1981
1982
  	input_dev->phys = hdev->phys;
  	input_dev->dev.parent = &hdev->dev;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1983
1984
  	input_dev->open = wacom_open;
  	input_dev->close = wacom_close;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1985
1986
1987
  	input_dev->uniq = hdev->uniq;
  	input_dev->id.bustype = hdev->bus;
  	input_dev->id.vendor  = hdev->vendor;
12969e3bd   Benjamin Tissoires   HID: wacom: make ...
1988
  	input_dev->id.product = wacom_wac->pid ? wacom_wac->pid : hdev->product;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1989
  	input_dev->id.version = hdev->version;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1990
  	input_set_drvdata(input_dev, wacom);
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1991
1992
  	return input_dev;
  }
d9f2d203a   Jason Gerecke   HID: wacom: Prope...
1993
1994
1995
1996
1997
1998
1999
  static int wacom_allocate_inputs(struct wacom *wacom)
  {
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
  
  	wacom_wac->pen_input = wacom_allocate_input(wacom);
  	wacom_wac->touch_input = wacom_allocate_input(wacom);
  	wacom_wac->pad_input = wacom_allocate_input(wacom);
3dad188e6   Benjamin Tissoires   HID: wacom: switc...
2000
2001
2002
  	if (!wacom_wac->pen_input ||
  	    !wacom_wac->touch_input ||
  	    !wacom_wac->pad_input)
d9f2d203a   Jason Gerecke   HID: wacom: Prope...
2003
  		return -ENOMEM;
d9f2d203a   Jason Gerecke   HID: wacom: Prope...
2004

2bdd163cf   Jason Gerecke   HID: wacom: Set d...
2005
  	wacom_wac->pen_input->name = wacom_wac->pen_name;
d9f2d203a   Jason Gerecke   HID: wacom: Prope...
2006
2007
2008
2009
2010
  	wacom_wac->touch_input->name = wacom_wac->touch_name;
  	wacom_wac->pad_input->name = wacom_wac->pad_name;
  
  	return 0;
  }
2546dacd3   Benjamin Tissoires   HID: wacom: split...
2011
2012
  static int wacom_register_inputs(struct wacom *wacom)
  {
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2013
  	struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
2546dacd3   Benjamin Tissoires   HID: wacom: split...
2014
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
2636a3f2d   Jason Gerecke   HID: wacom: Split...
2015
  	int error = 0;
2546dacd3   Benjamin Tissoires   HID: wacom: split...
2016

2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2017
2018
  	pen_input_dev = wacom_wac->pen_input;
  	touch_input_dev = wacom_wac->touch_input;
2546dacd3   Benjamin Tissoires   HID: wacom: split...
2019
  	pad_input_dev = wacom_wac->pad_input;
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2020
  	if (!pen_input_dev || !touch_input_dev || !pad_input_dev)
2546dacd3   Benjamin Tissoires   HID: wacom: split...
2021
  		return -EINVAL;
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2022
2023
2024
2025
2026
2027
2028
2029
2030
  	error = wacom_setup_pen_input_capabilities(pen_input_dev, wacom_wac);
  	if (error) {
  		/* no pen in use on this interface */
  		input_free_device(pen_input_dev);
  		wacom_wac->pen_input = NULL;
  		pen_input_dev = NULL;
  	} else {
  		error = input_register_device(pen_input_dev);
  		if (error)
3dad188e6   Benjamin Tissoires   HID: wacom: switc...
2031
  			goto fail;
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
  	}
  
  	error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac);
  	if (error) {
  		/* no touch in use on this interface */
  		input_free_device(touch_input_dev);
  		wacom_wac->touch_input = NULL;
  		touch_input_dev = NULL;
  	} else {
  		error = input_register_device(touch_input_dev);
30ebc1aea   Ping Cheng   HID: wacom - Bamb...
2042
  		if (error)
3dad188e6   Benjamin Tissoires   HID: wacom: switc...
2043
  			goto fail;
30ebc1aea   Ping Cheng   HID: wacom - Bamb...
2044
  	}
1963518b9   Ping Cheng   Input: wacom - ad...
2045

d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
2046
2047
2048
2049
2050
2051
2052
2053
2054
  	error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
  	if (error) {
  		/* no pad in use on this interface */
  		input_free_device(pad_input_dev);
  		wacom_wac->pad_input = NULL;
  		pad_input_dev = NULL;
  	} else {
  		error = input_register_device(pad_input_dev);
  		if (error)
3dad188e6   Benjamin Tissoires   HID: wacom: switc...
2055
  			goto fail;
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
2056
  	}
1963518b9   Ping Cheng   Input: wacom - ad...
2057
  	return 0;
3aac0ef10   Chris Bagwell   Input: wacom - is...
2058

3dad188e6   Benjamin Tissoires   HID: wacom: switc...
2059
2060
  fail:
  	wacom_wac->pad_input = NULL;
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2061
  	wacom_wac->touch_input = NULL;
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2062
  	wacom_wac->pen_input = NULL;
3aac0ef10   Chris Bagwell   Input: wacom - is...
2063
2064
  	return error;
  }
0be017120   Jason Gerecke   HID: wacom: Repor...
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
  /*
   * Not all devices report physical dimensions from HID.
   * Compute the default from hardcoded logical dimension
   * and resolution before driver overwrites them.
   */
  static void wacom_set_default_phy(struct wacom_features *features)
  {
  	if (features->x_resolution) {
  		features->x_phy = (features->x_max * 100) /
  					features->x_resolution;
  		features->y_phy = (features->y_max * 100) /
  					features->y_resolution;
  	}
  }
  
  static void wacom_calculate_res(struct wacom_features *features)
  {
  	/* set unit to "100th of a mm" for devices not reported by HID */
  	if (!features->unit) {
  		features->unit = 0x11;
  		features->unitExpo = -3;
  	}
  
  	features->x_resolution = wacom_calc_hid_res(features->x_max,
  						    features->x_phy,
  						    features->unit,
  						    features->unitExpo);
  	features->y_resolution = wacom_calc_hid_res(features->y_max,
  						    features->y_phy,
  						    features->unit,
  						    features->unitExpo);
  }
fce9957d8   Jason Gerecke   HID: wacom: Allow...
2097
2098
  void wacom_battery_work(struct work_struct *work)
  {
d17d1f171   Benjamin Tissoires   HID: wacom: use o...
2099
  	struct wacom *wacom = container_of(work, struct wacom, battery_work);
fce9957d8   Jason Gerecke   HID: wacom: Allow...
2100
2101
  
  	if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
2102
  	     !wacom->battery.battery) {
fce9957d8   Jason Gerecke   HID: wacom: Allow...
2103
2104
2105
  		wacom_initialize_battery(wacom);
  	}
  	else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
59d69bc82   Benjamin Tissoires   HID: wacom: EKR: ...
2106
  		 wacom->battery.battery) {
fce9957d8   Jason Gerecke   HID: wacom: Allow...
2107
2108
2109
  		wacom_destroy_battery(wacom);
  	}
  }
01c846f95   Benjamin Tissoires   Input: wacom - co...
2110
2111
2112
2113
2114
2115
2116
2117
2118
  static size_t wacom_compute_pktlen(struct hid_device *hdev)
  {
  	struct hid_report_enum *report_enum;
  	struct hid_report *report;
  	size_t size = 0;
  
  	report_enum = hdev->report_enum + HID_INPUT_REPORT;
  
  	list_for_each_entry(report, &report_enum->report_list, list) {
dabb05c66   Mathieu Magnaudet   HID: make hid_rep...
2119
  		size_t report_size = hid_report_len(report);
01c846f95   Benjamin Tissoires   Input: wacom - co...
2120
2121
2122
2123
2124
2125
  		if (report_size > size)
  			size = report_size;
  	}
  
  	return size;
  }
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2126
  static void wacom_update_name(struct wacom *wacom, const char *suffix)
c24eab4e0   Ping Cheng   HID: wacom: retri...
2127
2128
2129
  {
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct wacom_features *features = &wacom_wac->features;
073b50bcc   Jason Gerecke   HID: wacom: Fix s...
2130
  	char name[WACOM_NAME_MAX - 20]; /* Leave some room for suffixes */
c24eab4e0   Ping Cheng   HID: wacom: retri...
2131
2132
2133
  
  	/* Generic devices name unspecified */
  	if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
09dc28aca   Jason Gerecke   HID: wacom: Impro...
2134
  		char *product_name = wacom->hdev->name;
f2209d4ae   Jason Gerecke   HID: wacom: gener...
2135

09dc28aca   Jason Gerecke   HID: wacom: Impro...
2136
2137
2138
2139
2140
  		if (hid_is_using_ll_driver(wacom->hdev, &usb_hid_driver)) {
  			struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
  			struct usb_device *dev = interface_to_usbdev(intf);
  			product_name = dev->product;
  		}
f2209d4ae   Jason Gerecke   HID: wacom: gener...
2141

09dc28aca   Jason Gerecke   HID: wacom: Impro...
2142
2143
2144
2145
2146
2147
2148
  		if (wacom->hdev->bus == BUS_I2C) {
  			snprintf(name, sizeof(name), "%s %X",
  				 features->name, wacom->hdev->product);
  		} else if (strstr(product_name, "Wacom") ||
  			   strstr(product_name, "wacom") ||
  			   strstr(product_name, "WACOM")) {
  			strlcpy(name, product_name, sizeof(name));
c24eab4e0   Ping Cheng   HID: wacom: retri...
2149
  		} else {
09dc28aca   Jason Gerecke   HID: wacom: Impro...
2150
  			snprintf(name, sizeof(name), "Wacom %s", product_name);
c24eab4e0   Ping Cheng   HID: wacom: retri...
2151
  		}
09dc28aca   Jason Gerecke   HID: wacom: Impro...
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
  
  		/* strip out excess whitespaces */
  		while (1) {
  			char *gap = strstr(name, "  ");
  			if (gap == NULL)
  				break;
  			/* shift everything including the terminator */
  			memmove(gap, gap+1, strlen(gap));
  		}
  
  		/* get rid of trailing whitespace */
  		if (name[strlen(name)-1] == ' ')
  			name[strlen(name)-1] = '\0';
c24eab4e0   Ping Cheng   HID: wacom: retri...
2165
  	} else {
44b5250b9   Jason Gerecke   HID: wacom: Simpl...
2166
  		strlcpy(name, features->name, sizeof(name));
c24eab4e0   Ping Cheng   HID: wacom: retri...
2167
  	}
9956953ec   Benjamin Tissoires   HID: wacom: power...
2168
2169
  	snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s%s",
  		 name, suffix);
c24eab4e0   Ping Cheng   HID: wacom: retri...
2170
  	/* Append the device type to the name */
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2171
  	snprintf(wacom_wac->pen_name, sizeof(wacom_wac->pen_name),
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2172
  		"%s%s Pen", name, suffix);
2a6cdbdd4   Jason Gerecke   HID: wacom: Intro...
2173
  	snprintf(wacom_wac->touch_name, sizeof(wacom_wac->touch_name),
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2174
  		"%s%s Finger", name, suffix);
c24eab4e0   Ping Cheng   HID: wacom: retri...
2175
  	snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2176
  		"%s%s Pad", name, suffix);
c24eab4e0   Ping Cheng   HID: wacom: retri...
2177
  }
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
  static void wacom_release_resources(struct wacom *wacom)
  {
  	struct hid_device *hdev = wacom->hdev;
  
  	if (!wacom->resources)
  		return;
  
  	devres_release_group(&hdev->dev, wacom);
  
  	wacom->resources = false;
  
  	wacom->wacom_wac.pen_input = NULL;
  	wacom->wacom_wac.touch_input = NULL;
  	wacom->wacom_wac.pad_input = NULL;
  }
d2ec58aee   Aaron Armstrong Skomra   HID: wacom: gener...
2193
2194
2195
2196
2197
2198
  static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
  {
  	if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
  		wacom_wac->shared->type = wacom_wac->features.type;
  		wacom_wac->shared->touch_input = wacom_wac->touch_input;
  	}
d793ff818   Ping Cheng   HID: wacom: gener...
2199
  	if (wacom_wac->has_mute_touch_switch) {
d2ec58aee   Aaron Armstrong Skomra   HID: wacom: gener...
2200
  		wacom_wac->shared->has_mute_touch_switch = true;
d793ff818   Ping Cheng   HID: wacom: gener...
2201
2202
  		wacom_wac->shared->is_touch_on = true;
  	}
d2ec58aee   Aaron Armstrong Skomra   HID: wacom: gener...
2203
2204
2205
2206
2207
2208
2209
2210
  
  	if (wacom_wac->shared->has_mute_touch_switch &&
  	    wacom_wac->shared->touch_input) {
  		set_bit(EV_SW, wacom_wac->shared->touch_input->evbit);
  		input_set_capability(wacom_wac->shared->touch_input, EV_SW,
  				     SW_MUTE_DEVICE);
  	}
  }
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2211
  static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
3bea733ab   Ping Cheng   USB: wacom tablet...
2212
  {
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2213
2214
2215
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct wacom_features *features = &wacom_wac->features;
  	struct hid_device *hdev = wacom->hdev;
e33da8a54   Jason Childs   Input: wacom - us...
2216
  	int error;
7704ac937   Benjamin Tissoires   HID: wacom: imple...
2217
  	unsigned int connect_mask = HID_CONNECT_HIDRAW;
3bea733ab   Ping Cheng   USB: wacom tablet...
2218

01c846f95   Benjamin Tissoires   Input: wacom - co...
2219
  	features->pktlen = wacom_compute_pktlen(hdev);
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2220
2221
  	if (features->pktlen > WACOM_PKGLEN_MAX)
  		return -EINVAL;
3bea733ab   Ping Cheng   USB: wacom tablet...
2222

84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2223
2224
2225
2226
  	if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL))
  		return -ENOMEM;
  
  	wacom->resources = true;
3f14a63a5   Jason Gerecke   HID: wacom: Remov...
2227
2228
  	error = wacom_allocate_inputs(wacom);
  	if (error)
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2229
  		goto fail;
494078b0b   Benjamin Tissoires   HID: wacom: move ...
2230

8c97a7654   Benjamin Tissoires   HID: wacom: add f...
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
  	/*
  	 * Bamboo Pad has a generic hid handling for the Pen, and we switch it
  	 * into debug mode for the touch part.
  	 * We ignore the other interfaces.
  	 */
  	if (features->type == BAMBOO_PAD) {
  		if (features->pktlen == WACOM_PKGLEN_PENABLED) {
  			features->type = HID_GENERIC;
  		} else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
  			   (features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
  			error = -ENODEV;
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2242
  			goto fail;
8c97a7654   Benjamin Tissoires   HID: wacom: add f...
2243
2244
  		}
  	}
401d7d108   Ping Cheng   Input: wacom - in...
2245
2246
  	/* set the default size in case we do not get them from hid */
  	wacom_set_default_phy(features);
f393ee2b8   Ping Cheng   Input: wacom - re...
2247
  	/* Retrieve the physical and logical size for touch devices */
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
2248
  	wacom_retrieve_hid_descriptor(hdev, features);
42f4f2727   Ping Cheng   HID: wacom: move ...
2249
  	wacom_setup_device_quirks(wacom);
042628abd   Jason Gerecke   HID: wacom: Disco...
2250

aa86b18cc   Jason Gerecke   HID: wacom: Treat...
2251
2252
  	if (features->device_type == WACOM_DEVICETYPE_NONE &&
  	    features->type != WIRELESS) {
8e116d316   Jason Gerecke   HID: wacom: Fail ...
2253
  		error = features->type == HID_GENERIC ? -ENODEV : 0;
042628abd   Jason Gerecke   HID: wacom: Disco...
2254
  		dev_warn(&hdev->dev, "Unknown device_type for '%s'. %s.",
8e116d316   Jason Gerecke   HID: wacom: Fail ...
2255
2256
2257
2258
  			 hdev->name,
  			 error ? "Ignoring" : "Assuming pen");
  
  		if (error)
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2259
  			goto fail;
042628abd   Jason Gerecke   HID: wacom: Disco...
2260

aa86b18cc   Jason Gerecke   HID: wacom: Treat...
2261
  		features->device_type |= WACOM_DEVICETYPE_PEN;
042628abd   Jason Gerecke   HID: wacom: Disco...
2262
  	}
401d7d108   Ping Cheng   Input: wacom - in...
2263
  	wacom_calculate_res(features);
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2264
  	wacom_update_name(wacom, wireless ? " (WL)" : "");
4492effff   Ping Cheng   Input: wacom - sh...
2265

8b4073596   Aaron Armstrong Skomra   HID: wacom: Don't...
2266
2267
2268
2269
2270
2271
2272
  	/* pen only Bamboo neither support touch nor pad */
  	if ((features->type == BAMBOO_PEN) &&
  	    ((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
  	    (features->device_type & WACOM_DEVICETYPE_PAD))) {
  		error = -ENODEV;
  		goto fail;
  	}
a9ce7856c   Jason Gerecke   HID: wacom: Fix s...
2273
2274
2275
  	error = wacom_add_shared_data(hdev);
  	if (error)
  		goto fail;
49b764aeb   Ping Cheng   Input: wacom - ad...
2276

ccad85cc1   Jason Gerecke   HID: wacom: Repla...
2277
  	if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
2278
2279
2280
  	     (features->quirks & WACOM_QUIRK_BATTERY)) {
  		error = wacom_initialize_battery(wacom);
  		if (error)
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2281
  			goto fail;
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
2282
  	}
3f14a63a5   Jason Gerecke   HID: wacom: Remov...
2283
2284
  	error = wacom_register_inputs(wacom);
  	if (error)
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2285
  		goto fail;
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
2286

b62f6465c   Benjamin Tissoires   HID: wacom: remov...
2287
  	if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) {
85d2c77b7   Benjamin Tissoires   HID: wacom: untie...
2288
2289
  		error = wacom_initialize_leds(wacom);
  		if (error)
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2290
  			goto fail;
85d2c77b7   Benjamin Tissoires   HID: wacom: untie...
2291

83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2292
  		error = wacom_initialize_remotes(wacom);
b62f6465c   Benjamin Tissoires   HID: wacom: remov...
2293
  		if (error)
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2294
  			goto fail;
b62f6465c   Benjamin Tissoires   HID: wacom: remov...
2295
  	}
7704ac937   Benjamin Tissoires   HID: wacom: imple...
2296
2297
  	if (features->type == HID_GENERIC)
  		connect_mask |= HID_CONNECT_DRIVER;
29b473913   Benjamin Tissoires   Input: wacom - sw...
2298
  	/* Regular HID work starts now */
7704ac937   Benjamin Tissoires   HID: wacom: imple...
2299
  	error = hid_hw_start(hdev, connect_mask);
29b473913   Benjamin Tissoires   Input: wacom - sw...
2300
2301
2302
  	if (error) {
  		hid_err(hdev, "hw start failed
  ");
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2303
  		goto fail;
d3825d51c   Chris Bagwell   Input: wacom - wi...
2304
  	}
961794a00   Ping Cheng   Input: wacom - ad...
2305

fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2306
2307
  	if (!wireless) {
  		/* Note that if query fails it is not a hard failure */
a544c619a   Benjamin Tissoires   HID: wacom: do no...
2308
  		wacom_query_tablet_data(wacom);
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2309
  	}
86e88f0e7   Jason Gerecke   HID: wacom: Call ...
2310
2311
2312
2313
  
  	/* touch only Bamboo doesn't support pen */
  	if ((features->type == BAMBOO_TOUCH) &&
  	    (features->device_type & WACOM_DEVICETYPE_PEN)) {
4d20c332d   Aaron Armstrong Skomra   HID: wacom: call ...
2314
2315
  		cancel_delayed_work_sync(&wacom->init_work);
  		_wacom_query_tablet_data(wacom);
86e88f0e7   Jason Gerecke   HID: wacom: Call ...
2316
  		error = -ENODEV;
b62f6465c   Benjamin Tissoires   HID: wacom: remov...
2317
  		goto fail_quirks;
86e88f0e7   Jason Gerecke   HID: wacom: Call ...
2318
  	}
ccad85cc1   Jason Gerecke   HID: wacom: Repla...
2319
  	if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
29b473913   Benjamin Tissoires   Input: wacom - sw...
2320
  		error = hid_hw_open(hdev);
d2ec58aee   Aaron Armstrong Skomra   HID: wacom: gener...
2321
  	wacom_set_shared_values(wacom_wac);
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2322
  	devres_close_group(&hdev->dev, wacom);
3bea733ab   Ping Cheng   USB: wacom tablet...
2323
  	return 0;
b62f6465c   Benjamin Tissoires   HID: wacom: remov...
2324
  fail_quirks:
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2325
  	hid_hw_stop(hdev);
3888b0d53   Benjamin Tissoires   HID: wacom: rewor...
2326
  fail:
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2327
  	wacom_release_resources(wacom);
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2328
2329
  	return error;
  }
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2330
2331
  static void wacom_wireless_work(struct work_struct *work)
  {
d17d1f171   Benjamin Tissoires   HID: wacom: use o...
2332
  	struct wacom *wacom = container_of(work, struct wacom, wireless_work);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
  	struct usb_device *usbdev = wacom->usbdev;
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct hid_device *hdev1, *hdev2;
  	struct wacom *wacom1, *wacom2;
  	struct wacom_wac *wacom_wac1, *wacom_wac2;
  	int error;
  
  	/*
  	 * Regardless if this is a disconnect or a new tablet,
  	 * remove any existing input and battery devices.
  	 */
  
  	wacom_destroy_battery(wacom);
  
  	/* Stylus interface */
  	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
  	wacom1 = hid_get_drvdata(hdev1);
  	wacom_wac1 = &(wacom1->wacom_wac);
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2351
  	wacom_release_resources(wacom1);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2352
2353
2354
2355
2356
  
  	/* Touch interface */
  	hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
  	wacom2 = hid_get_drvdata(hdev2);
  	wacom_wac2 = &(wacom2->wacom_wac);
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2357
  	wacom_release_resources(wacom2);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2358
2359
2360
2361
  
  	if (wacom_wac->pid == 0) {
  		hid_info(wacom->hdev, "wireless tablet disconnected
  ");
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
  	} else {
  		const struct hid_device_id *id = wacom_ids;
  
  		hid_info(wacom->hdev, "wireless tablet connected with PID %x
  ",
  			 wacom_wac->pid);
  
  		while (id->bus) {
  			if (id->vendor == USB_VENDOR_ID_WACOM &&
  			    id->product == wacom_wac->pid)
  				break;
  			id++;
  		}
  
  		if (!id->bus) {
  			hid_info(wacom->hdev, "ignoring unknown PID.
  ");
  			return;
  		}
  
  		/* Stylus interface */
  		wacom_wac1->features =
  			*((struct wacom_features *)id->driver_data);
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2385

a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2386
  		wacom_wac1->pid = wacom_wac->pid;
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2387
2388
  		hid_hw_stop(hdev1);
  		error = wacom_parse_and_register(wacom1, true);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2389
2390
2391
2392
2393
2394
2395
2396
2397
  		if (error)
  			goto fail;
  
  		/* Touch interface */
  		if (wacom_wac1->features.touch_max ||
  		    (wacom_wac1->features.type >= INTUOSHT &&
  		    wacom_wac1->features.type <= BAMBOO_PT)) {
  			wacom_wac2->features =
  				*((struct wacom_features *)id->driver_data);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2398
  			wacom_wac2->pid = wacom_wac->pid;
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2399
2400
  			hid_hw_stop(hdev2);
  			error = wacom_parse_and_register(wacom2, true);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2401
2402
  			if (error)
  				goto fail;
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2403
  		}
9956953ec   Benjamin Tissoires   HID: wacom: power...
2404
2405
  		strlcpy(wacom_wac->name, wacom_wac1->name,
  			sizeof(wacom_wac->name));
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2406
2407
2408
2409
2410
2411
2412
2413
  		error = wacom_initialize_battery(wacom);
  		if (error)
  			goto fail;
  	}
  
  	return;
  
  fail:
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2414
  	wacom_release_resources(wacom1);
84dfbd7f2   Benjamin Tissoires   HID: wacom: put t...
2415
  	wacom_release_resources(wacom2);
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2416
2417
  	return;
  }
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2418
2419
2420
  static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
  {
  	struct wacom_remote *remote = wacom->remote;
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2421
  	u32 serial = remote->remotes[index].serial;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2422
  	int i;
7c35dc3cd   Benjamin Tissoires   HID: wacom: EKR: ...
2423
  	unsigned long flags;
791ae2737   Aaron Armstrong Skomra   HID: wacom: EKR: ...
2424
2425
  	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
  		if (remote->remotes[i].serial == serial) {
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2426

791ae2737   Aaron Armstrong Skomra   HID: wacom: EKR: ...
2427
2428
2429
  			spin_lock_irqsave(&remote->remote_lock, flags);
  			remote->remotes[i].registered = false;
  			spin_unlock_irqrestore(&remote->remote_lock, flags);
9f1015d45   Benjamin Tissoires   HID: wacom: EKR: ...
2430

791ae2737   Aaron Armstrong Skomra   HID: wacom: EKR: ...
2431
2432
2433
2434
2435
2436
2437
  			if (remote->remotes[i].battery.battery)
  				devres_release_group(&wacom->hdev->dev,
  						     &remote->remotes[i].battery.bat_desc);
  
  			if (remote->remotes[i].group.name)
  				devres_release_group(&wacom->hdev->dev,
  						     &remote->remotes[i]);
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2438

e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2439
2440
  			remote->remotes[i].serial = 0;
  			remote->remotes[i].group.name = NULL;
9f1015d45   Benjamin Tissoires   HID: wacom: EKR: ...
2441
  			remote->remotes[i].battery.battery = NULL;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2442
2443
2444
2445
2446
2447
2448
2449
2450
  			wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
  		}
  	}
  }
  
  static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
  				   unsigned int index)
  {
  	struct wacom_remote *remote = wacom->remote;
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
2451
  	struct device *dev = &wacom->hdev->dev;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2452
2453
2454
2455
2456
2457
  	int error, k;
  
  	/* A remote can pair more than once with an EKR,
  	 * check to make sure this serial isn't already paired.
  	 */
  	for (k = 0; k < WACOM_MAX_REMOTES; k++) {
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2458
  		if (remote->remotes[k].serial == serial)
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2459
2460
2461
2462
  			break;
  	}
  
  	if (k < WACOM_MAX_REMOTES) {
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2463
  		remote->remotes[index].serial = serial;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2464
2465
  		return 0;
  	}
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2466
  	if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
2467
  		return -ENOMEM;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2468
2469
  	error = wacom_remote_create_attr_group(wacom, serial, index);
  	if (error)
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
2470
  		goto fail;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2471

7c35dc3cd   Benjamin Tissoires   HID: wacom: EKR: ...
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
  	remote->remotes[index].input = wacom_allocate_input(wacom);
  	if (!remote->remotes[index].input) {
  		error = -ENOMEM;
  		goto fail;
  	}
  	remote->remotes[index].input->uniq = remote->remotes[index].group.name;
  	remote->remotes[index].input->name = wacom->wacom_wac.pad_name;
  
  	if (!remote->remotes[index].input->name) {
  		error = -EINVAL;
  		goto fail;
  	}
  
  	error = wacom_setup_pad_input_capabilities(remote->remotes[index].input,
  						   &wacom->wacom_wac);
  	if (error)
  		goto fail;
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2489
  	remote->remotes[index].serial = serial;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2490

7c35dc3cd   Benjamin Tissoires   HID: wacom: EKR: ...
2491
2492
2493
  	error = input_register_device(remote->remotes[index].input);
  	if (error)
  		goto fail;
97f5541fc   Benjamin Tissoires   HID: wacom: leds:...
2494
2495
2496
2497
2498
  	error = wacom_led_groups_alloc_and_register_one(
  					&remote->remotes[index].input->dev,
  					wacom, index, 3, true);
  	if (error)
  		goto fail;
7c35dc3cd   Benjamin Tissoires   HID: wacom: EKR: ...
2499
  	remote->remotes[index].registered = true;
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2500
  	devres_close_group(dev, &remote->remotes[index]);
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2501
  	return 0;
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
2502
2503
  
  fail:
e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2504
2505
  	devres_release_group(dev, &remote->remotes[index]);
  	remote->remotes[index].serial = 0;
f9036bd43   Benjamin Tissoires   HID: wacom: EKR: ...
2506
  	return error;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2507
  }
9f1015d45   Benjamin Tissoires   HID: wacom: EKR: ...
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
  static int wacom_remote_attach_battery(struct wacom *wacom, int index)
  {
  	struct wacom_remote *remote = wacom->remote;
  	int error;
  
  	if (!remote->remotes[index].registered)
  		return 0;
  
  	if (remote->remotes[index].battery.battery)
  		return 0;
  
  	if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN)
  		return 0;
  
  	error = __wacom_initialize_battery(wacom,
  					&wacom->remote->remotes[index].battery);
  	if (error)
  		return error;
  
  	return 0;
  }
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2529
2530
2531
  static void wacom_remote_work(struct work_struct *work)
  {
  	struct wacom *wacom = container_of(work, struct wacom, remote_work);
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2532
  	struct wacom_remote *remote = wacom->remote;
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2533
2534
2535
2536
  	struct wacom_remote_data data;
  	unsigned long flags;
  	unsigned int count;
  	u32 serial;
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2537
  	int i;
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2538

83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2539
  	spin_lock_irqsave(&remote->remote_lock, flags);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2540

83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2541
  	count = kfifo_out(&remote->remote_fifo, &data, sizeof(data));
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2542
2543
2544
2545
2546
  
  	if (count != sizeof(data)) {
  		hid_err(wacom->hdev,
  			"workitem triggered without status available
  ");
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2547
  		spin_unlock_irqrestore(&remote->remote_lock, flags);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2548
2549
  		return;
  	}
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2550
  	if (!kfifo_is_empty(&remote->remote_fifo))
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2551
  		wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);
83e6b40e2   Benjamin Tissoires   HID: wacom: EKR: ...
2552
  	spin_unlock_irqrestore(&remote->remote_lock, flags);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2553
2554
2555
2556
  
  	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
  		serial = data.remote[i].serial;
  		if (data.remote[i].connected) {
9f1015d45   Benjamin Tissoires   HID: wacom: EKR: ...
2557
2558
  			if (remote->remotes[i].serial == serial) {
  				wacom_remote_attach_battery(wacom, i);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2559
  				continue;
9f1015d45   Benjamin Tissoires   HID: wacom: EKR: ...
2560
  			}
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2561

e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2562
  			if (remote->remotes[i].serial)
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2563
  				wacom_remote_destroy_one(wacom, i);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2564

04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2565
  			wacom_remote_create_one(wacom, serial, i);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2566

e7749f6e5   Benjamin Tissoires   HID: wacom: EKR: ...
2567
  		} else if (remote->remotes[i].serial) {
04bfa27b4   Benjamin Tissoires   HID: wacom: EKR: ...
2568
  			wacom_remote_destroy_one(wacom, i);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2569
2570
2571
  		}
  	}
  }
4082da80f   Benjamin Tissoires   HID: wacom: gener...
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
  static void wacom_mode_change_work(struct work_struct *work)
  {
  	struct wacom *wacom = container_of(work, struct wacom, mode_change_work);
  	struct wacom_shared *shared = wacom->wacom_wac.shared;
  	struct wacom *wacom1 = NULL;
  	struct wacom *wacom2 = NULL;
  	bool is_direct = wacom->wacom_wac.is_direct_mode;
  	int error = 0;
  
  	if (shared->pen) {
  		wacom1 = hid_get_drvdata(shared->pen);
  		wacom_release_resources(wacom1);
  		hid_hw_stop(wacom1->hdev);
  		wacom1->wacom_wac.has_mode_change = true;
  		wacom1->wacom_wac.is_direct_mode = is_direct;
  	}
  
  	if (shared->touch) {
  		wacom2 = hid_get_drvdata(shared->touch);
  		wacom_release_resources(wacom2);
  		hid_hw_stop(wacom2->hdev);
  		wacom2->wacom_wac.has_mode_change = true;
  		wacom2->wacom_wac.is_direct_mode = is_direct;
  	}
  
  	if (wacom1) {
  		error = wacom_parse_and_register(wacom1, false);
  		if (error)
  			return;
  	}
  
  	if (wacom2) {
  		error = wacom_parse_and_register(wacom2, false);
  		if (error)
  			return;
  	}
a2f091af7   Benjamin Tissoires   HID: wacom: move ...
2608
2609
  	return;
  }
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
  static int wacom_probe(struct hid_device *hdev,
  		const struct hid_device_id *id)
  {
  	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  	struct usb_device *dev = interface_to_usbdev(intf);
  	struct wacom *wacom;
  	struct wacom_wac *wacom_wac;
  	struct wacom_features *features;
  	int error;
  
  	if (!id->driver_data)
  		return -EINVAL;
  
  	hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
  
  	/* hid-core sets this quirk for the boot interface */
  	hdev->quirks &= ~HID_QUIRK_NOGET;
19b643300   Benjamin Tissoires   HID: wacom: use d...
2627
  	wacom = devm_kzalloc(&hdev->dev, sizeof(struct wacom), GFP_KERNEL);
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2628
2629
2630
2631
2632
2633
2634
2635
2636
  	if (!wacom)
  		return -ENOMEM;
  
  	hid_set_drvdata(hdev, wacom);
  	wacom->hdev = hdev;
  
  	wacom_wac = &wacom->wacom_wac;
  	wacom_wac->features = *((struct wacom_features *)id->driver_data);
  	features = &wacom_wac->features;
362c571b9   Benjamin Tissoires   HID: wacom: do no...
2637
2638
  	if (features->check_for_hid_type && features->hid_type != hdev->type)
  		return -ENODEV;
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2639

797c128d3   Ping Cheng   HID: wacom: Fix m...
2640
  	error = wacom_devm_kfifo_alloc(wacom);
834172064   Jason Gerecke   HID: wacom: Queue...
2641
  	if (error)
362c571b9   Benjamin Tissoires   HID: wacom: do no...
2642
  		return error;
834172064   Jason Gerecke   HID: wacom: Queue...
2643

c6fa1aeba   Jason Gerecke   HID: wacom: Initi...
2644
  	wacom_wac->hid_data.inputmode = -1;
326ea2a90   Jason Gerecke   HID: wacom: Suppo...
2645
  	wacom_wac->mode_report = -1;
c6fa1aeba   Jason Gerecke   HID: wacom: Initi...
2646

c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2647
2648
2649
  	wacom->usbdev = dev;
  	wacom->intf = intf;
  	mutex_init(&wacom->lock);
a544c619a   Benjamin Tissoires   HID: wacom: do no...
2650
  	INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
d17d1f171   Benjamin Tissoires   HID: wacom: use o...
2651
2652
  	INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
  	INIT_WORK(&wacom->battery_work, wacom_battery_work);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2653
  	INIT_WORK(&wacom->remote_work, wacom_remote_work);
4082da80f   Benjamin Tissoires   HID: wacom: gener...
2654
  	INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2655
2656
2657
2658
2659
2660
  
  	/* ask for the report descriptor to be loaded by HID */
  	error = hid_parse(hdev);
  	if (error) {
  		hid_err(hdev, "parse failed
  ");
362c571b9   Benjamin Tissoires   HID: wacom: do no...
2661
  		return error;
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2662
  	}
fd5f92b6d   Benjamin Tissoires   HID: wacom: reuse...
2663
  	error = wacom_parse_and_register(wacom, false);
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2664
  	if (error)
362c571b9   Benjamin Tissoires   HID: wacom: do no...
2665
  		return error;
c58ac3a88   Benjamin Tissoires   HID: wacom: break...
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
  
  	if (hdev->bus == BUS_BLUETOOTH) {
  		error = device_create_file(&hdev->dev, &dev_attr_speed);
  		if (error)
  			hid_warn(hdev,
  				 "can't create sysfs speed attribute err: %d
  ",
  				 error);
  	}
  
  	return 0;
3bea733ab   Ping Cheng   USB: wacom tablet...
2677
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
2678
  static void wacom_remove(struct hid_device *hdev)
3bea733ab   Ping Cheng   USB: wacom tablet...
2679
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
2680
  	struct wacom *wacom = hid_get_drvdata(hdev);
f62051617   Benjamin Tissoires   HID: wacom: close...
2681
2682
2683
2684
2685
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
  	struct wacom_features *features = &wacom_wac->features;
  
  	if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
  		hid_hw_close(hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
2686

29b473913   Benjamin Tissoires   Input: wacom - sw...
2687
  	hid_hw_stop(hdev);
e72240944   Oliver Neukum   Input: wacom - im...
2688

a544c619a   Benjamin Tissoires   HID: wacom: do no...
2689
  	cancel_delayed_work_sync(&wacom->init_work);
d17d1f171   Benjamin Tissoires   HID: wacom: use o...
2690
2691
  	cancel_work_sync(&wacom->wireless_work);
  	cancel_work_sync(&wacom->battery_work);
e6f2813a6   Benjamin Tissoires   HID: wacom: EKR: ...
2692
  	cancel_work_sync(&wacom->remote_work);
4082da80f   Benjamin Tissoires   HID: wacom: gener...
2693
  	cancel_work_sync(&wacom->mode_change_work);
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
2694
2695
  	if (hdev->bus == BUS_BLUETOOTH)
  		device_remove_file(&hdev->dev, &dev_attr_speed);
e72240944   Oliver Neukum   Input: wacom - im...
2696

c0265a948   Benjamin Tissoires   HID: wacom: remov...
2697
2698
  	/* make sure we don't trigger the LEDs */
  	wacom_led_groups_release(wacom);
b6b1f19b0   Aaron Armstrong Skomra   HID: wacom: don't...
2699
2700
2701
  
  	if (wacom->wacom_wac.features.type != REMOTE)
  		wacom_release_resources(wacom);
e72240944   Oliver Neukum   Input: wacom - im...
2702
  }
41a745814   Geert Uytterhoeven   Input: wacom - fi...
2703
  #ifdef CONFIG_PM
29b473913   Benjamin Tissoires   Input: wacom - sw...
2704
  static int wacom_resume(struct hid_device *hdev)
e72240944   Oliver Neukum   Input: wacom - im...
2705
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
2706
  	struct wacom *wacom = hid_get_drvdata(hdev);
e72240944   Oliver Neukum   Input: wacom - im...
2707
2708
  
  	mutex_lock(&wacom->lock);
38101475f   Ping Cheng   Input: wacom - sw...
2709
2710
  
  	/* switch to wacom mode first */
a544c619a   Benjamin Tissoires   HID: wacom: do no...
2711
  	_wacom_query_tablet_data(wacom);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
2712
  	wacom_led_control(wacom);
38101475f   Ping Cheng   Input: wacom - sw...
2713

e72240944   Oliver Neukum   Input: wacom - im...
2714
  	mutex_unlock(&wacom->lock);
29b473913   Benjamin Tissoires   Input: wacom - sw...
2715
  	return 0;
e72240944   Oliver Neukum   Input: wacom - im...
2716
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
2717
  static int wacom_reset_resume(struct hid_device *hdev)
e72240944   Oliver Neukum   Input: wacom - im...
2718
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
2719
  	return wacom_resume(hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
2720
  }
41a745814   Geert Uytterhoeven   Input: wacom - fi...
2721
  #endif /* CONFIG_PM */
3bea733ab   Ping Cheng   USB: wacom tablet...
2722

29b473913   Benjamin Tissoires   Input: wacom - sw...
2723
  static struct hid_driver wacom_driver = {
3bea733ab   Ping Cheng   USB: wacom tablet...
2724
  	.name =		"wacom",
b036f6fb3   Bastian Blank   Input: wacom - ge...
2725
  	.id_table =	wacom_ids,
3bea733ab   Ping Cheng   USB: wacom tablet...
2726
  	.probe =	wacom_probe,
29b473913   Benjamin Tissoires   Input: wacom - sw...
2727
  	.remove =	wacom_remove,
7704ac937   Benjamin Tissoires   HID: wacom: imple...
2728
  	.report =	wacom_wac_report,
29b473913   Benjamin Tissoires   Input: wacom - sw...
2729
  #ifdef CONFIG_PM
e72240944   Oliver Neukum   Input: wacom - im...
2730
2731
  	.resume =	wacom_resume,
  	.reset_resume =	wacom_reset_resume,
29b473913   Benjamin Tissoires   Input: wacom - sw...
2732
2733
  #endif
  	.raw_event =	wacom_raw_event,
3bea733ab   Ping Cheng   USB: wacom tablet...
2734
  };
29b473913   Benjamin Tissoires   Input: wacom - sw...
2735
  module_hid_driver(wacom_driver);
f2e0a7d4a   Benjamin Tissoires   Input: wacom - on...
2736
2737
2738
2739
  
  MODULE_VERSION(DRIVER_VERSION);
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
7021b6007   Grant Grundler   HID: remove use o...
2740
  MODULE_LICENSE("GPL");