Blame view

drivers/hid/wacom_sys.c 40.6 KB
3bea733ab   Ping Cheng   USB: wacom tablet...
1
  /*
4104d13fe   Dmitry Torokhov   Input: move USB t...
2
   * drivers/input/tablet/wacom_sys.c
3bea733ab   Ping Cheng   USB: wacom tablet...
3
   *
232f5693e   Ping Cheng   Input: wacom - en...
4
   *  USB Wacom tablet support - system specific code
3bea733ab   Ping Cheng   USB: wacom tablet...
5
6
7
8
9
10
11
12
   */
  
  /*
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   */
3bea733ab   Ping Cheng   USB: wacom tablet...
13
  #include "wacom_wac.h"
51269fe86   Dmitry Torokhov   Input: wacom - do...
14
  #include "wacom.h"
b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
15
  #include <linux/input/mt.h>
3bea733ab   Ping Cheng   USB: wacom tablet...
16

a417ea443   Ping Cheng   Input: wacom - ad...
17
  #define WAC_MSG_RETRIES		5
3bea733ab   Ping Cheng   USB: wacom tablet...
18

912ca216b   Ping Cheng   HID: wacom - enab...
19
  #define WAC_CMD_WL_LED_CONTROL	0x03
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
20
21
22
  #define WAC_CMD_LED_CONTROL	0x20
  #define WAC_CMD_ICON_START	0x21
  #define WAC_CMD_ICON_XFER	0x23
849e2f067   Benjamin Tissoires   Input: wacom - ch...
23
  #define WAC_CMD_ICON_BT_XFER	0x26
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
24
  #define WAC_CMD_RETRIES		10
e0984bc37   Ping Cheng   HID: wacom - Add ...
25
26
  #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
  #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
c64d88347   Ping Cheng   HID: wacom - remo...
27
28
  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...
29
  {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
30
31
32
  	int retval;
  
  	do {
c64d88347   Ping Cheng   HID: wacom - remo...
33
  		retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
27b20a9de   Benjamin Tissoires   Input: wacom - us...
34
  				HID_REQ_GET_REPORT);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
35
36
37
  	} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
  
  	return retval;
3bea733ab   Ping Cheng   USB: wacom tablet...
38
  }
296b73787   Przemo Firszt   Input: wacom - re...
39
40
  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...
41
  {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
42
43
44
  	int retval;
  
  	do {
296b73787   Przemo Firszt   Input: wacom - re...
45
  		retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
27b20a9de   Benjamin Tissoires   Input: wacom - us...
46
  				HID_REQ_SET_REPORT);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
47
48
49
  	} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
  
  	return retval;
3bea733ab   Ping Cheng   USB: wacom tablet...
50
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
51
52
  static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
  		u8 *raw_data, int size)
3bea733ab   Ping Cheng   USB: wacom tablet...
53
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
54
  	struct wacom *wacom = hid_get_drvdata(hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
55

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

29b473913   Benjamin Tissoires   Input: wacom - sw...
59
  	memcpy(wacom->wacom_wac.data, raw_data, size);
3bea733ab   Ping Cheng   USB: wacom tablet...
60

29b473913   Benjamin Tissoires   Input: wacom - sw...
61
62
63
  	wacom_wac_irq(&wacom->wacom_wac, size);
  
  	return 0;
3bea733ab   Ping Cheng   USB: wacom tablet...
64
  }
3bea733ab   Ping Cheng   USB: wacom tablet...
65
66
  static int wacom_open(struct input_dev *dev)
  {
7791bdae7   Dmitry Torokhov   Input: drivers/us...
67
  	struct wacom *wacom = input_get_drvdata(dev);
29b473913   Benjamin Tissoires   Input: wacom - sw...
68

dff674168   Benjamin Tissoires   HID: wacom: fix f...
69
  	return hid_hw_open(wacom->hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
70
71
72
73
  }
  
  static void wacom_close(struct input_dev *dev)
  {
7791bdae7   Dmitry Torokhov   Input: drivers/us...
74
  	struct wacom *wacom = input_get_drvdata(dev);
3bea733ab   Ping Cheng   USB: wacom tablet...
75

29b473913   Benjamin Tissoires   Input: wacom - sw...
76
  	hid_hw_close(wacom->hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
77
  }
16bf288c4   Chris Bagwell   Input: wacom - cr...
78
  /*
198fdee28   Benjamin Tissoires   Input: wacom - us...
79
   * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res.
115d5e12a   Jason Gerecke   Input: wacom - in...
80
81
   */
  static int wacom_calc_hid_res(int logical_extents, int physical_extents,
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
82
  			       unsigned unit, int exponent)
115d5e12a   Jason Gerecke   Input: wacom - in...
83
  {
198fdee28   Benjamin Tissoires   Input: wacom - us...
84
85
86
87
88
89
90
91
  	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...
92
  }
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
93
94
  static void wacom_feature_mapping(struct hid_device *hdev,
  		struct hid_field *field, struct hid_usage *usage)
f393ee2b8   Ping Cheng   Input: wacom - re...
95
  {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
96
97
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
98
  	struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
99
100
  	u8 *data;
  	int ret;
f393ee2b8   Ping Cheng   Input: wacom - re...
101

c669fb2b9   Benjamin Tissoires   Input: wacom - us...
102
103
104
  	switch (usage->hid) {
  	case HID_DG_CONTACTMAX:
  		/* leave touch_max as is if predefined */
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
105
106
107
108
109
110
111
112
113
114
115
116
  		if (!features->touch_max) {
  			/* read manually */
  			data = kzalloc(2, GFP_KERNEL);
  			if (!data)
  				break;
  			data[0] = field->report->id;
  			ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
  						data, 2, 0);
  			if (ret == 2)
  				features->touch_max = data[1];
  			kfree(data);
  		}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
117
  		break;
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
118
119
120
121
122
123
124
125
126
127
128
  	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;
f393ee2b8   Ping Cheng   Input: wacom - re...
129
130
  	}
  }
428f85884   Chris Bagwell   Input: wacom - ad...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  /*
   * 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...
159
   *
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
160
161
   * 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...
162
   */
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
163
164
  static void wacom_usage_mapping(struct hid_device *hdev,
  		struct hid_field *field, struct hid_usage *usage)
545f4e99d   Ping Cheng   Input: wacom - ad...
165
  {
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
166
167
168
169
170
171
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
  	bool finger = (field->logical == HID_DG_FINGER) ||
  		      (field->physical == HID_DG_FINGER);
  	bool pen = (field->logical == HID_DG_STYLUS) ||
  		   (field->physical == HID_DG_STYLUS);
e9fc413f4   Jason Gerecke   Input: wacom - ov...
172

c669fb2b9   Benjamin Tissoires   Input: wacom - us...
173
174
175
176
177
178
179
  	/*
  	* Requiring Stylus Usage will ignore boot mouse
  	* X/Y values and some cases of invalid Digitizer X/Y
  	* values commonly reported.
  	*/
  	if (!pen && !finger)
  		return;
30ebc1aea   Ping Cheng   HID: wacom - Bamb...
180
181
182
183
184
185
186
187
188
  	/*
  	 * Bamboo models do not support HID_DG_CONTACTMAX.
  	 * And, Bamboo Pen only descriptor contains touch.
  	 */
  	if (features->type != BAMBOO_PT) {
  		/* ISDv4 touch devices at least supports one touch point */
  		if (finger && !features->touch_max)
  			features->touch_max = 1;
  	}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
189
190
191
192
193
194
195
196
197
198
  
  	switch (usage->hid) {
  	case HID_GD_X:
  		features->x_max = field->logical_maximum;
  		if (finger) {
  			features->device_type = BTN_TOOL_FINGER;
  			features->x_phy = field->physical_maximum;
  			if (features->type != BAMBOO_PT) {
  				features->unit = field->unit;
  				features->unitExpo = field->unit_exponent;
545f4e99d   Ping Cheng   Input: wacom - ad...
199
  			}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  		} else {
  			features->device_type = BTN_TOOL_PEN;
  		}
  		break;
  	case HID_GD_Y:
  		features->y_max = field->logical_maximum;
  		if (finger) {
  			features->y_phy = field->physical_maximum;
  			if (features->type != BAMBOO_PT) {
  				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...
219
220
221
  
  	if (features->type == HID_GENERIC)
  		wacom_wac_usage_mapping(hdev, field, usage);
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
222
  }
4134361af   Chris Bagwell   Input: wacom - re...
223

b58ba1ba1   Jason Gerecke   HID: wacom: Initi...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  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 */
  		if (features->touch_max > 1) {
  			input_mt_init_slots(wacom_wac->input, wacom_wac->features.touch_max,
  				    INPUT_MT_DIRECT);
  		}
  	}
  }
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  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...
256
  			}
545f4e99d   Ping Cheng   Input: wacom - ad...
257
258
  		}
  	}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
