diff options
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 145 |
1 files changed, 106 insertions, 39 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 0d3219f29744..9edf9806cff9 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -172,6 +172,76 @@ static void wacom_close(struct input_dev *dev) | |||
172 | } | 172 | } |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * Calculate the resolution of the X or Y axis, given appropriate HID data. | ||
176 | * This function is little more than hidinput_calc_abs_res stripped down. | ||
177 | */ | ||
178 | static int wacom_calc_hid_res(int logical_extents, int physical_extents, | ||
179 | unsigned char unit, unsigned char exponent) | ||
180 | { | ||
181 | int prev, unit_exponent; | ||
182 | |||
183 | /* Check if the extents are sane */ | ||
184 | if (logical_extents <= 0 || physical_extents <= 0) | ||
185 | return 0; | ||
186 | |||
187 | /* Get signed value of nybble-sized twos-compliment exponent */ | ||
188 | unit_exponent = exponent; | ||
189 | if (unit_exponent > 7) | ||
190 | unit_exponent -= 16; | ||
191 | |||
192 | /* Convert physical_extents to millimeters */ | ||
193 | if (unit == 0x11) { /* If centimeters */ | ||
194 | unit_exponent += 1; | ||
195 | } else if (unit == 0x13) { /* If inches */ | ||
196 | prev = physical_extents; | ||
197 | physical_extents *= 254; | ||
198 | if (physical_extents < prev) | ||
199 | return 0; | ||
200 | unit_exponent -= 1; | ||
201 | } else { | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /* Apply negative unit exponent */ | ||
206 | for (; unit_exponent < 0; unit_exponent++) { | ||
207 | prev = logical_extents; | ||
208 | logical_extents *= 10; | ||
209 | if (logical_extents < prev) | ||
210 | return 0; | ||
211 | } | ||
212 | /* Apply positive unit exponent */ | ||
213 | for (; unit_exponent > 0; unit_exponent--) { | ||
214 | prev = physical_extents; | ||
215 | physical_extents *= 10; | ||
216 | if (physical_extents < prev) | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | /* Calculate resolution */ | ||
221 | return logical_extents / physical_extents; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * The physical dimension specified by the HID descriptor is likely not in | ||
226 | * the "100th of a mm" units expected by wacom_calculate_touch_res. This | ||
227 | * function adjusts the value of [xy]_phy based on the unit and exponent | ||
228 | * provided by the HID descriptor. If an error occurs durring conversion | ||
229 | * (e.g. from the unit being left unspecified) [xy]_phy is not modified. | ||
230 | */ | ||
231 | static void wacom_fix_phy_from_hid(struct wacom_features *features) | ||
232 | { | ||
233 | int xres = wacom_calc_hid_res(features->x_max, features->x_phy, | ||
234 | features->unit, features->unitExpo); | ||
235 | int yres = wacom_calc_hid_res(features->y_max, features->y_phy, | ||
236 | features->unit, features->unitExpo); | ||
237 | |||
238 | if (xres > 0 && yres > 0) { | ||
239 | features->x_phy = (100 * features->x_max) / xres; | ||
240 | features->y_phy = (100 * features->y_max) / yres; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* | ||
175 | * Static values for max X/Y and resolution of Pen interface is stored in | 245 | * Static values for max X/Y and resolution of Pen interface is stored in |
176 | * features. This mean physical size of active area can be computed. | 246 | * features. This mean physical size of active area can be computed. |
177 | * This is useful to do when Pen and Touch have same active area of tablet. | 247 | * This is useful to do when Pen and Touch have same active area of tablet. |
@@ -432,56 +502,52 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
432 | return result; | 502 | return result; |
433 | } | 503 | } |
434 | 504 | ||
435 | static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) | 505 | static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode) |
436 | { | 506 | { |
437 | unsigned char *rep_data; | 507 | unsigned char *rep_data; |
438 | int limit = 0, report_id = 2; | 508 | int error = -ENOMEM, limit = 0; |
439 | int error = -ENOMEM; | ||
440 | 509 | ||
441 | rep_data = kmalloc(4, GFP_KERNEL); | 510 | rep_data = kzalloc(length, GFP_KERNEL); |
442 | if (!rep_data) | 511 | if (!rep_data) |
443 | return error; | 512 | return error; |
444 | 513 | ||
445 | /* ask to report Wacom data */ | 514 | rep_data[0] = report_id; |
515 | rep_data[1] = mode; | ||
516 | |||
517 | do { | ||
518 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, | ||
519 | report_id, rep_data, length, 1); | ||
520 | if (error >= 0) | ||
521 | error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, | ||
522 | report_id, rep_data, length, 1); | ||
523 | } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); | ||
524 | |||
525 | kfree(rep_data); | ||
526 | |||
527 | return error < 0 ? error : 0; | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * Switch the tablet into its most-capable mode. Wacom tablets are | ||
532 | * typically configured to power-up in a mode which sends mouse-like | ||
533 | * reports to the OS. To get absolute position, pressure data, etc. | ||
534 | * from the tablet, it is necessary to switch the tablet out of this | ||
535 | * mode and into one which sends the full range of tablet data. | ||
536 | */ | ||
537 | static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) | ||
538 | { | ||
446 | if (features->device_type == BTN_TOOL_FINGER) { | 539 | if (features->device_type == BTN_TOOL_FINGER) { |
447 | /* if it is an MT Tablet PC touch */ | ||
448 | if (features->type > TABLETPC) { | 540 | if (features->type > TABLETPC) { |
449 | do { | 541 | /* MT Tablet PC touch */ |
450 | rep_data[0] = 3; | 542 | return wacom_set_device_mode(intf, 3, 4, 4); |
451 | rep_data[1] = 4; | 543 | } |
452 | rep_data[2] = 0; | 544 | } else if (features->device_type == BTN_TOOL_PEN) { |
453 | rep_data[3] = 0; | 545 | if (features->type <= BAMBOO_PT && features->type != WIRELESS) { |
454 | report_id = 3; | 546 | return wacom_set_device_mode(intf, 2, 2, 2); |
455 | error = wacom_set_report(intf, | ||
456 | WAC_HID_FEATURE_REPORT, | ||
457 | report_id, | ||
458 | rep_data, 4, 1); | ||
459 | if (error >= 0) | ||
460 | error = wacom_get_report(intf, | ||
461 | WAC_HID_FEATURE_REPORT, | ||
462 | report_id, | ||
463 | rep_data, 4, 1); | ||
464 | } while ((error < 0 || rep_data[1] != 4) && | ||
465 | limit++ < WAC_MSG_RETRIES); | ||
466 | } | 547 | } |
467 | } else if (features->type <= BAMBOO_PT && | ||
468 | features->type != WIRELESS && | ||
469 | features->device_type == BTN_TOOL_PEN) { | ||
470 | do { | ||
471 | rep_data[0] = 2; | ||
472 | rep_data[1] = 2; | ||
473 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, | ||
474 | report_id, rep_data, 2, 1); | ||
475 | if (error >= 0) | ||
476 | error = wacom_get_report(intf, | ||
477 | WAC_HID_FEATURE_REPORT, | ||
478 | report_id, rep_data, 2, 1); | ||
479 | } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); | ||
480 | } | 548 | } |
481 | 549 | ||
482 | kfree(rep_data); | 550 | return 0; |
483 | |||
484 | return error < 0 ? error : 0; | ||
485 | } | 551 | } |
486 | 552 | ||
487 | static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | 553 | static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, |
@@ -531,6 +597,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | |||
531 | error = wacom_parse_hid(intf, hid_desc, features); | 597 | error = wacom_parse_hid(intf, hid_desc, features); |
532 | if (error) | 598 | if (error) |
533 | goto out; | 599 | goto out; |
600 | wacom_fix_phy_from_hid(features); | ||
534 | 601 | ||
535 | out: | 602 | out: |
536 | return error; | 603 | return error; |