aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/tablet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/tablet')
-rw-r--r--drivers/input/tablet/wacom_sys.c145
-rw-r--r--drivers/input/tablet/wacom_wac.c36
2 files changed, 133 insertions, 48 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 */
178static 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 */
231static 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
435static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) 505static 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 */
537static 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
487static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, 553static 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;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 93171098abbd..c3468c8dbd89 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -25,6 +25,11 @@
25#define WACOM_INTUOS_RES 100 25#define WACOM_INTUOS_RES 100
26#define WACOM_INTUOS3_RES 200 26#define WACOM_INTUOS3_RES 200
27 27
28/* Scale factor relating reported contact size to logical contact area.
29 * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
30 */
31#define WACOM_CONTACT_AREA_SCALE 2607
32
28static int wacom_penpartner_irq(struct wacom_wac *wacom) 33static int wacom_penpartner_irq(struct wacom_wac *wacom)
29{ 34{
30 unsigned char *data = wacom->data; 35 unsigned char *data = wacom->data;
@@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
326 331
327 /* Enter report */ 332 /* Enter report */
328 if ((data[1] & 0xfc) == 0xc0) { 333 if ((data[1] & 0xfc) == 0xc0) {
329 if (features->type >= INTUOS5S && features->type <= INTUOS5L) 334 if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
330 wacom->shared->stylus_in_proximity = true; 335 wacom->shared->stylus_in_proximity = true;
331 336
332 /* serial number of the tool */ 337 /* serial number of the tool */
@@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
414 419
415 /* Exit report */ 420 /* Exit report */
416 if ((data[1] & 0xfe) == 0x80) { 421 if ((data[1] & 0xfe) == 0x80) {
417 if (features->type >= INTUOS5S && features->type <= INTUOS5L) 422 if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
418 wacom->shared->stylus_in_proximity = false; 423 wacom->shared->stylus_in_proximity = false;
419 424
420 /* 425 /*
@@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
1043 if (touch) { 1048 if (touch) {
1044 int x = (data[2] << 4) | (data[4] >> 4); 1049 int x = (data[2] << 4) | (data[4] >> 4);
1045 int y = (data[3] << 4) | (data[4] & 0x0f); 1050 int y = (data[3] << 4) | (data[4] & 0x0f);
1046 int w = data[6]; 1051 int a = data[5];
1052
1053 // "a" is a scaled-down area which we assume is roughly
1054 // circular and which can be described as: a=(pi*r^2)/C.
1055 int x_res = input_abs_get_res(input, ABS_X);
1056 int y_res = input_abs_get_res(input, ABS_Y);
1057 int width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
1058 int height = width * y_res / x_res;
1047 1059
1048 input_report_abs(input, ABS_MT_POSITION_X, x); 1060 input_report_abs(input, ABS_MT_POSITION_X, x);
1049 input_report_abs(input, ABS_MT_POSITION_Y, y); 1061 input_report_abs(input, ABS_MT_POSITION_Y, y);
1050 input_report_abs(input, ABS_MT_TOUCH_MAJOR, w); 1062 input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
1063 input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
1051 } 1064 }
1052} 1065}
1053 1066
@@ -1530,10 +1543,12 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
1530 __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); 1543 __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
1531 __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); 1544 __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
1532 1545
1533 input_mt_init_slots(input_dev, features->touch_max); 1546 input_mt_init_slots(input_dev, features->touch_max, 0);
1534 1547
1535 input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 1548 input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
1536 0, 255, 0, 0); 1549 0, features->x_max, 0, 0);
1550 input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
1551 0, features->y_max, 0, 0);
1537 1552
1538 input_set_abs_params(input_dev, ABS_MT_POSITION_X, 1553 input_set_abs_params(input_dev, ABS_MT_POSITION_X,
1539 0, features->x_max, 1554 0, features->x_max,
@@ -1575,7 +1590,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
1575 1590
1576 case TABLETPC2FG: 1591 case TABLETPC2FG:
1577 if (features->device_type == BTN_TOOL_FINGER) { 1592 if (features->device_type == BTN_TOOL_FINGER) {
1578 input_mt_init_slots(input_dev, features->touch_max); 1593 input_mt_init_slots(input_dev, features->touch_max, 0);
1579 input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 1594 input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
1580 0, MT_TOOL_MAX, 0, 0); 1595 0, MT_TOOL_MAX, 0, 0);
1581 input_set_abs_params(input_dev, ABS_MT_POSITION_X, 1596 input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1631,7 +1646,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
1631 1646
1632 __set_bit(BTN_TOOL_FINGER, input_dev->keybit); 1647 __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
1633 __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); 1648 __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
1634 input_mt_init_slots(input_dev, features->touch_max); 1649 input_mt_init_slots(input_dev, features->touch_max, 0);
1635 1650
1636 if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { 1651 if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
1637 __set_bit(BTN_TOOL_TRIPLETAP, 1652 __set_bit(BTN_TOOL_TRIPLETAP,
@@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
1641 1656
1642 input_set_abs_params(input_dev, 1657 input_set_abs_params(input_dev,
1643 ABS_MT_TOUCH_MAJOR, 1658 ABS_MT_TOUCH_MAJOR,
1644 0, 255, 0, 0); 1659 0, features->x_max, 0, 0);
1660 input_set_abs_params(input_dev,
1661 ABS_MT_TOUCH_MINOR,
1662 0, features->y_max, 0, 0);
1645 } 1663 }
1646 1664
1647 input_set_abs_params(input_dev, ABS_MT_POSITION_X, 1665 input_set_abs_params(input_dev, ABS_MT_POSITION_X,