259
260
261
262
263
264
265
266
267
268
269
270
  	/* 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...
271
272
  
  	wacom_post_parse_hid(hdev, features);
545f4e99d   Ping Cheng   Input: wacom - ad...
273
  }
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  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;
  }
27b20a9de   Benjamin Tissoires   Input: wacom - us...
292
293
  static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
  		int length, int mode)
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
294
295
  {
  	unsigned char *rep_data;
fe494bc2f   Jason Gerecke   Input: wacom - cl...
296
  	int error = -ENOMEM, limit = 0;
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
297

fe494bc2f   Jason Gerecke   Input: wacom - cl...
298
  	rep_data = kzalloc(length, GFP_KERNEL);
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
299
  	if (!rep_data)
ec67bbedc   Ping Cheng   Input: wacom - ad...
300
  		return error;
fe494bc2f   Jason Gerecke   Input: wacom - cl...
301
  	do {
9937c0268   Chris Bagwell   Input: wacom - fi...
302
303
  		rep_data[0] = report_id;
  		rep_data[1] = mode;
296b73787   Przemo Firszt   Input: wacom - re...
304
305
  		error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
  					 length, 1);
3cb83157e   Benjamin Tissoires   Input: Revert "wa...
306
  		if (error >= 0)
27b20a9de   Benjamin Tissoires   Input: wacom - us...
307
  			error = wacom_get_report(hdev, HID_FEATURE_REPORT,
c64d88347   Ping Cheng   HID: wacom - remo...
308
  			                         rep_data, length, 1);
fe494bc2f   Jason Gerecke   Input: wacom - cl...
309
310
311
312
313
314
  	} while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
  
  	kfree(rep_data);
  
  	return error < 0 ? error : 0;
  }
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
315
316
317
  static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
  		struct wacom_features *features)
  {
387142bb8   Benjamin Tissoires   Input: wacom - ha...
318
319
320
321
322
323
324
325
  	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...
326
327
  		ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
  					3);
387142bb8   Benjamin Tissoires   Input: wacom - ha...
328
329
330
331
332
333
  
  		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...
334
  						rep_data, 2, 3);
387142bb8   Benjamin Tissoires   Input: wacom - ha...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  
  			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...
350
351
352
353
354
355
356
357
  	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...
358
359
  		ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
  					1);
81af7e61a   Benjamin Tissoires   Input: wacom - ha...
360
361
362
  		if (ret >= 0)
  			wacom->wacom_wac.bt_high_speed = speed;
  		break;
387142bb8   Benjamin Tissoires   Input: wacom - ha...
363
  	}
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
364
365
  	return 0;
  }
fe494bc2f   Jason Gerecke   Input: wacom - cl...
366
367
368
369
370
371
372
  /*
   * 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.
   */
27b20a9de   Benjamin Tissoires   Input: wacom - us...
373
374
  static int wacom_query_tablet_data(struct hid_device *hdev,
  		struct wacom_features *features)
fe494bc2f   Jason Gerecke   Input: wacom - cl...
375
  {
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
376
377
  	if (hdev->bus == BUS_BLUETOOTH)
  		return wacom_bt_query_tablet_data(hdev, 1, features);
5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
378
379
  	if (features->type == HID_GENERIC)
  		return wacom_hid_set_device_mode(hdev);
1963518b9   Ping Cheng   Input: wacom - ad...
380
  	if (features->device_type == BTN_TOOL_FINGER) {
ea2e60244   Ping Cheng   Input: wacom - re...
381
  		if (features->type > TABLETPC) {
fe494bc2f   Jason Gerecke   Input: wacom - cl...
382
  			/* MT Tablet PC touch */
27b20a9de   Benjamin Tissoires   Input: wacom - us...
383
  			return wacom_set_device_mode(hdev, 3, 4, 4);
fe494bc2f   Jason Gerecke   Input: wacom - cl...
384
  		}
36d3c510e   Jason Gerecke   Input: wacom - su...
385
  		else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
27b20a9de   Benjamin Tissoires   Input: wacom - us...
386
  			return wacom_set_device_mode(hdev, 18, 3, 2);
b1e4279e4   Jason Gerecke   Input: wacom - ad...
387
  		}
fe494bc2f   Jason Gerecke   Input: wacom - cl...
388
389
  	} else if (features->device_type == BTN_TOOL_PEN) {
  		if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
27b20a9de   Benjamin Tissoires   Input: wacom - us...
390
  			return wacom_set_device_mode(hdev, 2, 2, 2);
1963518b9   Ping Cheng   Input: wacom - ad...
391
  		}
ec67bbedc   Ping Cheng   Input: wacom - ad...
392
  	}
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
393

fe494bc2f   Jason Gerecke   Input: wacom - cl...
394
  	return 0;
3b7307c2d   Dmitry Torokhov   Input: wacom - do...
395
  }
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
396
  static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
1963518b9   Ping Cheng   Input: wacom - ad...
397
  					 struct wacom_features *features)
ec67bbedc   Ping Cheng   Input: wacom - ad...
398
  {
27b20a9de   Benjamin Tissoires   Input: wacom - us...
399
400
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct usb_interface *intf = wacom->intf;
ec67bbedc   Ping Cheng   Input: wacom - ad...
401

fed87e655   Henrik Rydberg   Input: wacom - ad...
402
  	/* default features */
ec67bbedc   Ping Cheng   Input: wacom - ad...
403
  	features->device_type = BTN_TOOL_PEN;
fed87e655   Henrik Rydberg   Input: wacom - ad...
404
405
406
407
  	features->x_fuzz = 4;
  	features->y_fuzz = 4;
  	features->pressure_fuzz = 0;
  	features->distance_fuzz = 0;
ec67bbedc   Ping Cheng   Input: wacom - ad...
408

d3825d51c   Chris Bagwell   Input: wacom - wi...
409
410
411
412
413
414
415
416
417
418
  	/*
  	 * 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) {
  		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
  			features->device_type = 0;
  		} else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
adad004e1   Ping Cheng   Input: wacom - BT...
419
  			features->device_type = BTN_TOOL_FINGER;
d3825d51c   Chris Bagwell   Input: wacom - wi...
420
421
422
  			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
  		}
  	}
1963518b9   Ping Cheng   Input: wacom - ad...
423
  	/* only devices that support touch need to retrieve the info */
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
424
425
  	if (features->type < BAMBOO_PT)
  		return;
ec67bbedc   Ping Cheng   Input: wacom - ad...
426

c669fb2b9   Benjamin Tissoires   Input: wacom - us...
427
  	wacom_parse_hid(hdev, features);
ec67bbedc   Ping Cheng   Input: wacom - ad...
428
  }
4451e088c   Benjamin Tissoires   Input: wacom - re...
429
  struct wacom_hdev_data {
4492effff   Ping Cheng   Input: wacom - sh...
430
431
  	struct list_head list;
  	struct kref kref;
4451e088c   Benjamin Tissoires   Input: wacom - re...
432
  	struct hid_device *dev;
4492effff   Ping Cheng   Input: wacom - sh...
433
434
435
436
437
  	struct wacom_shared shared;
  };
  
  static LIST_HEAD(wacom_udev_list);
  static DEFINE_MUTEX(wacom_udev_list_lock);
4451e088c   Benjamin Tissoires   Input: wacom - re...
438
439
  static bool wacom_are_sibling(struct hid_device *hdev,
  		struct hid_device *sibling)
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
440
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
441
442
443
444
445
446
447
448
449
450
  	struct wacom *wacom = hid_get_drvdata(hdev);
  	struct wacom_features *features = &wacom->wacom_wac.features;
  	int vid = features->oVid;
  	int pid = features->oPid;
  	int n1,n2;
  
  	if (vid == 0 && pid == 0) {
  		vid = hdev->vendor;
  		pid = hdev->product;
  	}
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
451

4451e088c   Benjamin Tissoires   Input: wacom - re...
452
453
  	if (vid != sibling->vendor || pid != sibling->product)
  		return false;
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
454

4451e088c   Benjamin Tissoires   Input: wacom - re...
455
456
457
458
459
  	/* Compare the physical path. */
  	n1 = strrchr(hdev->phys, '.') - hdev->phys;
  	n2 = strrchr(sibling->phys, '.') - sibling->phys;
  	if (n1 != n2 || n1 <= 0 || n2 <= 0)
  		return false;
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
460

4451e088c   Benjamin Tissoires   Input: wacom - re...
461
  	return !strncmp(hdev->phys, sibling->phys, n1);
aea2bf6a5   Jason Gerecke   Input: wacom - ha...
462
  }
4451e088c   Benjamin Tissoires   Input: wacom - re...
463
  static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
4492effff   Ping Cheng   Input: wacom - sh...
464
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
465
  	struct wacom_hdev_data *data;
