diff options
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 356 |
1 files changed, 326 insertions, 30 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 958b4eb6369..1c1b7b43cf9 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -48,27 +48,49 @@ struct hid_descriptor { | |||
48 | /* defines to get/set USB message */ | 48 | /* defines to get/set USB message */ |
49 | #define USB_REQ_GET_REPORT 0x01 | 49 | #define USB_REQ_GET_REPORT 0x01 |
50 | #define USB_REQ_SET_REPORT 0x09 | 50 | #define USB_REQ_SET_REPORT 0x09 |
51 | |||
51 | #define WAC_HID_FEATURE_REPORT 0x03 | 52 | #define WAC_HID_FEATURE_REPORT 0x03 |
52 | #define WAC_MSG_RETRIES 5 | 53 | #define WAC_MSG_RETRIES 5 |
53 | 54 | ||
54 | static int usb_get_report(struct usb_interface *intf, unsigned char type, | 55 | #define WAC_CMD_LED_CONTROL 0x20 |
55 | unsigned char id, void *buf, int size) | 56 | #define WAC_CMD_ICON_START 0x21 |
57 | #define WAC_CMD_ICON_XFER 0x23 | ||
58 | #define WAC_CMD_RETRIES 10 | ||
59 | |||
60 | static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id, | ||
61 | void *buf, size_t size, unsigned int retries) | ||
56 | { | 62 | { |
57 | return usb_control_msg(interface_to_usbdev(intf), | 63 | struct usb_device *dev = interface_to_usbdev(intf); |
58 | usb_rcvctrlpipe(interface_to_usbdev(intf), 0), | 64 | int retval; |
59 | USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 65 | |
60 | (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, | 66 | do { |
61 | buf, size, 100); | 67 | retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
68 | USB_REQ_GET_REPORT, | ||
69 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
70 | (type << 8) + id, | ||
71 | intf->altsetting[0].desc.bInterfaceNumber, | ||
72 | buf, size, 100); | ||
73 | } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); | ||
74 | |||
75 | return retval; | ||
62 | } | 76 | } |
63 | 77 | ||
64 | static int usb_set_report(struct usb_interface *intf, unsigned char type, | 78 | static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id, |
65 | unsigned char id, void *buf, int size) | 79 | void *buf, size_t size, unsigned int retries) |
66 | { | 80 | { |
67 | return usb_control_msg(interface_to_usbdev(intf), | 81 | struct usb_device *dev = interface_to_usbdev(intf); |
68 | usb_sndctrlpipe(interface_to_usbdev(intf), 0), | 82 | int retval; |
69 | USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 83 | |
70 | (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, | 84 | do { |
71 | buf, size, 1000); | 85 | retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
86 | USB_REQ_SET_REPORT, | ||
87 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
88 | (type << 8) + id, | ||
89 | intf->altsetting[0].desc.bInterfaceNumber, | ||
90 | buf, size, 1000); | ||
91 | } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); | ||
92 | |||
93 | return retval; | ||
72 | } | 94 | } |
73 | 95 | ||
74 | static void wacom_sys_irq(struct urb *urb) | 96 | static void wacom_sys_irq(struct urb *urb) |
@@ -319,23 +341,23 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat | |||
319 | rep_data[2] = 0; | 341 | rep_data[2] = 0; |
320 | rep_data[3] = 0; | 342 | rep_data[3] = 0; |
321 | report_id = 3; | 343 | report_id = 3; |
322 | error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, | 344 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, |
323 | report_id, rep_data, 4); | 345 | report_id, rep_data, 4, 1); |
324 | if (error >= 0) | 346 | if (error >= 0) |
325 | error = usb_get_report(intf, | 347 | error = wacom_get_report(intf, |
326 | WAC_HID_FEATURE_REPORT, report_id, | 348 | WAC_HID_FEATURE_REPORT, |
327 | rep_data, 4); | 349 | report_id, rep_data, 4, 1); |
328 | } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); | 350 | } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); |
329 | } else if (features->type != TABLETPC) { | 351 | } else if (features->type != TABLETPC) { |
330 | do { | 352 | do { |
331 | rep_data[0] = 2; | 353 | rep_data[0] = 2; |
332 | rep_data[1] = 2; | 354 | rep_data[1] = 2; |
333 | error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, | 355 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, |
334 | report_id, rep_data, 2); | 356 | report_id, rep_data, 2, 1); |
335 | if (error >= 0) | 357 | if (error >= 0) |
336 | error = usb_get_report(intf, | 358 | error = wacom_get_report(intf, |
337 | WAC_HID_FEATURE_REPORT, report_id, | 359 | WAC_HID_FEATURE_REPORT, |
338 | rep_data, 2); | 360 | report_id, rep_data, 2, 1); |
339 | } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); | 361 | } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); |
340 | } | 362 | } |
341 | 363 | ||
@@ -454,6 +476,275 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom) | |||
454 | } | 476 | } |
455 | } | 477 | } |
456 | 478 | ||
479 | static int wacom_led_control(struct wacom *wacom) | ||
480 | { | ||
481 | unsigned char *buf; | ||
482 | int retval, led = 0; | ||
483 | |||
484 | buf = kzalloc(9, GFP_KERNEL); | ||
485 | if (!buf) | ||
486 | return -ENOMEM; | ||
487 | |||
488 | if (wacom->wacom_wac.features.type == WACOM_21UX2) | ||
489 | led = (wacom->led.select[1] << 4) | 0x40; | ||
490 | |||
491 | led |= wacom->led.select[0] | 0x4; | ||
492 | |||
493 | buf[0] = WAC_CMD_LED_CONTROL; | ||
494 | buf[1] = led; | ||
495 | buf[2] = wacom->led.llv; | ||
496 | buf[3] = wacom->led.hlv; | ||
497 | buf[4] = wacom->led.img_lum; | ||
498 | |||
499 | retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL, | ||
500 | buf, 9, WAC_CMD_RETRIES); | ||
501 | kfree(buf); | ||
502 | |||
503 | return retval; | ||
504 | } | ||
505 | |||
506 | static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img) | ||
507 | { | ||
508 | unsigned char *buf; | ||
509 | int i, retval; | ||
510 | |||
511 | buf = kzalloc(259, GFP_KERNEL); | ||
512 | if (!buf) | ||
513 | return -ENOMEM; | ||
514 | |||
515 | /* Send 'start' command */ | ||
516 | buf[0] = WAC_CMD_ICON_START; | ||
517 | buf[1] = 1; | ||
518 | retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, | ||
519 | buf, 2, WAC_CMD_RETRIES); | ||
520 | if (retval < 0) | ||
521 | goto out; | ||
522 | |||
523 | buf[0] = WAC_CMD_ICON_XFER; | ||
524 | buf[1] = button_id & 0x07; | ||
525 | for (i = 0; i < 4; i++) { | ||
526 | buf[2] = i; | ||
527 | memcpy(buf + 3, img + i * 256, 256); | ||
528 | |||
529 | retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER, | ||
530 | buf, 259, WAC_CMD_RETRIES); | ||
531 | if (retval < 0) | ||
532 | break; | ||
533 | } | ||
534 | |||
535 | /* Send 'stop' */ | ||
536 | buf[0] = WAC_CMD_ICON_START; | ||
537 | buf[1] = 0; | ||
538 | wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, | ||
539 | buf, 2, WAC_CMD_RETRIES); | ||
540 | |||
541 | out: | ||
542 | kfree(buf); | ||
543 | return retval; | ||
544 | } | ||
545 | |||
546 | static ssize_t wacom_led_select_store(struct device *dev, int set_id, | ||
547 | const char *buf, size_t count) | ||
548 | { | ||
549 | struct wacom *wacom = dev_get_drvdata(dev); | ||
550 | unsigned int id; | ||
551 | int err; | ||
552 | |||
553 | err = kstrtouint(buf, 10, &id); | ||
554 | if (err) | ||
555 | return err; | ||
556 | |||
557 | mutex_lock(&wacom->lock); | ||
558 | |||
559 | wacom->led.select[set_id] = id & 0x3; | ||
560 | err = wacom_led_control(wacom); | ||
561 | |||
562 | mutex_unlock(&wacom->lock); | ||
563 | |||
564 | return err < 0 ? err : count; | ||
565 | } | ||
566 | |||
567 | #define DEVICE_LED_SELECT_ATTR(SET_ID) \ | ||
568 | static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \ | ||
569 | struct device_attribute *attr, const char *buf, size_t count) \ | ||
570 | { \ | ||
571 | return wacom_led_select_store(dev, SET_ID, buf, count); \ | ||
572 | } \ | ||
573 | static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \ | ||
574 | struct device_attribute *attr, char *buf) \ | ||
575 | { \ | ||
576 | struct wacom *wacom = dev_get_drvdata(dev); \ | ||
577 | return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \ | ||
578 | } \ | ||
579 | static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \ | ||
580 | wacom_led##SET_ID##_select_show, \ | ||
581 | wacom_led##SET_ID##_select_store) | ||
582 | |||
583 | DEVICE_LED_SELECT_ATTR(0); | ||
584 | DEVICE_LED_SELECT_ATTR(1); | ||
585 | |||
586 | static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest, | ||
587 | const char *buf, size_t count) | ||
588 | { | ||
589 | unsigned int value; | ||
590 | int err; | ||
591 | |||
592 | err = kstrtouint(buf, 10, &value); | ||
593 | if (err) | ||
594 | return err; | ||
595 | |||
596 | mutex_lock(&wacom->lock); | ||
597 | |||
598 | *dest = value & 0x7f; | ||
599 | err = wacom_led_control(wacom); | ||
600 | |||
601 | mutex_unlock(&wacom->lock); | ||
602 | |||
603 | return err < 0 ? err : count; | ||
604 | } | ||
605 | |||
606 | #define DEVICE_LUMINANCE_ATTR(name, field) \ | ||
607 | static ssize_t wacom_##name##_luminance_store(struct device *dev, \ | ||
608 | struct device_attribute *attr, const char *buf, size_t count) \ | ||
609 | { \ | ||
610 | struct wacom *wacom = dev_get_drvdata(dev); \ | ||
611 | \ | ||
612 | return wacom_luminance_store(wacom, &wacom->led.field, \ | ||
613 | buf, count); \ | ||
614 | } \ | ||
615 | static DEVICE_ATTR(name##_luminance, S_IWUSR, \ | ||
616 | NULL, wacom_##name##_luminance_store) | ||
617 | |||
618 | DEVICE_LUMINANCE_ATTR(status0, llv); | ||
619 | DEVICE_LUMINANCE_ATTR(status1, hlv); | ||
620 | DEVICE_LUMINANCE_ATTR(buttons, img_lum); | ||
621 | |||
622 | static ssize_t wacom_button_image_store(struct device *dev, int button_id, | ||
623 | const char *buf, size_t count) | ||
624 | { | ||
625 | struct wacom *wacom = dev_get_drvdata(dev); | ||
626 | int err; | ||
627 | |||
628 | if (count != 1024) | ||
629 | return -EINVAL; | ||
630 | |||
631 | mutex_lock(&wacom->lock); | ||
632 | |||
633 | err = wacom_led_putimage(wacom, button_id, buf); | ||
634 | |||
635 | mutex_unlock(&wacom->lock); | ||
636 | |||
637 | return err < 0 ? err : count; | ||
638 | } | ||
639 | |||
640 | #define DEVICE_BTNIMG_ATTR(BUTTON_ID) \ | ||
641 | static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \ | ||
642 | struct device_attribute *attr, const char *buf, size_t count) \ | ||
643 | { \ | ||
644 | return wacom_button_image_store(dev, BUTTON_ID, buf, count); \ | ||
645 | } \ | ||
646 | static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR, \ | ||
647 | NULL, wacom_btnimg##BUTTON_ID##_store) | ||
648 | |||
649 | DEVICE_BTNIMG_ATTR(0); | ||
650 | DEVICE_BTNIMG_ATTR(1); | ||
651 | DEVICE_BTNIMG_ATTR(2); | ||
652 | DEVICE_BTNIMG_ATTR(3); | ||
653 | DEVICE_BTNIMG_ATTR(4); | ||
654 | DEVICE_BTNIMG_ATTR(5); | ||
655 | DEVICE_BTNIMG_ATTR(6); | ||
656 | DEVICE_BTNIMG_ATTR(7); | ||
657 | |||
658 | static struct attribute *cintiq_led_attrs[] = { | ||
659 | &dev_attr_status_led0_select.attr, | ||
660 | &dev_attr_status_led1_select.attr, | ||
661 | NULL | ||
662 | }; | ||
663 | |||
664 | static struct attribute_group cintiq_led_attr_group = { | ||
665 | .name = "wacom_led", | ||
666 | .attrs = cintiq_led_attrs, | ||
667 | }; | ||
668 | |||
669 | static struct attribute *intuos4_led_attrs[] = { | ||
670 | &dev_attr_status0_luminance.attr, | ||
671 | &dev_attr_status1_luminance.attr, | ||
672 | &dev_attr_status_led0_select.attr, | ||
673 | &dev_attr_buttons_luminance.attr, | ||
674 | &dev_attr_button0_rawimg.attr, | ||
675 | &dev_attr_button1_rawimg.attr, | ||
676 | &dev_attr_button2_rawimg.attr, | ||
677 | &dev_attr_button3_rawimg.attr, | ||
678 | &dev_attr_button4_rawimg.attr, | ||
679 | &dev_attr_button5_rawimg.attr, | ||
680 | &dev_attr_button6_rawimg.attr, | ||
681 | &dev_attr_button7_rawimg.attr, | ||
682 | NULL | ||
683 | }; | ||
684 | |||
685 | static struct attribute_group intuos4_led_attr_group = { | ||
686 | .name = "wacom_led", | ||
687 | .attrs = intuos4_led_attrs, | ||
688 | }; | ||
689 | |||
690 | static int wacom_initialize_leds(struct wacom *wacom) | ||
691 | { | ||
692 | int error; | ||
693 | |||
694 | /* Initialize default values */ | ||
695 | switch (wacom->wacom_wac.features.type) { | ||
696 | case INTUOS4: | ||
697 | case INTUOS4L: | ||
698 | wacom->led.select[0] = 0; | ||
699 | wacom->led.select[1] = 0; | ||
700 | wacom->led.llv = 10; | ||
701 | wacom->led.hlv = 20; | ||
702 | wacom->led.img_lum = 10; | ||
703 | error = sysfs_create_group(&wacom->intf->dev.kobj, | ||
704 | &intuos4_led_attr_group); | ||
705 | break; | ||
706 | |||
707 | case WACOM_21UX2: | ||
708 | wacom->led.select[0] = 0; | ||
709 | wacom->led.select[1] = 0; | ||
710 | wacom->led.llv = 0; | ||
711 | wacom->led.hlv = 0; | ||
712 | wacom->led.img_lum = 0; | ||
713 | |||
714 | error = sysfs_create_group(&wacom->intf->dev.kobj, | ||
715 | &cintiq_led_attr_group); | ||
716 | break; | ||
717 | |||
718 | default: | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | if (error) { | ||
723 | dev_err(&wacom->intf->dev, | ||
724 | "cannot create sysfs group err: %d\n", error); | ||
725 | return error; | ||
726 | } | ||
727 | wacom_led_control(wacom); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static void wacom_destroy_leds(struct wacom *wacom) | ||
733 | { | ||
734 | switch (wacom->wacom_wac.features.type) { | ||
735 | case INTUOS4: | ||
736 | case INTUOS4L: | ||
737 | sysfs_remove_group(&wacom->intf->dev.kobj, | ||
738 | &intuos4_led_attr_group); | ||
739 | break; | ||
740 | |||
741 | case WACOM_21UX2: | ||
742 | sysfs_remove_group(&wacom->intf->dev.kobj, | ||
743 | &cintiq_led_attr_group); | ||
744 | break; | ||
745 | } | ||
746 | } | ||
747 | |||
457 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) | 748 | static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) |
458 | { | 749 | { |
459 | struct usb_device *dev = interface_to_usbdev(intf); | 750 | struct usb_device *dev = interface_to_usbdev(intf); |
@@ -542,16 +833,21 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
542 | wacom->irq->transfer_dma = wacom->data_dma; | 833 | wacom->irq->transfer_dma = wacom->data_dma; |
543 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 834 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
544 | 835 | ||
545 | error = input_register_device(input_dev); | 836 | error = wacom_initialize_leds(wacom); |
546 | if (error) | 837 | if (error) |
547 | goto fail4; | 838 | goto fail4; |
548 | 839 | ||
840 | error = input_register_device(input_dev); | ||
841 | if (error) | ||
842 | goto fail5; | ||
843 | |||
549 | /* Note that if query fails it is not a hard failure */ | 844 | /* Note that if query fails it is not a hard failure */ |
550 | wacom_query_tablet_data(intf, features); | 845 | wacom_query_tablet_data(intf, features); |
551 | 846 | ||
552 | usb_set_intfdata(intf, wacom); | 847 | usb_set_intfdata(intf, wacom); |
553 | return 0; | 848 | return 0; |
554 | 849 | ||
850 | fail5: wacom_destroy_leds(wacom); | ||
555 | fail4: wacom_remove_shared_data(wacom_wac); | 851 | fail4: wacom_remove_shared_data(wacom_wac); |
556 | fail3: usb_free_urb(wacom->irq); | 852 | fail3: usb_free_urb(wacom->irq); |
557 | fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); | 853 | fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); |
@@ -568,6 +864,7 @@ static void wacom_disconnect(struct usb_interface *intf) | |||
568 | 864 | ||
569 | usb_kill_urb(wacom->irq); | 865 | usb_kill_urb(wacom->irq); |
570 | input_unregister_device(wacom->wacom_wac.input); | 866 | input_unregister_device(wacom->wacom_wac.input); |
867 | wacom_destroy_leds(wacom); | ||
571 | usb_free_urb(wacom->irq); | 868 | usb_free_urb(wacom->irq); |
572 | usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, | 869 | usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, |
573 | wacom->wacom_wac.data, wacom->data_dma); | 870 | wacom->wacom_wac.data, wacom->data_dma); |
@@ -590,17 +887,16 @@ static int wacom_resume(struct usb_interface *intf) | |||
590 | { | 887 | { |
591 | struct wacom *wacom = usb_get_intfdata(intf); | 888 | struct wacom *wacom = usb_get_intfdata(intf); |
592 | struct wacom_features *features = &wacom->wacom_wac.features; | 889 | struct wacom_features *features = &wacom->wacom_wac.features; |
593 | int rv; | 890 | int rv = 0; |
594 | 891 | ||
595 | mutex_lock(&wacom->lock); | 892 | mutex_lock(&wacom->lock); |
596 | 893 | ||
597 | /* switch to wacom mode first */ | 894 | /* switch to wacom mode first */ |
598 | wacom_query_tablet_data(intf, features); | 895 | wacom_query_tablet_data(intf, features); |
896 | wacom_led_control(wacom); | ||
599 | 897 | ||
600 | if (wacom->open) | 898 | if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0) |
601 | rv = usb_submit_urb(wacom->irq, GFP_NOIO); | 899 | rv = -EIO; |
602 | else | ||
603 | rv = 0; | ||
604 | 900 | ||
605 | mutex_unlock(&wacom->lock); | 901 | mutex_unlock(&wacom->lock); |
606 | 902 | ||