diff options
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 244 |
1 files changed, 180 insertions, 64 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 79a0509882d4..cad5602d3ce4 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #define HID_USAGE_Y_TILT 0x3e | 28 | #define HID_USAGE_Y_TILT 0x3e |
29 | #define HID_USAGE_FINGER 0x22 | 29 | #define HID_USAGE_FINGER 0x22 |
30 | #define HID_USAGE_STYLUS 0x20 | 30 | #define HID_USAGE_STYLUS 0x20 |
31 | #define HID_USAGE_CONTACTMAX 0x55 | ||
31 | #define HID_COLLECTION 0xa1 | 32 | #define HID_COLLECTION 0xa1 |
32 | #define HID_COLLECTION_LOGICAL 0x02 | 33 | #define HID_COLLECTION_LOGICAL 0x02 |
33 | #define HID_COLLECTION_END 0xc0 | 34 | #define HID_COLLECTION_END 0xc0 |
@@ -204,6 +205,27 @@ static int wacom_parse_logical_collection(unsigned char *report, | |||
204 | return length; | 205 | return length; |
205 | } | 206 | } |
206 | 207 | ||
208 | static void wacom_retrieve_report_data(struct usb_interface *intf, | ||
209 | struct wacom_features *features) | ||
210 | { | ||
211 | int result = 0; | ||
212 | unsigned char *rep_data; | ||
213 | |||
214 | rep_data = kmalloc(2, GFP_KERNEL); | ||
215 | if (rep_data) { | ||
216 | |||
217 | rep_data[0] = 12; | ||
218 | result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, | ||
219 | rep_data[0], &rep_data, 2, | ||
220 | WAC_MSG_RETRIES); | ||
221 | |||
222 | if (result >= 0 && rep_data[1] > 2) | ||
223 | features->touch_max = rep_data[1]; | ||
224 | |||
225 | kfree(rep_data); | ||
226 | } | ||
227 | } | ||
228 | |||
207 | /* | 229 | /* |
208 | * Interface Descriptor of wacom devices can be incomplete and | 230 | * Interface Descriptor of wacom devices can be incomplete and |
209 | * inconsistent so wacom_features table is used to store stylus | 231 | * inconsistent so wacom_features table is used to store stylus |
@@ -236,6 +258,9 @@ static int wacom_parse_logical_collection(unsigned char *report, | |||
236 | * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical | 258 | * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical |
237 | * Collection. Instead they define a Logical Collection with a single | 259 | * Collection. Instead they define a Logical Collection with a single |
238 | * Logical Maximum for both X and Y. | 260 | * Logical Maximum for both X and Y. |
261 | * | ||
262 | * Intuos5 touch interface does not contain useful data. We deal with | ||
263 | * this after returning from this function. | ||
239 | */ | 264 | */ |
240 | static int wacom_parse_hid(struct usb_interface *intf, | 265 | static int wacom_parse_hid(struct usb_interface *intf, |
241 | struct hid_descriptor *hid_desc, | 266 | struct hid_descriptor *hid_desc, |
@@ -295,6 +320,10 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
295 | /* need to reset back */ | 320 | /* need to reset back */ |
296 | features->pktlen = WACOM_PKGLEN_TPC2FG; | 321 | features->pktlen = WACOM_PKGLEN_TPC2FG; |
297 | } | 322 | } |
323 | |||
324 | if (features->type == MTSCREEN) | ||
325 | features->pktlen = WACOM_PKGLEN_MTOUCH; | ||
326 | |||
298 | if (features->type == BAMBOO_PT) { | 327 | if (features->type == BAMBOO_PT) { |
299 | /* need to reset back */ | 328 | /* need to reset back */ |
300 | features->pktlen = WACOM_PKGLEN_BBTOUCH; | 329 | features->pktlen = WACOM_PKGLEN_BBTOUCH; |
@@ -327,18 +356,15 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
327 | case HID_USAGE_Y: | 356 | case HID_USAGE_Y: |
328 | if (usage == WCM_DESKTOP) { | 357 | if (usage == WCM_DESKTOP) { |
329 | if (finger) { | 358 | if (finger) { |
330 | features->device_type = BTN_TOOL_FINGER; | 359 | int type = features->type; |
331 | if (features->type == TABLETPC2FG) { | 360 | |
332 | /* need to reset back */ | 361 | if (type == TABLETPC2FG || type == MTSCREEN) { |
333 | features->pktlen = WACOM_PKGLEN_TPC2FG; | ||
334 | features->y_max = | 362 | features->y_max = |
335 | get_unaligned_le16(&report[i + 3]); | 363 | get_unaligned_le16(&report[i + 3]); |
336 | features->y_phy = | 364 | features->y_phy = |
337 | get_unaligned_le16(&report[i + 6]); | 365 | get_unaligned_le16(&report[i + 6]); |
338 | i += 7; | 366 | i += 7; |
339 | } else if (features->type == BAMBOO_PT) { | 367 | } else if (type == BAMBOO_PT) { |
340 | /* need to reset back */ | ||
341 | features->pktlen = WACOM_PKGLEN_BBTOUCH; | ||
342 | features->y_phy = | 368 | features->y_phy = |
343 | get_unaligned_le16(&report[i + 3]); | 369 | get_unaligned_le16(&report[i + 3]); |
344 | features->y_max = | 370 | features->y_max = |
@@ -352,10 +378,6 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
352 | i += 4; | 378 | i += 4; |
353 | } | 379 | } |
354 | } else if (pen) { | 380 | } else if (pen) { |
355 | /* penabled only accepts exact bytes of data */ | ||
356 | if (features->type == TABLETPC2FG) | ||
357 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; | ||
358 | features->device_type = BTN_TOOL_PEN; | ||
359 | features->y_max = | 381 | features->y_max = |
360 | get_unaligned_le16(&report[i + 3]); | 382 | get_unaligned_le16(&report[i + 3]); |
361 | i += 4; | 383 | i += 4; |
@@ -377,6 +399,11 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
377 | pen = 1; | 399 | pen = 1; |
378 | i++; | 400 | i++; |
379 | break; | 401 | break; |
402 | |||
403 | case HID_USAGE_CONTACTMAX: | ||
404 | wacom_retrieve_report_data(intf, features); | ||
405 | i++; | ||
406 | break; | ||
380 | } | 407 | } |
381 | break; | 408 | break; |
382 | 409 | ||
@@ -413,22 +440,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat | |||
413 | if (!rep_data) | 440 | if (!rep_data) |
414 | return error; | 441 | return error; |
415 | 442 | ||
416 | /* ask to report tablet data if it is MT Tablet PC or | 443 | /* ask to report Wacom data */ |
417 | * not a Tablet PC */ | 444 | if (features->device_type == BTN_TOOL_FINGER) { |
418 | if (features->type == TABLETPC2FG) { | 445 | /* if it is an MT Tablet PC touch */ |
419 | do { | 446 | if (features->type == TABLETPC2FG || |
420 | rep_data[0] = 3; | 447 | features->type == MTSCREEN) { |
421 | rep_data[1] = 4; | 448 | do { |
422 | rep_data[2] = 0; | 449 | rep_data[0] = 3; |
423 | rep_data[3] = 0; | 450 | rep_data[1] = 4; |
424 | report_id = 3; | 451 | rep_data[2] = 0; |
425 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, | 452 | rep_data[3] = 0; |
426 | report_id, rep_data, 4, 1); | 453 | report_id = 3; |
427 | if (error >= 0) | 454 | error = wacom_set_report(intf, |
428 | error = wacom_get_report(intf, | 455 | WAC_HID_FEATURE_REPORT, |
429 | WAC_HID_FEATURE_REPORT, | 456 | report_id, |
430 | report_id, rep_data, 4, 1); | 457 | rep_data, 4, 1); |
431 | } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); | 458 | if (error >= 0) |
459 | error = wacom_get_report(intf, | ||
460 | WAC_HID_FEATURE_REPORT, | ||
461 | report_id, | ||
462 | rep_data, 4, 1); | ||
463 | } while ((error < 0 || rep_data[1] != 4) && | ||
464 | limit++ < WAC_MSG_RETRIES); | ||
465 | } | ||
432 | } else if (features->type != TABLETPC && | 466 | } else if (features->type != TABLETPC && |
433 | features->type != WIRELESS && | 467 | features->type != WIRELESS && |
434 | features->device_type == BTN_TOOL_PEN) { | 468 | features->device_type == BTN_TOOL_PEN) { |
@@ -450,7 +484,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat | |||
450 | } | 484 | } |
451 | 485 | ||
452 | static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | 486 | static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, |
453 | struct wacom_features *features) | 487 | struct wacom_features *features) |
454 | { | 488 | { |
455 | int error = 0; | 489 | int error = 0; |
456 | struct usb_host_interface *interface = intf->cur_altsetting; | 490 | struct usb_host_interface *interface = intf->cur_altsetting; |
@@ -478,16 +512,21 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | |||
478 | } | 512 | } |
479 | } | 513 | } |
480 | 514 | ||
481 | /* only Tablet PCs and Bamboo P&T need to retrieve the info */ | 515 | /* only devices that support touch need to retrieve the info */ |
482 | if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) && | 516 | if (features->type != TABLETPC && |
483 | (features->type != BAMBOO_PT)) | 517 | features->type != TABLETPC2FG && |
518 | features->type != BAMBOO_PT && | ||
519 | features->type != MTSCREEN) { | ||
484 | goto out; | 520 | goto out; |
521 | } | ||
485 | 522 | ||
486 | if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { | 523 | error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc); |
487 | if (usb_get_extra_descriptor(&interface->endpoint[0], | 524 | if (error) { |
488 | HID_DEVICET_REPORT, &hid_desc)) { | 525 | error = usb_get_extra_descriptor(&interface->endpoint[0], |
489 | printk("wacom: can not retrieve extra class descriptor\n"); | 526 | HID_DEVICET_REPORT, &hid_desc); |
490 | error = 1; | 527 | if (error) { |
528 | dev_err(&intf->dev, | ||
529 | "can not retrieve extra class descriptor\n"); | ||
491 | goto out; | 530 | goto out; |
492 | } | 531 | } |
493 | } | 532 | } |
@@ -577,23 +616,39 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom) | |||
577 | static int wacom_led_control(struct wacom *wacom) | 616 | static int wacom_led_control(struct wacom *wacom) |
578 | { | 617 | { |
579 | unsigned char *buf; | 618 | unsigned char *buf; |
580 | int retval, led = 0; | 619 | int retval; |
581 | 620 | ||
582 | buf = kzalloc(9, GFP_KERNEL); | 621 | buf = kzalloc(9, GFP_KERNEL); |
583 | if (!buf) | 622 | if (!buf) |
584 | return -ENOMEM; | 623 | return -ENOMEM; |
585 | 624 | ||
586 | if (wacom->wacom_wac.features.type == WACOM_21UX2 || | 625 | if (wacom->wacom_wac.features.type >= INTUOS5S && |
587 | wacom->wacom_wac.features.type == WACOM_24HD) | 626 | wacom->wacom_wac.features.type <= INTUOS5L) { |
588 | led = (wacom->led.select[1] << 4) | 0x40; | 627 | /* |
589 | 628 | * Touch Ring and crop mark LED luminance may take on | |
590 | led |= wacom->led.select[0] | 0x4; | 629 | * one of four values: |
591 | 630 | * 0 = Low; 1 = Medium; 2 = High; 3 = Off | |
592 | buf[0] = WAC_CMD_LED_CONTROL; | 631 | */ |
593 | buf[1] = led; | 632 | int ring_led = wacom->led.select[0] & 0x03; |
594 | buf[2] = wacom->led.llv; | 633 | int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03; |
595 | buf[3] = wacom->led.hlv; | 634 | int crop_lum = 0; |
596 | buf[4] = wacom->led.img_lum; | 635 | |
636 | buf[0] = WAC_CMD_LED_CONTROL; | ||
637 | buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led); | ||
638 | } | ||
639 | else { | ||
640 | int led = wacom->led.select[0] | 0x4; | ||
641 | |||
642 | if (wacom->wacom_wac.features.type == WACOM_21UX2 || | ||
643 | wacom->wacom_wac.features.type == WACOM_24HD) | ||
644 | led |= (wacom->led.select[1] << 4) | 0x40; | ||
645 | |||
646 | buf[0] = WAC_CMD_LED_CONTROL; | ||
647 | buf[1] = led; | ||
648 | buf[2] = wacom->led.llv; | ||
649 | buf[3] = wacom->led.hlv; | ||
650 | buf[4] = wacom->led.img_lum; | ||
651 | } | ||
597 | 652 | ||
598 | retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL, | 653 | retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL, |
599 | buf, 9, WAC_CMD_RETRIES); | 654 | buf, 9, WAC_CMD_RETRIES); |
@@ -786,6 +841,17 @@ static struct attribute_group intuos4_led_attr_group = { | |||
786 | .attrs = intuos4_led_attrs, | 841 | .attrs = intuos4_led_attrs, |
787 | }; | 842 | }; |
788 | 843 | ||
844 | static struct attribute *intuos5_led_attrs[] = { | ||
845 | &dev_attr_status0_luminance.attr, | ||
846 | &dev_attr_status_led0_select.attr, | ||
847 | NULL | ||
848 | }; | ||
849 | |||
850 | static struct attribute_group intuos5_led_attr_group = { | ||
851 | .name = "wacom_led", | ||
852 | .attrs = intuos5_led_attrs, | ||
853 | }; | ||
854 | |||
789 | static int wacom_initialize_leds(struct wacom *wacom) | 855 | static int wacom_initialize_leds(struct wacom *wacom) |
790 | { | 856 | { |
791 | int error; | 857 | int error; |
@@ -815,6 +881,19 @@ static int wacom_initialize_leds(struct wacom *wacom) | |||
815 | &cintiq_led_attr_group); | 881 | &cintiq_led_attr_group); |
816 | break; | 882 | break; |
817 | 883 | ||
884 | case INTUOS5S: | ||
885 | case INTUOS5: | ||
886 | case INTUOS5L: | ||
887 | wacom->led.select[0] = 0; | ||
888 | wacom->led.select[1] = 0; | ||
889 | wacom->led.llv = 32; | ||
890 | wacom->led.hlv = 0; | ||
891 | wacom->led.img_lum = 0; | ||
892 | |||
893 | error = sysfs_create_group(&wacom->intf->dev.kobj, | ||
894 | &intuos5_led_attr_group); | ||
895 | break; | ||
896 | |||
818 | default: | 897 | default: |
819 | return 0; | 898 | return 0; |
820 | } | 899 | } |
@@ -843,6 +922,13 @@ static void wacom_destroy_leds(struct wacom *wacom) | |||
843 | sysfs_remove_group(&wacom->intf->dev.kobj, | 922 | sysfs_remove_group(&wacom->intf->dev.kobj, |
844 | &cintiq_led_attr_group); | 923 | &cintiq_led_attr_group); |
845 | break; | 924 | break; |
925 | |||
926 | case INTUOS5S: | ||
927 | case INTUOS5: | ||
928 | case INTUOS5L: | ||
929 | sysfs_remove_group(&wacom->intf->dev.kobj, | ||
930 | &intuos5_led_attr_group); | ||
931 | break; | ||
846 | } | 932 | } |
847 | } | 933 | } |
848 | 934 | ||
@@ -904,8 +990,10 @@ static int wacom_register_input(struct wacom *wacom) | |||
904 | int error; | 990 | int error; |
905 | 991 | ||
906 | input_dev = input_allocate_device(); | 992 | input_dev = input_allocate_device(); |
907 | if (!input_dev) | 993 | if (!input_dev) { |
908 | return -ENOMEM; | 994 | error = -ENOMEM; |
995 | goto fail1; | ||
996 | } | ||
909 | 997 | ||
910 | input_dev->name = wacom_wac->name; | 998 | input_dev->name = wacom_wac->name; |
911 | input_dev->dev.parent = &intf->dev; | 999 | input_dev->dev.parent = &intf->dev; |
@@ -915,14 +1003,20 @@ static int wacom_register_input(struct wacom *wacom) | |||
915 | input_set_drvdata(input_dev, wacom); | 1003 | input_set_drvdata(input_dev, wacom); |
916 | 1004 | ||
917 | wacom_wac->input = input_dev; | 1005 | wacom_wac->input = input_dev; |
918 | wacom_setup_input_capabilities(input_dev, wacom_wac); | 1006 | error = wacom_setup_input_capabilities(input_dev, wacom_wac); |
1007 | if (error) | ||
1008 | goto fail1; | ||
919 | 1009 | ||
920 | error = input_register_device(input_dev); | 1010 | error = input_register_device(input_dev); |
921 | if (error) { | 1011 | if (error) |
922 | input_free_device(input_dev); | 1012 | goto fail2; |
923 | wacom_wac->input = NULL; | ||
924 | } | ||
925 | 1013 | ||
1014 | return 0; | ||
1015 | |||
1016 | fail2: | ||
1017 | input_free_device(input_dev); | ||
1018 | wacom_wac->input = NULL; | ||
1019 | fail1: | ||
926 | return error; | 1020 | return error; |
927 | } | 1021 | } |
928 | 1022 | ||
@@ -941,22 +1035,22 @@ static void wacom_wireless_work(struct work_struct *work) | |||
941 | wacom = usb_get_intfdata(usbdev->config->interface[1]); | 1035 | wacom = usb_get_intfdata(usbdev->config->interface[1]); |
942 | if (wacom->wacom_wac.input) | 1036 | if (wacom->wacom_wac.input) |
943 | input_unregister_device(wacom->wacom_wac.input); | 1037 | input_unregister_device(wacom->wacom_wac.input); |
944 | wacom->wacom_wac.input = 0; | 1038 | wacom->wacom_wac.input = NULL; |
945 | 1039 | ||
946 | /* Touch interface */ | 1040 | /* Touch interface */ |
947 | wacom = usb_get_intfdata(usbdev->config->interface[2]); | 1041 | wacom = usb_get_intfdata(usbdev->config->interface[2]); |
948 | if (wacom->wacom_wac.input) | 1042 | if (wacom->wacom_wac.input) |
949 | input_unregister_device(wacom->wacom_wac.input); | 1043 | input_unregister_device(wacom->wacom_wac.input); |
950 | wacom->wacom_wac.input = 0; | 1044 | wacom->wacom_wac.input = NULL; |
951 | 1045 | ||
952 | if (wacom_wac->pid == 0) { | 1046 | if (wacom_wac->pid == 0) { |
953 | printk(KERN_INFO "wacom: wireless tablet disconnected\n"); | 1047 | dev_info(&wacom->intf->dev, "wireless tablet disconnected\n"); |
954 | } else { | 1048 | } else { |
955 | const struct usb_device_id *id = wacom_ids; | 1049 | const struct usb_device_id *id = wacom_ids; |
956 | 1050 | ||
957 | printk(KERN_INFO | 1051 | dev_info(&wacom->intf->dev, |
958 | "wacom: wireless tablet connected with PID %x\n", | 1052 | "wireless tablet connected with PID %x\n", |
959 | wacom_wac->pid); | 1053 | wacom_wac->pid); |
960 | 1054 | ||
961 | while (id->match_flags) { | 1055 | while (id->match_flags) { |
962 | if (id->idVendor == USB_VENDOR_ID_WACOM && | 1056 | if (id->idVendor == USB_VENDOR_ID_WACOM && |
@@ -966,8 +1060,8 @@ static void wacom_wireless_work(struct work_struct *work) | |||
966 | } | 1060 | } |
967 | 1061 | ||
968 | if (!id->match_flags) { | 1062 | if (!id->match_flags) { |
969 | printk(KERN_INFO | 1063 | dev_info(&wacom->intf->dev, |
970 | "wacom: ignorning unknown PID.\n"); | 1064 | "ignoring unknown PID.\n"); |
971 | return; | 1065 | return; |
972 | } | 1066 | } |
973 | 1067 | ||
@@ -1038,11 +1132,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
1038 | 1132 | ||
1039 | endpoint = &intf->cur_altsetting->endpoint[0].desc; | 1133 | endpoint = &intf->cur_altsetting->endpoint[0].desc; |
1040 | 1134 | ||
1041 | /* Retrieve the physical and logical size for OEM devices */ | 1135 | /* Retrieve the physical and logical size for touch devices */ |
1042 | error = wacom_retrieve_hid_descriptor(intf, features); | 1136 | error = wacom_retrieve_hid_descriptor(intf, features); |
1043 | if (error) | 1137 | if (error) |
1044 | goto fail3; | 1138 | goto fail3; |
1045 | 1139 | ||
1140 | /* | ||
1141 | * Intuos5 has no useful data about its touch interface in its | ||
1142 | * HID descriptor. If this is the touch interface (wMaxPacketSize | ||
1143 | * of WACOM_PKGLEN_BBTOUCH3), override the table values. | ||
1144 | */ | ||
1145 | if (features->type >= INTUOS5S && features->type <= INTUOS5L) { | ||
1146 | if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) { | ||
1147 | features->device_type = BTN_TOOL_FINGER; | ||
1148 | features->pktlen = WACOM_PKGLEN_BBTOUCH3; | ||
1149 | |||
1150 | features->x_phy = | ||
1151 | (features->x_max * 100) / features->x_resolution; | ||
1152 | features->y_phy = | ||
1153 | (features->y_max * 100) / features->y_resolution; | ||
1154 | |||
1155 | features->x_max = 4096; | ||
1156 | features->y_max = 4096; | ||
1157 | } else { | ||
1158 | features->device_type = BTN_TOOL_PEN; | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1046 | wacom_setup_device_quirks(features); | 1162 | wacom_setup_device_quirks(features); |
1047 | 1163 | ||
1048 | strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); | 1164 | strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); |