4492effff   Ping Cheng   Input: wacom - sh...
466
467
  
  	list_for_each_entry(data, &wacom_udev_list, list) {
4451e088c   Benjamin Tissoires   Input: wacom - re...
468
  		if (wacom_are_sibling(hdev, data->dev)) {
4492effff   Ping Cheng   Input: wacom - sh...
469
470
471
472
473
474
475
  			kref_get(&data->kref);
  			return data;
  		}
  	}
  
  	return NULL;
  }
4451e088c   Benjamin Tissoires   Input: wacom - re...
476
  static int wacom_add_shared_data(struct hid_device *hdev)
4492effff   Ping Cheng   Input: wacom - sh...
477
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
478
479
480
  	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...
481
482
483
  	int retval = 0;
  
  	mutex_lock(&wacom_udev_list_lock);
4451e088c   Benjamin Tissoires   Input: wacom - re...
484
  	data = wacom_get_hdev_data(hdev);
4492effff   Ping Cheng   Input: wacom - sh...
485
  	if (!data) {
4451e088c   Benjamin Tissoires   Input: wacom - re...
486
  		data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
4492effff   Ping Cheng   Input: wacom - sh...
487
488
489
490
491
492
  		if (!data) {
  			retval = -ENOMEM;
  			goto out;
  		}
  
  		kref_init(&data->kref);
4451e088c   Benjamin Tissoires   Input: wacom - re...
493
  		data->dev = hdev;
4492effff   Ping Cheng   Input: wacom - sh...
494
495
  		list_add_tail(&data->list, &wacom_udev_list);
  	}
4451e088c   Benjamin Tissoires   Input: wacom - re...
496
  	wacom_wac->shared = &data->shared;
4492effff   Ping Cheng   Input: wacom - sh...
497
498
499
500
501
502
503
504
  
  out:
  	mutex_unlock(&wacom_udev_list_lock);
  	return retval;
  }
  
  static void wacom_release_shared_data(struct kref *kref)
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
505
506
  	struct wacom_hdev_data *data =
  		container_of(kref, struct wacom_hdev_data, kref);
4492effff   Ping Cheng   Input: wacom - sh...
507
508
509
510
511
512
513
514
515
516
  
  	mutex_lock(&wacom_udev_list_lock);
  	list_del(&data->list);
  	mutex_unlock(&wacom_udev_list_lock);
  
  	kfree(data);
  }
  
  static void wacom_remove_shared_data(struct wacom_wac *wacom)
  {
4451e088c   Benjamin Tissoires   Input: wacom - re...
517
  	struct wacom_hdev_data *data;
4492effff   Ping Cheng   Input: wacom - sh...
518
519
  
  	if (wacom->shared) {
4451e088c   Benjamin Tissoires   Input: wacom - re...
520
  		data = container_of(wacom->shared, struct wacom_hdev_data, shared);
4492effff   Ping Cheng   Input: wacom - sh...
521
522
523
524
  		kref_put(&data->kref, wacom_release_shared_data);
  		wacom->shared = NULL;
  	}
  }
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
525
526
527
  static int wacom_led_control(struct wacom *wacom)
  {
  	unsigned char *buf;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
528
  	int retval;
912ca216b   Ping Cheng   HID: wacom - enab...
529
530
  	unsigned char report_id = WAC_CMD_LED_CONTROL;
  	int buf_size = 9;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
531

912ca216b   Ping Cheng   HID: wacom - enab...
532
533
534
535
536
  	if (wacom->wacom_wac.pid) { /* wireless connected */
  		report_id = WAC_CMD_WL_LED_CONTROL;
  		buf_size = 13;
  	}
  	buf = kzalloc(buf_size, GFP_KERNEL);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
537
538
  	if (!buf)
  		return -ENOMEM;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
539
  	if (wacom->wacom_wac.features.type >= INTUOS5S &&
9a35c411f   Ping Cheng   Input: wacom - ad...
540
  	    wacom->wacom_wac.features.type <= INTUOSPL) {
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
541
542
543
544
545
546
547
548
  		/*
  		 * Touch Ring and crop mark LED luminance may take on
  		 * one of four values:
  		 *    0 = Low; 1 = Medium; 2 = High; 3 = Off
  		 */
  		int ring_led = wacom->led.select[0] & 0x03;
  		int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
  		int crop_lum = 0;
912ca216b   Ping Cheng   HID: wacom - enab...
549
550
551
552
553
554
555
556
557
558
  		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...
559
560
561
562
563
564
565
  	}
  	else {
  		int led = wacom->led.select[0] | 0x4;
  
  		if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
  		    wacom->wacom_wac.features.type == WACOM_24HD)
  			led |= (wacom->led.select[1] << 4) | 0x40;
912ca216b   Ping Cheng   HID: wacom - enab...
566
  		buf[0] = report_id;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
567
568
569
570
571
  		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...
572

912ca216b   Ping Cheng   HID: wacom - enab...
573
  	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, buf_size,
296b73787   Przemo Firszt   Input: wacom - re...
574
  				  WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
575
576
577
578
  	kfree(buf);
  
  	return retval;
  }
849e2f067   Benjamin Tissoires   Input: wacom - ch...
579
580
  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...
581
582
583
  {
  	unsigned char *buf;
  	int i, retval;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
584
  	const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
585

849e2f067   Benjamin Tissoires   Input: wacom - ch...
586
  	buf = kzalloc(chunk_len + 3 , GFP_KERNEL);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
587
588
589
590
591
592
  	if (!buf)
  		return -ENOMEM;
  
  	/* Send 'start' command */
  	buf[0] = WAC_CMD_ICON_START;
  	buf[1] = 1;
296b73787   Przemo Firszt   Input: wacom - re...
593
594
  	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
  				  WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
595
596
  	if (retval < 0)
  		goto out;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
597
  	buf[0] = xfer_id;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
598
599
600
  	buf[1] = button_id & 0x07;
  	for (i = 0; i < 4; i++) {
  		buf[2] = i;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
601
  		memcpy(buf + 3, img + i * chunk_len, chunk_len);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
602

27b20a9de   Benjamin Tissoires   Input: wacom - us...
603
  		retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
296b73787   Przemo Firszt   Input: wacom - re...
604
  					  buf, chunk_len + 3, WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
605
606
607
608
609
610
611
  		if (retval < 0)
  			break;
  	}
  
  	/* Send 'stop' */
  	buf[0] = WAC_CMD_ICON_START;
  	buf[1] = 0;
296b73787   Przemo Firszt   Input: wacom - re...
612
613
  	wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
  			 WAC_CMD_RETRIES);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
614
615
616
617
618
  
  out:
  	kfree(buf);
  	return retval;
  }
09e7d9410   Ping Cheng   Input: wacom - ad...
619
  static ssize_t wacom_led_select_store(struct device *dev, int set_id,
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
620
621
  				      const char *buf, size_t count)
  {
c31a408f7   Benjamin Tissoires   Input: wacom - in...
622
  	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
29b473913   Benjamin Tissoires   Input: wacom - sw...
623
  	struct wacom *wacom = hid_get_drvdata(hdev);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
624
625
626
627
628
629
630
631
  	unsigned int id;
  	int err;
  
  	err = kstrtouint(buf, 10, &id);
  	if (err)
  		return err;
  
  	mutex_lock(&wacom->lock);
09e7d9410   Ping Cheng   Input: wacom - ad...
632
  	wacom->led.select[set_id] = id & 0x3;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
633
634
635
636
637
638
  	err = wacom_led_control(wacom);
  
  	mutex_unlock(&wacom->lock);
  
  	return err < 0 ? err : count;
  }
09e7d9410   Ping Cheng   Input: wacom - ad...
639
640
641
642
643
644
  #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...
645
646
647
  static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,	\
  	struct device_attribute *attr, char *buf)			\
  {									\
c31a408f7   Benjamin Tissoires   Input: wacom - in...
648
  	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
29b473913   Benjamin Tissoires   Input: wacom - sw...
649
  	struct wacom *wacom = hid_get_drvdata(hdev);			\
37449adc5   Ping Cheng   HID: wacom - Clea...
650
651
652
  	return scnprintf(buf, PAGE_SIZE, "%d
  ",			\
  			 wacom->led.select[SET_ID]);			\
04c59abd3   Ping Cheng   Input: wacom - ma...
653
  }									\
e0984bc37   Ping Cheng   HID: wacom - Add ...
654
  static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM,	\
04c59abd3   Ping Cheng   Input: wacom - ma...
655
  		    wacom_led##SET_ID##_select_show,			\
09e7d9410   Ping Cheng   Input: wacom - ad...
656
657
658
659
  		    wacom_led##SET_ID##_select_store)
  
  DEVICE_LED_SELECT_ATTR(0);
  DEVICE_LED_SELECT_ATTR(1);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  
  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)	\
  {									\
c31a408f7   Benjamin Tissoires   Input: wacom - in...
685
  	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
29b473913   Benjamin Tissoires   Input: wacom - sw...
686
  	struct wacom *wacom = hid_get_drvdata(hdev);			\
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
687
688
689
690
  									\
  	return wacom_luminance_store(wacom, &wacom->led.field,		\
  				     buf, count);			\
  }									\
