aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2014-07-24 16:02:14 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-07-25 21:53:55 -0400
commitc669fb2b9ac47682b53f0a97d55c7ae4f2f3eaee (patch)
tree3341cef9d7d2c5dbda688bfae262fa9c94e556c2
parente2114ce1af0dd8c1e077b6d545e346e9ac4d137c (diff)
Input: wacom - use in-kernel HID parser
HID already parses the report descriptor, so use it instead of implementing our own. The special case for Bamboo PT 3rd gen is also removed and handled in the same way Intuos 5 is treated, by hardcoding it in the driver. Last, the unit_exponent stored into the hid field already is signed, so there is no need to handle a two's complement anymore. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Jason Gerecke <killertofu@gmail.com> Tested-by: Jason Gerecke <killertofu@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/tablet/wacom_sys.c348
-rw-r--r--drivers/input/tablet/wacom_wac.h4
2 files changed, 114 insertions, 238 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 2c1d984edc7f..ed27e7da5444 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -15,13 +15,6 @@
15#include "wacom.h" 15#include "wacom.h"
16#include <linux/hid.h> 16#include <linux/hid.h>
17 17
18#define HID_HDESC_USAGE_UNDEFINED 0x00
19#define HID_HDESC_USAGE_PAGE 0x05
20#define HID_HDESC_USAGE 0x09
21#define HID_HDESC_COLLECTION 0xa1
22#define HID_HDESC_COLLECTION_LOGICAL 0x02
23#define HID_HDESC_COLLECTION_END 0xc0
24
25#define WAC_MSG_RETRIES 5 18#define WAC_MSG_RETRIES 5
26 19
27#define WAC_CMD_LED_CONTROL 0x20 20#define WAC_CMD_LED_CONTROL 0x20
@@ -96,19 +89,15 @@ static void wacom_close(struct input_dev *dev)
96 * This function is little more than hidinput_calc_abs_res stripped down. 89 * This function is little more than hidinput_calc_abs_res stripped down.
97 */ 90 */
98static int wacom_calc_hid_res(int logical_extents, int physical_extents, 91static int wacom_calc_hid_res(int logical_extents, int physical_extents,
99 unsigned char unit, unsigned char exponent) 92 unsigned unit, int exponent)
100{ 93{
101 int prev, unit_exponent; 94 int prev;
95 int unit_exponent = exponent;
102 96
103 /* Check if the extents are sane */ 97 /* Check if the extents are sane */
104 if (logical_extents <= 0 || physical_extents <= 0) 98 if (logical_extents <= 0 || physical_extents <= 0)
105 return 0; 99 return 0;
106 100
107 /* Get signed value of nybble-sized twos-compliment exponent */
108 unit_exponent = exponent;
109 if (unit_exponent > 7)
110 unit_exponent -= 16;
111
112 /* Convert physical_extents to millimeters */ 101 /* Convert physical_extents to millimeters */
113 if (unit == 0x11) { /* If centimeters */ 102 if (unit == 0x11) { /* If centimeters */
114 unit_exponent += 1; 103 unit_exponent += 1;
@@ -141,42 +130,18 @@ static int wacom_calc_hid_res(int logical_extents, int physical_extents,
141 return logical_extents / physical_extents; 130 return logical_extents / physical_extents;
142} 131}
143 132
144static int wacom_parse_logical_collection(unsigned char *report, 133static void wacom_feature_mapping(struct hid_device *hdev,
145 struct wacom_features *features) 134 struct hid_field *field, struct hid_usage *usage)
146{
147 int length = 0;
148
149 if (features->type == BAMBOO_PT) {
150
151 /* Logical collection is only used by 3rd gen Bamboo Touch */
152 features->device_type = BTN_TOOL_FINGER;
153
154 features->x_max = features->y_max =
155 get_unaligned_le16(&report[10]);
156
157 length = 11;
158 }
159 return length;
160}
161
162static void wacom_retrieve_report_data(struct hid_device *hdev,
163 struct wacom_features *features)
164{ 135{
165 int result = 0; 136 struct wacom *wacom = hid_get_drvdata(hdev);
166 unsigned char *rep_data; 137 struct wacom_features *features = &wacom->wacom_wac.features;
167
168 rep_data = kmalloc(2, GFP_KERNEL);
169 if (rep_data) {
170
171 rep_data[0] = 12;
172 result = wacom_get_report(hdev, HID_FEATURE_REPORT,
173 rep_data[0], rep_data, 2,
174 WAC_MSG_RETRIES);
175
176 if (result >= 0 && rep_data[1] > 2)
177 features->touch_max = rep_data[1];
178 138
179 kfree(rep_data); 139 switch (usage->hid) {
140 case HID_DG_CONTACTMAX:
141 /* leave touch_max as is if predefined */
142 if (!features->touch_max)
143 features->touch_max = field->value[0];
144 break;
180 } 145 }
181} 146}
182 147
@@ -209,190 +174,96 @@ static void wacom_retrieve_report_data(struct hid_device *hdev,
209 * interfaces haven't supported pressure or distance, this is enough 174 * interfaces haven't supported pressure or distance, this is enough
210 * information to override invalid values in the wacom_features table. 175 * information to override invalid values in the wacom_features table.
211 * 176 *
212 * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical 177 * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
213 * Collection. Instead they define a Logical Collection with a single 178 * data. We deal with them after returning from this function.
214 * Logical Maximum for both X and Y.
215 *
216 * Intuos5 touch interface does not contain useful data. We deal with
217 * this after returning from this function.
218 */ 179 */
219static int wacom_parse_hid(struct hid_device *hdev, 180static void wacom_usage_mapping(struct hid_device *hdev,
220 struct wacom_features *features) 181 struct hid_field *field, struct hid_usage *usage)
221{ 182{
222 /* result has to be defined as int for some devices */ 183 struct wacom *wacom = hid_get_drvdata(hdev);
223 int result = 0, touch_max = 0; 184 struct wacom_features *features = &wacom->wacom_wac.features;
224 int i = 0, page = 0, finger = 0, pen = 0; 185 bool finger = (field->logical == HID_DG_FINGER) ||
225 unsigned char *report = hdev->rdesc; 186 (field->physical == HID_DG_FINGER);
226 187 bool pen = (field->logical == HID_DG_STYLUS) ||
227 for (i = 0; i < hdev->rsize; i++) { 188 (field->physical == HID_DG_STYLUS);
228
229 switch (report[i]) {
230 case HID_HDESC_USAGE_PAGE:
231 page = report[i + 1];
232 i++;
233 break;
234
235 case HID_HDESC_USAGE:
236 switch (page << 16 | report[i + 1]) {
237 case HID_GD_X:
238 if (finger) {
239 features->device_type = BTN_TOOL_FINGER;
240 /* touch device at least supports one touch point */
241 touch_max = 1;
242
243 switch (features->type) {
244 case BAMBOO_PT:
245 features->x_phy =
246 get_unaligned_le16(&report[i + 5]);
247 features->x_max =
248 get_unaligned_le16(&report[i + 8]);
249 i += 15;
250 break;
251
252 case WACOM_24HDT:
253 features->x_max =
254 get_unaligned_le16(&report[i + 3]);
255 features->x_phy =
256 get_unaligned_le16(&report[i + 8]);
257 features->unit = report[i - 1];
258 features->unitExpo = report[i - 3];
259 i += 12;
260 break;
261
262 case MTTPC_B:
263 features->x_max =
264 get_unaligned_le16(&report[i + 3]);
265 features->x_phy =
266 get_unaligned_le16(&report[i + 6]);
267 features->unit = report[i - 5];
268 features->unitExpo = report[i - 3];
269 i += 9;
270 break;
271
272 default:
273 features->x_max =
274 get_unaligned_le16(&report[i + 3]);
275 features->x_phy =
276 get_unaligned_le16(&report[i + 6]);
277 features->unit = report[i + 9];
278 features->unitExpo = report[i + 11];
279 i += 12;
280 break;
281 }
282 } else if (pen) {
283 /* penabled only accepts exact bytes of data */
284 features->device_type = BTN_TOOL_PEN;
285 features->x_max =
286 get_unaligned_le16(&report[i + 3]);
287 i += 4;
288 }
289 break;
290
291 case HID_GD_Y:
292 if (finger) {
293 switch (features->type) {
294 case TABLETPC2FG:
295 case MTSCREEN:
296 case MTTPC:
297 features->y_max =
298 get_unaligned_le16(&report[i + 3]);
299 features->y_phy =
300 get_unaligned_le16(&report[i + 6]);
301 i += 7;
302 break;
303
304 case WACOM_24HDT:
305 features->y_max =
306 get_unaligned_le16(&report[i + 3]);
307 features->y_phy =
308 get_unaligned_le16(&report[i - 2]);
309 i += 7;
310 break;
311
312 case BAMBOO_PT:
313 features->y_phy =
314 get_unaligned_le16(&report[i + 3]);
315 features->y_max =
316 get_unaligned_le16(&report[i + 6]);
317 i += 12;
318 break;
319
320 case MTTPC_B:
321 features->y_max =
322 get_unaligned_le16(&report[i + 3]);
323 features->y_phy =
324 get_unaligned_le16(&report[i + 6]);
325 i += 9;
326 break;
327
328 default:
329 features->y_max =
330 features->x_max;
331 features->y_phy =
332 get_unaligned_le16(&report[i + 3]);
333 i += 4;
334 break;
335 }
336 } else if (pen) {
337 features->y_max =
338 get_unaligned_le16(&report[i + 3]);
339 i += 4;
340 }
341 break;
342
343 case HID_DG_FINGER:
344 finger = 1;
345 i++;
346 break;
347
348 /*
349 * Requiring Stylus Usage will ignore boot mouse
350 * X/Y values and some cases of invalid Digitizer X/Y
351 * values commonly reported.
352 */
353 case HID_DG_STYLUS:
354 pen = 1;
355 i++;
356 break;
357
358 case HID_DG_CONTACTMAX:
359 /* leave touch_max as is if predefined */
360 if (!features->touch_max)
361 wacom_retrieve_report_data(hdev, features);
362 i++;
363 break;
364 189
365 case HID_DG_TIPPRESSURE: 190 /*
366 if (pen) { 191 * Requiring Stylus Usage will ignore boot mouse
367 features->pressure_max = 192 * X/Y values and some cases of invalid Digitizer X/Y
368 get_unaligned_le16(&report[i + 3]); 193 * values commonly reported.
369 i += 4; 194 */
370 } 195 if (!pen && !finger)
371 break; 196 return;
197
198 if (finger && !features->touch_max)
199 /* touch device at least supports one touch point */
200 features->touch_max = 1;
201
202 switch (usage->hid) {
203 case HID_GD_X:
204 features->x_max = field->logical_maximum;
205 if (finger) {
206 features->device_type = BTN_TOOL_FINGER;
207 features->x_phy = field->physical_maximum;
208 if (features->type != BAMBOO_PT) {
209 features->unit = field->unit;
210 features->unitExpo = field->unit_exponent;
372 } 211 }
373 break; 212 } else {
374 213 features->device_type = BTN_TOOL_PEN;
375 case HID_HDESC_COLLECTION_END: 214 }
376 /* reset UsagePage and Finger */ 215 break;
377 finger = page = 0; 216 case HID_GD_Y:
378 break; 217 features->y_max = field->logical_maximum;
218 if (finger) {
219 features->y_phy = field->physical_maximum;
220 if (features->type != BAMBOO_PT) {
221 features->unit = field->unit;
222 features->unitExpo = field->unit_exponent;
223 }
224 }
225 break;
226 case HID_DG_TIPPRESSURE:
227 if (pen)
228 features->pressure_max = field->logical_maximum;
229 break;
230 }
231}
379 232
380 case HID_HDESC_COLLECTION: 233static void wacom_parse_hid(struct hid_device *hdev,
381 i++; 234 struct wacom_features *features)
382 switch (report[i]) { 235{
383 case HID_HDESC_COLLECTION_LOGICAL: 236 struct hid_report_enum *rep_enum;
384 i += wacom_parse_logical_collection(&report[i], 237 struct hid_report *hreport;
385 features); 238 int i, j;
386 break; 239
240 /* check features first */
241 rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
242 list_for_each_entry(hreport, &rep_enum->report_list, list) {
243 for (i = 0; i < hreport->maxfield; i++) {
244 /* Ignore if report count is out of bounds. */
245 if (hreport->field[i]->report_count < 1)
246 continue;
247
248 for (j = 0; j < hreport->field[i]->maxusage; j++) {
249 wacom_feature_mapping(hdev, hreport->field[i],
250 hreport->field[i]->usage + j);
387 } 251 }
388 break;
389 } 252 }
390 } 253 }
391 254
392 if (!features->touch_max && touch_max) 255 /* now check the input usages */
393 features->touch_max = touch_max; 256 rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
394 result = 0; 257 list_for_each_entry(hreport, &rep_enum->report_list, list) {
395 return result; 258
259 if (!hreport->maxfield)
260 continue;
261
262 for (i = 0; i < hreport->maxfield; i++)
263 for (j = 0; j < hreport->field[i]->maxusage; j++)
264 wacom_usage_mapping(hdev, hreport->field[i],
265 hreport->field[i]->usage + j);
266 }
396} 267}
397 268
398static int wacom_set_device_mode(struct hid_device *hdev, int report_id, 269static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
@@ -448,10 +319,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
448 return 0; 319 return 0;
449} 320}
450 321
451static int wacom_retrieve_hid_descriptor(struct hid_device *hdev, 322static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
452 struct wacom_features *features) 323 struct wacom_features *features)
453{ 324{
454 int error = 0;
455 struct wacom *wacom = hid_get_drvdata(hdev); 325 struct wacom *wacom = hid_get_drvdata(hdev);
456 struct usb_interface *intf = wacom->intf; 326 struct usb_interface *intf = wacom->intf;
457 327
@@ -478,14 +348,10 @@ static int wacom_retrieve_hid_descriptor(struct hid_device *hdev,
478 } 348 }
479 349
480 /* only devices that support touch need to retrieve the info */ 350 /* only devices that support touch need to retrieve the info */
481 if (features->type < BAMBOO_PT) { 351 if (features->type < BAMBOO_PT)
482 goto out; 352 return;
483 }
484 353
485 error = wacom_parse_hid(hdev, features); 354 wacom_parse_hid(hdev, features);
486
487 out:
488 return error;
489} 355}
490 356
491struct wacom_hdev_data { 357struct wacom_hdev_data {
@@ -1275,9 +1141,7 @@ static int wacom_probe(struct hid_device *hdev,
1275 wacom_set_default_phy(features); 1141 wacom_set_default_phy(features);
1276 1142
1277 /* Retrieve the physical and logical size for touch devices */ 1143 /* Retrieve the physical and logical size for touch devices */
1278 error = wacom_retrieve_hid_descriptor(hdev, features); 1144 wacom_retrieve_hid_descriptor(hdev, features);
1279 if (error)
1280 goto fail1;
1281 1145
1282 /* 1146 /*
1283 * Intuos5 has no useful data about its touch interface in its 1147 * Intuos5 has no useful data about its touch interface in its
@@ -1295,12 +1159,24 @@ static int wacom_probe(struct hid_device *hdev,
1295 } 1159 }
1296 } 1160 }
1297 1161
1162 /*
1163 * Same thing for Bamboo 3rd gen.
1164 */
1165 if ((features->type == BAMBOO_PT) &&
1166 (features->pktlen == WACOM_PKGLEN_BBTOUCH3) &&
1167 (features->device_type == BTN_TOOL_PEN)) {
1168 features->device_type = BTN_TOOL_FINGER;
1169
1170 features->x_max = 4096;
1171 features->y_max = 4096;
1172 }
1173
1298 wacom_setup_device_quirks(features); 1174 wacom_setup_device_quirks(features);
1299 1175
1300 /* set unit to "100th of a mm" for devices not reported by HID */ 1176 /* set unit to "100th of a mm" for devices not reported by HID */
1301 if (!features->unit) { 1177 if (!features->unit) {
1302 features->unit = 0x11; 1178 features->unit = 0x11;
1303 features->unitExpo = 16 - 3; 1179 features->unitExpo = -3;
1304 } 1180 }
1305 wacom_calculate_res(features); 1181 wacom_calculate_res(features);
1306 1182
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 8821a518abf6..2a7612ae14a6 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -127,8 +127,8 @@ struct wacom_features {
127 int device_type; 127 int device_type;
128 int x_phy; 128 int x_phy;
129 int y_phy; 129 int y_phy;
130 unsigned char unit; 130 unsigned unit;
131 unsigned char unitExpo; 131 int unitExpo;
132 int x_fuzz; 132 int x_fuzz;
133 int y_fuzz; 133 int y_fuzz;
134 int pressure_fuzz; 134 int pressure_fuzz;