aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/tablet/wacom_sys.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-12 21:56:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-12 21:56:03 -0400
commit8bbbfa70549bd84f29ff331d0ac051897ccbbd72 (patch)
tree306640629d368960428326201098a881d7fd724f /drivers/input/tablet/wacom_sys.c
parentbd81ccea8558daab570d70d2c23746413f26cecf (diff)
parent0cc8d6a9d23d6662da91eeb6bb8e7d1c559850f0 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input layer updates from Dmitry Torokhov: "2nd round of updates for the input subsystem. With it input core no longer limits number of character devices per event handler (such as evdev) to 32, but switches to dynamic minors once legacy range is exhausted. This should get multi-seat installations that currently run our of event devices very quickly. You will also get an update for Wacom driver and a couple of driver fixes." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: extend the number of event (and other) devices Input: mousedev - mark mousedev interfaces as non-seekable Input: mousedev - rename mixdev_open to opened_by_mixdev Input: mousedev - reformat structure initializers Input: mousedev - factor out psaux code to reduce #ifdefery Input: samsung-keypad - add clk_prepare and clk_unprepare Input: atmel_mxt_ts - simplify mxt_dump_message Input: wacom - clean up wacom_query_tablet_data Input: wacom - introduce wacom_fix_phy_from_hid Input: wacom - allow any multi-input Intuos device to set prox Input: wacom - report correct touch contact size for I5/Bamboo
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
-rw-r--r--drivers/input/tablet/wacom_sys.c145
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 */
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;