37449adc5   Ping Cheng   HID: wacom - Clea...
691
692
693
694
695
696
697
  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 ...
698
  static DEVICE_ATTR(name##_luminance, DEV_ATTR_RW_PERM,			\
37449adc5   Ping Cheng   HID: wacom - Clea...
699
700
  		   wacom_##name##_luminance_show,			\
  		   wacom_##name##_luminance_store)
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
701
702
703
704
705
706
707
708
  
  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)
  {
c31a408f7   Benjamin Tissoires   Input: wacom - in...
709
  	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
29b473913   Benjamin Tissoires   Input: wacom - sw...
710
  	struct wacom *wacom = hid_get_drvdata(hdev);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
711
  	int err;
849e2f067   Benjamin Tissoires   Input: wacom - ch...
712
713
714
715
716
717
718
719
720
721
  	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...
722

849e2f067   Benjamin Tissoires   Input: wacom - ch...
723
  	if (count != len)
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
724
725
726
  		return -EINVAL;
  
  	mutex_lock(&wacom->lock);
849e2f067   Benjamin Tissoires   Input: wacom - ch...
727
  	err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
728
729
730
731
732
733
734
735
736
737
738
739
  
  	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 ...
740
  static DEVICE_ATTR(button##BUTTON_ID##_rawimg, DEV_ATTR_WO_PERM,	\
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
741
742
743
744
745
746
747
748
749
750
  		   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...
751
752
753
754
755
756
757
758
759
760
761
762
  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...
763
764
  	&dev_attr_status0_luminance.attr,
  	&dev_attr_status1_luminance.attr,
09e7d9410   Ping Cheng   Input: wacom - ad...
765
  	&dev_attr_status_led0_select.attr,
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
766
767
768
769
770
771
772
773
774
775
776
  	&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...
777
  static struct attribute_group intuos4_led_attr_group = {
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
778
  	.name = "wacom_led",
09e7d9410   Ping Cheng   Input: wacom - ad...
779
  	.attrs = intuos4_led_attrs,
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
780
  };
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
781
782
783
784
785
786
787
788
789
790
  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,
  };
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
791
792
793
  static int wacom_initialize_leds(struct wacom *wacom)
  {
  	int error;
09e7d9410   Ping Cheng   Input: wacom - ad...
794
795
  	/* Initialize default values */
  	switch (wacom->wacom_wac.features.type) {
a19fc9868   Jason Gerecke   Input: wacom - in...
796
  	case INTUOS4S:
09e7d9410   Ping Cheng   Input: wacom - ad...
797
  	case INTUOS4:
81af7e61a   Benjamin Tissoires   Input: wacom - ha...
798
  	case INTUOS4WL:
09e7d9410   Ping Cheng   Input: wacom - ad...
799
800
801
  	case INTUOS4L:
  		wacom->led.select[0] = 0;
  		wacom->led.select[1] = 0;
f4fa9a6d8   Ping Cheng   Input: wacom - lo...
802
  		wacom->led.llv = 10;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
803
804
  		wacom->led.hlv = 20;
  		wacom->led.img_lum = 10;
c31a408f7   Benjamin Tissoires   Input: wacom - in...
805
  		error = sysfs_create_group(&wacom->hdev->dev.kobj,
09e7d9410   Ping Cheng   Input: wacom - ad...
806
807
  					   &intuos4_led_attr_group);
  		break;
246835fcc   Jason Gerecke   Input: wacom - ad...
808
  	case WACOM_24HD:
09e7d9410   Ping Cheng   Input: wacom - ad...
809
810
811
812
813
814
  	case WACOM_21UX2:
  		wacom->led.select[0] = 0;
  		wacom->led.select[1] = 0;
  		wacom->led.llv = 0;
  		wacom->led.hlv = 0;
  		wacom->led.img_lum = 0;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
815

c31a408f7   Benjamin Tissoires   Input: wacom - in...
816
  		error = sysfs_create_group(&wacom->hdev->dev.kobj,
09e7d9410   Ping Cheng   Input: wacom - ad...
817
818
  					   &cintiq_led_attr_group);
  		break;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
819
820
821
  	case INTUOS5S:
  	case INTUOS5:
  	case INTUOS5L:
9a35c411f   Ping Cheng   Input: wacom - ad...
822
823
824
  	case INTUOSPS:
  	case INTUOSPM:
  	case INTUOSPL:
c2b0c273e   Ping Cheng   Input: wacom - LE...
825
826
827
828
829
830
  		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) {
  			wacom->led.select[0] = 0;
  			wacom->led.select[1] = 0;
  			wacom->led.llv = 32;
  			wacom->led.hlv = 0;
  			wacom->led.img_lum = 0;
c31a408f7   Benjamin Tissoires   Input: wacom - in...
831
  			error = sysfs_create_group(&wacom->hdev->dev.kobj,
c2b0c273e   Ping Cheng   Input: wacom - LE...
832
833
834
  						  &intuos5_led_attr_group);
  		} else
  			return 0;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
835
  		break;
09e7d9410   Ping Cheng   Input: wacom - ad...
836
837
  	default:
  		return 0;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
838
  	}
09e7d9410   Ping Cheng   Input: wacom - ad...
839
  	if (error) {
c31a408f7   Benjamin Tissoires   Input: wacom - in...
840
  		hid_err(wacom->hdev,
09e7d9410   Ping Cheng   Input: wacom - ad...
841
842
843
844
845
  			"cannot create sysfs group err: %d
  ", error);
  		return error;
  	}
  	wacom_led_control(wacom);
c757cbafd   Benjamin Tissoires   Input: wacom - pu...
846
  	wacom->led_initialized = true;
09e7d9410   Ping Cheng   Input: wacom - ad...
847

5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
848
849
850
851
852
  	return 0;
  }
  
  static void wacom_destroy_leds(struct wacom *wacom)
  {
c757cbafd   Benjamin Tissoires   Input: wacom - pu...
853
854
855
856
  	if (!wacom->led_initialized)
  		return;
  
  	wacom->led_initialized = false;
09e7d9410   Ping Cheng   Input: wacom - ad...
857
  	switch (wacom->wacom_wac.features.type) {
a19fc9868   Jason Gerecke   Input: wacom - in...
858
  	case INTUOS4S:
09e7d9410   Ping Cheng   Input: wacom - ad...
859
  	case INTUOS4:
81af7e61a   Benjamin Tissoires   Input: wacom - ha...
860
  	case INTUOS4WL:
09e7d9410   Ping Cheng   Input: wacom - ad...
861
  	case INTUOS4L:
c31a408f7   Benjamin Tissoires   Input: wacom - in...
862
  		sysfs_remove_group(&wacom->hdev->dev.kobj,
09e7d9410   Ping Cheng   Input: wacom - ad...
863
864
  				   &intuos4_led_attr_group);
  		break;
246835fcc   Jason Gerecke   Input: wacom - ad...
865
  	case WACOM_24HD:
09e7d9410   Ping Cheng   Input: wacom - ad...
866
  	case WACOM_21UX2:
c31a408f7   Benjamin Tissoires   Input: wacom - in...
867
  		sysfs_remove_group(&wacom->hdev->dev.kobj,
09e7d9410   Ping Cheng   Input: wacom - ad...
868
869
  				   &cintiq_led_attr_group);
  		break;
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
870
871
872
873
  
  	case INTUOS5S:
  	case INTUOS5:
  	case INTUOS5L:
9a35c411f   Ping Cheng   Input: wacom - ad...
874
875
876
  	case INTUOSPS:
  	case INTUOSPM:
  	case INTUOSPL:
c2b0c273e   Ping Cheng   Input: wacom - LE...
877
  		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN)
c31a408f7   Benjamin Tissoires   Input: wacom - in...
878
  			sysfs_remove_group(&wacom->hdev->dev.kobj,
c2b0c273e   Ping Cheng   Input: wacom - LE...
879
  					   &intuos5_led_attr_group);
9b5b95dd5   Jason Gerecke   Input: wacom - ad...
880
  		break;
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
881
882
  	}
  }
a1d552cc1   Chris Bagwell   Input: wacom - wi...
883
  static enum power_supply_property wacom_battery_props[] = {
ac8d10101   Benjamin Tissoires   Input: wacom - en...
884
  	POWER_SUPPLY_PROP_STATUS,
6e2a6e806   Bastien Nocera   Input: wacom - ex...
885
  	POWER_SUPPLY_PROP_SCOPE,
a1d552cc1   Chris Bagwell   Input: wacom - wi...
886
887
  	POWER_SUPPLY_PROP_CAPACITY
  };
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
888
889
890
891
892
  static enum power_supply_property wacom_ac_props[] = {
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_ONLINE,
  	POWER_SUPPLY_PROP_SCOPE,
  };
a1d552cc1   Chris Bagwell   Input: wacom - wi...
893
894
895
896
897
898
899
900
  static int wacom_battery_get_property(struct power_supply *psy,
  				      enum power_supply_property psp,
  				      union power_supply_propval *val)
  {
  	struct wacom *wacom = container_of(psy, struct wacom, battery);
  	int ret = 0;
  
  	switch (psp) {
6e2a6e806   Bastien Nocera   Input: wacom - ex...
901
902
903
  		case POWER_SUPPLY_PROP_SCOPE:
  			val->intval = POWER_SUPPLY_SCOPE_DEVICE;
  			break;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
904
905
  		case POWER_SUPPLY_PROP_CAPACITY:
  			val->intval =
ac8d10101   Benjamin Tissoires   Input: wacom - en...
906
907
908
909
910
911
912
913
914
915
  				wacom->wacom_wac.battery_capacity;
  			break;
  		case POWER_SUPPLY_PROP_STATUS:
  			if (wacom->wacom_wac.bat_charging)
  				val->intval = POWER_SUPPLY_STATUS_CHARGING;
  			else if (wacom->wacom_wac.battery_capacity == 100 &&
  				    wacom->wacom_wac.ps_connected)
  				val->intval = POWER_SUPPLY_STATUS_FULL;
  			else
  				val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
916
917
918
919
920
921
922
923
  			break;
  		default:
  			ret = -EINVAL;
  			break;
  	}
  
  	return ret;
  }
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
  static int wacom_ac_get_property(struct power_supply *psy,
  				enum power_supply_property psp,
  				union power_supply_propval *val)
  {
  	struct wacom *wacom = container_of(psy, struct wacom, ac);
  	int ret = 0;
  
  	switch (psp) {
  	case POWER_SUPPLY_PROP_PRESENT:
  		/* fall through */
  	case POWER_SUPPLY_PROP_ONLINE:
  		val->intval = wacom->wacom_wac.ps_connected;
  		break;
  	case POWER_SUPPLY_PROP_SCOPE:
  		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
  		break;
  	default:
  		ret = -EINVAL;
  		break;
  	}
  	return ret;
  }
a1d552cc1   Chris Bagwell   Input: wacom - wi...
946
947
  static int wacom_initialize_battery(struct wacom *wacom)
  {
d70420b91   Benjamin Tissoires   Input: wacom - us...
948
  	static atomic_t battery_no = ATOMIC_INIT(0);
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
949
  	int error;
d70420b91   Benjamin Tissoires   Input: wacom - us...
950
  	unsigned long n;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
951

ac8d10101   Benjamin Tissoires   Input: wacom - en...
952
  	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
d70420b91   Benjamin Tissoires   Input: wacom - us...
953
  		n = atomic_inc_return(&battery_no) - 1;
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
954

a1d552cc1   Chris Bagwell   Input: wacom - wi...
955
956
957
  		wacom->battery.properties = wacom_battery_props;
  		wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
  		wacom->battery.get_property = wacom_battery_get_property;
d70420b91   Benjamin Tissoires   Input: wacom - us...
958
959
  		sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
  		wacom->battery.name = wacom->wacom_wac.bat_name;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
960
961
  		wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
  		wacom->battery.use_for_apm = 0;
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
962
963
964
965
966
967
968
  		wacom->ac.properties = wacom_ac_props;
  		wacom->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
  		wacom->ac.get_property = wacom_ac_get_property;
  		sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n);
  		wacom->ac.name = wacom->wacom_wac.ac_name;
  		wacom->ac.type = POWER_SUPPLY_TYPE_MAINS;
  		wacom->ac.use_for_apm = 0;
dd3181a70   Benjamin Tissoires   Input: wacom - re...
969
  		error = power_supply_register(&wacom->hdev->dev,
a1d552cc1   Chris Bagwell   Input: wacom - wi...
970
  					      &wacom->battery);
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
971
972
973
974
  		if (error)
  			return error;
  
  		power_supply_powers(&wacom->battery, &wacom->hdev->dev);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
975

7dbd229e1   Benjamin Tissoires   Input: wacom - re...
976
977
978
979
980
981
982
  		error = power_supply_register(&wacom->hdev->dev, &wacom->ac);
  		if (error) {
  			power_supply_unregister(&wacom->battery);
  			return error;
  		}
  
  		power_supply_powers(&wacom->ac, &wacom->hdev->dev);
a1d552cc1   Chris Bagwell   Input: wacom - wi...
983
  	}
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
984
  	return 0;
a1d552cc1   Chris Bagwell   Input: wacom - wi...
985
986
987
988
  }
  
  static void wacom_destroy_battery(struct wacom *wacom)
  {
ac8d10101   Benjamin Tissoires   Input: wacom - en...
989
990
  	if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
  	     wacom->battery.dev) {
a1d552cc1   Chris Bagwell   Input: wacom - wi...
991
  		power_supply_unregister(&wacom->battery);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
992
  		wacom->battery.dev = NULL;
7dbd229e1   Benjamin Tissoires   Input: wacom - re...
993
994
  		power_supply_unregister(&wacom->ac);
  		wacom->ac.dev = NULL;
b7af2bb84   Chris Bagwell   Input: wacom - ba...
995
  	}
a1d552cc1   Chris Bagwell   Input: wacom - wi...
996
  }
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  static ssize_t wacom_show_speed(struct device *dev,
  				struct device_attribute
  				*attr, char *buf)
  {
  	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
  	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)
  {
  	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
  	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 ...
1026
  static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM,
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1027
  		wacom_show_speed, wacom_store_speed);
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1028
  static struct input_dev *wacom_allocate_input(struct wacom *wacom)
3aac0ef10   Chris Bagwell   Input: wacom - is...
1029
1030
  {
  	struct input_dev *input_dev;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1031
  	struct hid_device *hdev = wacom->hdev;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1032
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
3aac0ef10   Chris Bagwell   Input: wacom - is...
1033
1034
  
  	input_dev = input_allocate_device();
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1035
1036
  	if (!input_dev)
  		return NULL;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1037
1038
  
  	input_dev->name = wacom_wac->name;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1039
1040
  	input_dev->phys = hdev->phys;
  	input_dev->dev.parent = &hdev->dev;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1041
1042
  	input_dev->open = wacom_open;
  	input_dev->close = wacom_close;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1043
1044
1045
  	input_dev->uniq = hdev->uniq;
  	input_dev->id.bustype = hdev->bus;
  	input_dev->id.vendor  = hdev->vendor;
12969e3bd   Benjamin Tissoires   HID: wacom: make ...
1046
  	input_dev->id.product = wacom_wac->pid ? wacom_wac->pid : hdev->product;
b6c79f2ca   Benjamin Tissoires   Input: wacom - re...
1047
  	input_dev->id.version = hdev->version;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1048
  	input_set_drvdata(input_dev, wacom);
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1049
1050
  	return input_dev;
  }
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1051
  static void wacom_free_inputs(struct wacom *wacom)
008f4d9e3   Benjamin Tissoires   Input: wacom - sp...
1052
  {
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1053
1054
1055
1056
1057
1058
1059
1060
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
  
  	if (wacom_wac->input)
  		input_free_device(wacom_wac->input);
  	if (wacom_wac->pad_input)
  		input_free_device(wacom_wac->pad_input);
  	wacom_wac->input = NULL;
  	wacom_wac->pad_input = NULL;
008f4d9e3   Benjamin Tissoires   Input: wacom - sp...
1061
  }
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1062
  static int wacom_allocate_inputs(struct wacom *wacom)
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1063
1064
1065
  {
  	struct input_dev *input_dev, *pad_input_dev;
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1066
1067
1068
1069
  
  	input_dev = wacom_allocate_input(wacom);
  	pad_input_dev = wacom_allocate_input(wacom);
  	if (!input_dev || !pad_input_dev) {
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1070
1071
  		wacom_free_inputs(wacom);
  		return -ENOMEM;
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1072
  	}
3aac0ef10   Chris Bagwell   Input: wacom - is...
1073
  	wacom_wac->input = input_dev;
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1074
1075
  	wacom_wac->pad_input = pad_input_dev;
  	wacom_wac->pad_input->name = wacom_wac->pad_name;
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  	return 0;
  }
  
  static void wacom_clean_inputs(struct wacom *wacom)
  {
  	if (wacom->wacom_wac.input) {
  		if (wacom->wacom_wac.input_registered)
  			input_unregister_device(wacom->wacom_wac.input);
  		else
  			input_free_device(wacom->wacom_wac.input);
  	}
  	if (wacom->wacom_wac.pad_input) {
954df6ad0   Ping Cheng   HID: wacom: PAD i...
1088
  		if (wacom->wacom_wac.pad_registered)
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  			input_unregister_device(wacom->wacom_wac.pad_input);
  		else
  			input_free_device(wacom->wacom_wac.pad_input);
  	}
  	wacom->wacom_wac.input = NULL;
  	wacom->wacom_wac.pad_input = NULL;
  	wacom_destroy_leds(wacom);
  }
  
  static int wacom_register_inputs(struct wacom *wacom)
  {
  	struct input_dev *input_dev, *pad_input_dev;
  	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
  	int error;
  
  	input_dev = wacom_wac->input;
  	pad_input_dev = wacom_wac->pad_input;
  
  	if (!input_dev || !pad_input_dev)
  		return -EINVAL;
30ebc1aea   Ping Cheng   HID: wacom - Bamb...
1109
1110
1111
1112
1113
  	error = wacom_setup_pentouch_input_capabilities(input_dev, wacom_wac);
  	if (!error) {
  		error = input_register_device(input_dev);
  		if (error)
  			return error;
954df6ad0   Ping Cheng   HID: wacom: PAD i...
1114
  		wacom_wac->input_registered = true;
30ebc1aea   Ping Cheng   HID: wacom - Bamb...
1115
  	}
1963518b9   Ping Cheng   Input: wacom - ad...
1116

d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1117
1118
1119
1120
1121
1122
1123
1124
1125
  	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)
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1126
  			goto fail_register_pad_input;
954df6ad0   Ping Cheng   HID: wacom: PAD i...
1127
  		wacom_wac->pad_registered = true;
912ca216b   Ping Cheng   HID: wacom - enab...
1128
1129
1130
  
  		error = wacom_initialize_leds(wacom);
  		if (error)
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1131
  			goto fail_leds;
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1132
  	}
1963518b9   Ping Cheng   Input: wacom - ad...
1133
  	return 0;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1134

7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1135
  fail_leds:
912ca216b   Ping Cheng   HID: wacom - enab...
1136
1137
  	input_unregister_device(pad_input_dev);
  	pad_input_dev = NULL;
954df6ad0   Ping Cheng   HID: wacom: PAD i...
1138
  	wacom_wac->pad_registered = false;
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1139
  fail_register_pad_input:
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1140
  	input_unregister_device(input_dev);
1963518b9   Ping Cheng   Input: wacom - ad...
1141
  	wacom_wac->input = NULL;
954df6ad0   Ping Cheng   HID: wacom: PAD i...
1142
  	wacom_wac->input_registered = false;
3aac0ef10   Chris Bagwell   Input: wacom - is...
1143
1144
  	return error;
  }
16bf288c4   Chris Bagwell   Input: wacom - cr...
1145
1146
1147
1148
1149
  static void wacom_wireless_work(struct work_struct *work)
  {
  	struct wacom *wacom = container_of(work, struct wacom, work);
  	struct usb_device *usbdev = wacom->usbdev;
  	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
29b473913   Benjamin Tissoires   Input: wacom - sw...
1150
  	struct hid_device *hdev1, *hdev2;
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1151
1152
1153
  	struct wacom *wacom1, *wacom2;
  	struct wacom_wac *wacom_wac1, *wacom_wac2;
  	int error;
16bf288c4   Chris Bagwell   Input: wacom - cr...
1154
1155
1156
  
  	/*
  	 * Regardless if this is a disconnect or a new tablet,
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1157
  	 * remove any existing input and battery devices.
16bf288c4   Chris Bagwell   Input: wacom - cr...
1158
  	 */
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1159
  	wacom_destroy_battery(wacom);
16bf288c4   Chris Bagwell   Input: wacom - cr...
1160
  	/* Stylus interface */
29b473913   Benjamin Tissoires   Input: wacom - sw...
1161
1162
  	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
  	wacom1 = hid_get_drvdata(hdev1);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1163
  	wacom_wac1 = &(wacom1->wacom_wac);
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1164
  	wacom_clean_inputs(wacom1);
16bf288c4   Chris Bagwell   Input: wacom - cr...
1165
1166
  
  	/* Touch interface */
29b473913   Benjamin Tissoires   Input: wacom - sw...
1167
1168
  	hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
  	wacom2 = hid_get_drvdata(hdev2);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1169
  	wacom_wac2 = &(wacom2->wacom_wac);
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1170
  	wacom_clean_inputs(wacom2);
16bf288c4   Chris Bagwell   Input: wacom - cr...
1171
1172
  
  	if (wacom_wac->pid == 0) {
e2114ce1a   Benjamin Tissoires   Input: wacom - us...
1173
1174
  		hid_info(wacom->hdev, "wireless tablet disconnected
  ");
ac8d10101   Benjamin Tissoires   Input: wacom - en...
1175
  		wacom_wac1->shared->type = 0;
16bf288c4   Chris Bagwell   Input: wacom - cr...
1176
  	} else {
29b473913   Benjamin Tissoires   Input: wacom - sw...
1177
  		const struct hid_device_id *id = wacom_ids;
16bf288c4   Chris Bagwell   Input: wacom - cr...
1178

e2114ce1a   Benjamin Tissoires   Input: wacom - us...
1179
1180
  		hid_info(wacom->hdev, "wireless tablet connected with PID %x
  ",
eb71d1bb2   Dmitry Torokhov   Input: wacom - us...
1181
  			 wacom_wac->pid);
16bf288c4   Chris Bagwell   Input: wacom - cr...
1182

29b473913   Benjamin Tissoires   Input: wacom - sw...
1183
1184
1185
  		while (id->bus) {
  			if (id->vendor == USB_VENDOR_ID_WACOM &&
  			    id->product == wacom_wac->pid)
16bf288c4   Chris Bagwell   Input: wacom - cr...
1186
1187
1188
  				break;
  			id++;
  		}
29b473913   Benjamin Tissoires   Input: wacom - sw...
1189
  		if (!id->bus) {
e2114ce1a   Benjamin Tissoires   Input: wacom - us...
1190
1191
  			hid_info(wacom->hdev, "ignoring unknown PID.
  ");
16bf288c4   Chris Bagwell   Input: wacom - cr...
1192
1193
1194
1195
  			return;
  		}
  
  		/* Stylus interface */
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1196
  		wacom_wac1->features =
29b473913   Benjamin Tissoires   Input: wacom - sw...
1197
  			*((struct wacom_features *)id->driver_data);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1198
  		wacom_wac1->features.device_type = BTN_TOOL_PEN;
57bcfce37   Ping Cheng   Input: wacom - no...
1199
1200
  		snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
  			 wacom_wac1->features.name);
008f4d9e3   Benjamin Tissoires   Input: wacom - sp...
1201
1202
  		snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
  			 wacom_wac1->features.name);
961794a00   Ping Cheng   Input: wacom - ad...
1203
1204
  		wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
  		wacom_wac1->shared->type = wacom_wac1->features.type;
912ca216b   Ping Cheng   HID: wacom - enab...
1205
  		wacom_wac1->pid = wacom_wac->pid;
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1206
1207
  		error = wacom_allocate_inputs(wacom1) ||
  			wacom_register_inputs(wacom1);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1208
  		if (error)
57bcfce37   Ping Cheng   Input: wacom - no...
1209
  			goto fail;
16bf288c4   Chris Bagwell   Input: wacom - cr...
1210
1211
  
  		/* Touch interface */
b5fd2a3e9   Ping Cheng   Input: wacom - ad...
1212
1213
  		if (wacom_wac1->features.touch_max ||
  		    wacom_wac1->features.type == INTUOSHT) {
57bcfce37   Ping Cheng   Input: wacom - no...
1214
  			wacom_wac2->features =
29b473913   Benjamin Tissoires   Input: wacom - sw...
1215
  				*((struct wacom_features *)id->driver_data);
57bcfce37   Ping Cheng   Input: wacom - no...
1216
1217
1218
1219
1220
1221
1222
1223
1224
  			wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
  			wacom_wac2->features.device_type = BTN_TOOL_FINGER;
  			wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
  			if (wacom_wac2->features.touch_max)
  				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
  					 "%s (WL) Finger",wacom_wac2->features.name);
  			else
  				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
  					 "%s (WL) Pad",wacom_wac2->features.name);
008f4d9e3   Benjamin Tissoires   Input: wacom - sp...
1225
1226
  			snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
  				 "%s (WL) Pad", wacom_wac2->features.name);
912ca216b   Ping Cheng   HID: wacom - enab...
1227
  			wacom_wac2->pid = wacom_wac->pid;
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1228
1229
  			error = wacom_allocate_inputs(wacom2) ||
  				wacom_register_inputs(wacom2);
57bcfce37   Ping Cheng   Input: wacom - no...
1230
1231
  			if (error)
  				goto fail;
961794a00   Ping Cheng   Input: wacom - ad...
1232
1233
1234
1235
  
  			if (wacom_wac1->features.type == INTUOSHT &&
  			    wacom_wac1->features.touch_max)
  				wacom_wac->shared->touch_input = wacom_wac2->input;
57bcfce37   Ping Cheng   Input: wacom - no...
1236
  		}
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1237
1238
1239
  
  		error = wacom_initialize_battery(wacom);
  		if (error)
57bcfce37   Ping Cheng   Input: wacom - no...
1240
  			goto fail;
16bf288c4   Chris Bagwell   Input: wacom - cr...
1241
  	}
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1242
1243
  
  	return;
57bcfce37   Ping Cheng   Input: wacom - no...
1244
  fail:
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1245
1246
  	wacom_clean_inputs(wacom1);
  	wacom_clean_inputs(wacom2);
b7af2bb84   Chris Bagwell   Input: wacom - ba...
1247
  	return;
16bf288c4   Chris Bagwell   Input: wacom - cr...
1248
  }
401d7d108   Ping Cheng   Input: wacom - in...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  /*
   * 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)
  {
  	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);
  }
01c846f95   Benjamin Tissoires   Input: wacom - co...
1275
1276
1277
1278
1279
1280
1281
1282
1283
  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...
1284
  		size_t report_size = hid_report_len(report);
01c846f95   Benjamin Tissoires   Input: wacom - co...
1285
1286
1287
1288
1289
1290
  		if (report_size > size)
  			size = report_size;
  	}
  
  	return size;
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
1291
1292
  static int wacom_probe(struct hid_device *hdev,
  		const struct hid_device_id *id)
3bea733ab   Ping Cheng   USB: wacom tablet...
1293
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
1294
  	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
3bea733ab   Ping Cheng   USB: wacom tablet...
1295
  	struct usb_device *dev = interface_to_usbdev(intf);
3bea733ab   Ping Cheng   USB: wacom tablet...
1296
1297
  	struct wacom *wacom;
  	struct wacom_wac *wacom_wac;
e33da8a54   Jason Childs   Input: wacom - us...
1298
  	struct wacom_features *features;
e33da8a54   Jason Childs   Input: wacom - us...
1299
  	int error;
7704ac937   Benjamin Tissoires   HID: wacom: imple...
1300
  	unsigned int connect_mask = HID_CONNECT_HIDRAW;
3bea733ab   Ping Cheng   USB: wacom tablet...
1301

29b473913   Benjamin Tissoires   Input: wacom - sw...
1302
  	if (!id->driver_data)
b036f6fb3   Bastian Blank   Input: wacom - ge...
1303
  		return -EINVAL;
8ffffd521   Benjamin Tissoires   HID: wacom: fix t...
1304
  	hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
3bea733ab   Ping Cheng   USB: wacom tablet...
1305
  	wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
f18239403   Dan Carpenter   Input: wacom - ch...
1306
1307
  	if (!wacom)
  		return -ENOMEM;
e33da8a54   Jason Childs   Input: wacom - us...
1308

29b473913   Benjamin Tissoires   Input: wacom - sw...
1309
1310
  	hid_set_drvdata(hdev, wacom);
  	wacom->hdev = hdev;
ba9a3541f   Benjamin Tissoires   Input: wacom - us...
1311
1312
1313
1314
1315
  	/* ask for the report descriptor to be loaded by HID */
  	error = hid_parse(hdev);
  	if (error) {
  		hid_err(hdev, "parse failed
  ");
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1316
  		goto fail_parse;
ba9a3541f   Benjamin Tissoires   Input: wacom - us...
1317
  	}
51269fe86   Dmitry Torokhov   Input: wacom - do...
1318
  	wacom_wac = &wacom->wacom_wac;
29b473913   Benjamin Tissoires   Input: wacom - sw...
1319
  	wacom_wac->features = *((struct wacom_features *)id->driver_data);
e33da8a54   Jason Childs   Input: wacom - us...
1320
  	features = &wacom_wac->features;
01c846f95   Benjamin Tissoires   Input: wacom - co...
1321
  	features->pktlen = wacom_compute_pktlen(hdev);
e33da8a54   Jason Childs   Input: wacom - us...
1322
1323
  	if (features->pktlen > WACOM_PKGLEN_MAX) {
  		error = -EINVAL;
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1324
  		goto fail_pktlen;
e33da8a54   Jason Childs   Input: wacom - us...
1325
  	}
3bea733ab   Ping Cheng   USB: wacom tablet...
1326

29b473913   Benjamin Tissoires   Input: wacom - sw...
1327
1328
  	if (features->check_for_hid_type && features->hid_type != hdev->type) {
  		error = -ENODEV;
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1329
  		goto fail_type;
e33da8a54   Jason Childs   Input: wacom - us...
1330
  	}
3bea733ab   Ping Cheng   USB: wacom tablet...
1331

3bea733ab   Ping Cheng   USB: wacom tablet...
1332
  	wacom->usbdev = dev;
e72240944   Oliver Neukum   Input: wacom - im...
1333
1334
  	wacom->intf = intf;
  	mutex_init(&wacom->lock);
16bf288c4   Chris Bagwell   Input: wacom - cr...
1335
  	INIT_WORK(&wacom->work, wacom_wireless_work);
3bea733ab   Ping Cheng   USB: wacom tablet...
1336

494078b0b   Benjamin Tissoires   HID: wacom: move ...
1337
1338
1339
1340
1341
  	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
  		error = wacom_allocate_inputs(wacom);
  		if (error)
  			goto fail_allocate_inputs;
  	}
401d7d108   Ping Cheng   Input: wacom - in...
1342
1343
  	/* set the default size in case we do not get them from hid */
  	wacom_set_default_phy(features);
f393ee2b8   Ping Cheng   Input: wacom - re...
1344
  	/* Retrieve the physical and logical size for touch devices */
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
1345
  	wacom_retrieve_hid_descriptor(hdev, features);
545f4e99d   Ping Cheng   Input: wacom - ad...
1346

ae584ca47   Jason Gerecke   Input: wacom - ad...
1347
1348
  	/*
  	 * Intuos5 has no useful data about its touch interface in its
01c846f95   Benjamin Tissoires   Input: wacom - co...
1349
  	 * HID descriptor. If this is the touch interface (PacketSize
ae584ca47   Jason Gerecke   Input: wacom - ad...
1350
1351
  	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.
  	 */
b5fd2a3e9   Ping Cheng   Input: wacom - ad...
1352
  	if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
01c846f95   Benjamin Tissoires   Input: wacom - co...
1353
  		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
ae584ca47   Jason Gerecke   Input: wacom - ad...
1354
  			features->device_type = BTN_TOOL_FINGER;
ae584ca47   Jason Gerecke   Input: wacom - ad...
1355

ae584ca47   Jason Gerecke   Input: wacom - ad...
1356
1357
1358
1359
1360
1361
  			features->x_max = 4096;
  			features->y_max = 4096;
  		} else {
  			features->device_type = BTN_TOOL_PEN;
  		}
  	}
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
  	/*
  	 * Same thing for Bamboo 3rd gen.
  	 */
  	if ((features->type == BAMBOO_PT) &&
  	    (features->pktlen == WACOM_PKGLEN_BBTOUCH3) &&
  	    (features->device_type == BTN_TOOL_PEN)) {
  		features->device_type = BTN_TOOL_FINGER;
  
  		features->x_max = 4096;
  		features->y_max = 4096;
  	}
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1373
1374
  	if (hdev->bus == BUS_BLUETOOTH)
  		features->quirks |= WACOM_QUIRK_BATTERY;
bc73dd39e   Henrik Rydberg   Input: wacom - co...
1375
  	wacom_setup_device_quirks(features);
401d7d108   Ping Cheng   Input: wacom - in...
1376
1377
1378
  	/* set unit to "100th of a mm" for devices not reported by HID */
  	if (!features->unit) {
  		features->unit = 0x11;
c669fb2b9   Benjamin Tissoires   Input: wacom - us...
1379
  		features->unitExpo = -3;
401d7d108   Ping Cheng   Input: wacom - in...
1380
1381
  	}
  	wacom_calculate_res(features);
49b764aeb   Ping Cheng   Input: wacom - ad...
1382
  	strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
d2d13f18a   Benjamin Tissoires   Input: wacom - cr...
1383
1384
  	snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
  		"%s Pad", features->name);
49b764aeb   Ping Cheng   Input: wacom - ad...
1385

bc73dd39e   Henrik Rydberg   Input: wacom - co...
1386
  	if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
49b764aeb   Ping Cheng   Input: wacom - ad...
1387
  		/* Append the device type to the name */
57bcfce37   Ping Cheng   Input: wacom - no...
1388
1389
1390
1391
1392
1393
  		if (features->device_type != BTN_TOOL_FINGER)
  			strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
  		else if (features->touch_max)
  			strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
  		else
  			strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
4492effff   Ping Cheng   Input: wacom - sh...
1394

4451e088c   Benjamin Tissoires   Input: wacom - re...
1395
  		error = wacom_add_shared_data(hdev);
4492effff   Ping Cheng   Input: wacom - sh...
1396
  		if (error)
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1397
  			goto fail_shared_data;
49b764aeb   Ping Cheng   Input: wacom - ad...
1398
  	}
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1399
1400
1401
1402
  	if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
  	     (features->quirks & WACOM_QUIRK_BATTERY)) {
  		error = wacom_initialize_battery(wacom);
  		if (error)
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1403
  			goto fail_battery;
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1404
  	}
d3825d51c   Chris Bagwell   Input: wacom - wi...
1405
  	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
494078b0b   Benjamin Tissoires   HID: wacom: move ...
1406
  		error = wacom_register_inputs(wacom);
d3825d51c   Chris Bagwell   Input: wacom - wi...
1407
  		if (error)
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1408
  			goto fail_register_inputs;
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1409
1410
1411
1412
1413
1414
1415
1416
1417
  	}
  
  	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);
d3825d51c   Chris Bagwell   Input: wacom - wi...
1418
  	}
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1419

7704ac937   Benjamin Tissoires   HID: wacom: imple...
1420
1421
  	if (features->type == HID_GENERIC)
  		connect_mask |= HID_CONNECT_DRIVER;
29b473913   Benjamin Tissoires   Input: wacom - sw...
1422
  	/* Regular HID work starts now */
7704ac937   Benjamin Tissoires   HID: wacom: imple...
1423
  	error = hid_hw_start(hdev, connect_mask);
29b473913   Benjamin Tissoires   Input: wacom - sw...
1424
1425
1426
  	if (error) {
  		hid_err(hdev, "hw start failed
  ");
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1427
  		goto fail_hw_start;
d3825d51c   Chris Bagwell   Input: wacom - wi...
1428
  	}
961794a00   Ping Cheng   Input: wacom - ad...
1429

5ae6e89f7   Benjamin Tissoires   HID: wacom: imple...
1430
1431
  	/* Note that if query fails it is not a hard failure */
  	wacom_query_tablet_data(hdev, features);
29b473913   Benjamin Tissoires   Input: wacom - sw...
1432
1433
  	if (features->quirks & WACOM_QUIRK_MONITOR)
  		error = hid_hw_open(hdev);
961794a00   Ping Cheng   Input: wacom - ad...
1434
1435
1436
1437
  	if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) {
  		if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
  			wacom_wac->shared->touch_input = wacom_wac->input;
  	}
3bea733ab   Ping Cheng   USB: wacom tablet...
1438
  	return 0;
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1439
  fail_hw_start:
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1440
  	if (hdev->bus == BUS_BLUETOOTH)
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1441
  		device_remove_file(&hdev->dev, &dev_attr_speed);
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1442
  fail_register_inputs:
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1443
  	wacom_clean_inputs(wacom);
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1444
1445
1446
1447
  	wacom_destroy_battery(wacom);
  fail_battery:
  	wacom_remove_shared_data(wacom_wac);
  fail_shared_data:
494078b0b   Benjamin Tissoires   HID: wacom: move ...
1448
1449
  	wacom_clean_inputs(wacom);
  fail_allocate_inputs:
7fefeec51   Benjamin Tissoires   HID: wacom: renam...
1450
1451
1452
1453
  fail_type:
  fail_pktlen:
  fail_parse:
  	kfree(wacom);
29b473913   Benjamin Tissoires   Input: wacom - sw...
1454
  	hid_set_drvdata(hdev, NULL);
5014186de   Dmitry Torokhov   Input: USB device...
1455
  	return error;
3bea733ab   Ping Cheng   USB: wacom tablet...
1456
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
1457
  static void wacom_remove(struct hid_device *hdev)
3bea733ab   Ping Cheng   USB: wacom tablet...
1458
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
1459
  	struct wacom *wacom = hid_get_drvdata(hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
1460

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

16bf288c4   Chris Bagwell   Input: wacom - cr...
1463
  	cancel_work_sync(&wacom->work);
2546dacd3   Benjamin Tissoires   HID: wacom: split...
1464
  	wacom_clean_inputs(wacom);
f81a1295c   Benjamin Tissoires   Input: wacom - pr...
1465
1466
  	if (hdev->bus == BUS_BLUETOOTH)
  		device_remove_file(&hdev->dev, &dev_attr_speed);
a1d552cc1   Chris Bagwell   Input: wacom - wi...
1467
  	wacom_destroy_battery(wacom);
51269fe86   Dmitry Torokhov   Input: wacom - do...
1468
  	wacom_remove_shared_data(&wacom->wacom_wac);
e72240944   Oliver Neukum   Input: wacom - im...
1469

29b473913   Benjamin Tissoires   Input: wacom - sw...
1470
1471
  	hid_set_drvdata(hdev, NULL);
  	kfree(wacom);
e72240944   Oliver Neukum   Input: wacom - im...
1472
  }
41a745814   Geert Uytterhoeven   Input: wacom - fi...
1473
  #ifdef CONFIG_PM
29b473913   Benjamin Tissoires   Input: wacom - sw...
1474
  static int wacom_resume(struct hid_device *hdev)
e72240944   Oliver Neukum   Input: wacom - im...
1475
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
1476
  	struct wacom *wacom = hid_get_drvdata(hdev);
51269fe86   Dmitry Torokhov   Input: wacom - do...
1477
  	struct wacom_features *features = &wacom->wacom_wac.features;
e72240944   Oliver Neukum   Input: wacom - im...
1478
1479
  
  	mutex_lock(&wacom->lock);
38101475f   Ping Cheng   Input: wacom - sw...
1480
1481
  
  	/* switch to wacom mode first */
27b20a9de   Benjamin Tissoires   Input: wacom - us...
1482
  	wacom_query_tablet_data(hdev, features);
5d7e7d479   Eduard Hasenleithner   Input: wacom - ad...
1483
  	wacom_led_control(wacom);
38101475f   Ping Cheng   Input: wacom - sw...
1484

e72240944   Oliver Neukum   Input: wacom - im...
1485
  	mutex_unlock(&wacom->lock);
29b473913   Benjamin Tissoires   Input: wacom - sw...
1486
  	return 0;
e72240944   Oliver Neukum   Input: wacom - im...
1487
  }
29b473913   Benjamin Tissoires   Input: wacom - sw...
1488
  static int wacom_reset_resume(struct hid_device *hdev)
e72240944   Oliver Neukum   Input: wacom - im...
1489
  {
29b473913   Benjamin Tissoires   Input: wacom - sw...
1490
  	return wacom_resume(hdev);
3bea733ab   Ping Cheng   USB: wacom tablet...
1491
  }
41a745814   Geert Uytterhoeven   Input: wacom - fi...
1492
  #endif /* CONFIG_PM */
3bea733ab   Ping Cheng   USB: wacom tablet...
1493

29b473913   Benjamin Tissoires   Input: wacom - sw...
1494
  static struct hid_driver wacom_driver = {
3bea733ab   Ping Cheng   USB: wacom tablet...
1495
  	.name =		"wacom",
b036f6fb3   Bastian Blank   Input: wacom - ge...
1496
  	.id_table =	wacom_ids,
3bea733ab   Ping Cheng   USB: wacom tablet...
1497
  	.probe =	wacom_probe,
29b473913   Benjamin Tissoires   Input: wacom - sw...
1498
  	.remove =	wacom_remove,
7704ac937   Benjamin Tissoires   HID: wacom: imple...
1499
1500
  	.event =	wacom_wac_event,
  	.report =	wacom_wac_report,
29b473913   Benjamin Tissoires   Input: wacom - sw...
1501
  #ifdef CONFIG_PM
e72240944   Oliver Neukum   Input: wacom - im...
1502
1503
  	.resume =	wacom_resume,
  	.reset_resume =	wacom_reset_resume,
29b473913   Benjamin Tissoires   Input: wacom - sw...
1504
1505
  #endif
  	.raw_event =	wacom_raw_event,
3bea733ab   Ping Cheng   USB: wacom tablet...
1506
  };
29b473913   Benjamin Tissoires   Input: wacom - sw...
1507
  module_hid_driver(wacom_driver);
f2e0a7d4a   Benjamin Tissoires   Input: wacom - on...
1508
1509
1510
1511
1512
  
  MODULE_VERSION(DRIVER_VERSION);
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
  MODULE_LICENSE(DRIVER_LICENSE);