aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/tablet/wacom_sys.c
diff options
context:
space:
mode:
authorEduard Hasenleithner <eduard@hasenleithner.at>2011-09-07 17:08:54 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-09-07 17:19:01 -0400
commit5d7e7d479856f23eebc272128905a7ecada367fb (patch)
treede9a5eab7bee6007b7a576b6f96a9a32ce06dc57 /drivers/input/tablet/wacom_sys.c
parent7e66eaf14e19c032433be7c4df3c892fa2a5282f (diff)
Input: wacom - add Intuos4 LED and OLED control
This commit enables control of the LEDs and OLED displays found on the Wacom Intuos4 M, L, and XL. For this purpose, a new "wacom_led" attribute group is added to the sysfs entry of the USB device. This "wacom_led" group only shows up when the correct device (M, L, or XL) is detected. The attributes are described in Documentation/ABI/testing/sysfs-wacom Signed-off-by: Eduard Hasenleithner <eduard@hasenleithner.at> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
-rw-r--r--drivers/input/tablet/wacom_sys.c301
1 files changed, 271 insertions, 30 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index d27c9d91630b..0eccf57df5cd 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
54static 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
60static 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
64static int usb_set_report(struct usb_interface *intf, unsigned char type, 78static 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
74static void wacom_sys_irq(struct urb *urb) 96static void wacom_sys_irq(struct urb *urb)
@@ -333,23 +355,23 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
333 rep_data[2] = 0; 355 rep_data[2] = 0;
334 rep_data[3] = 0; 356 rep_data[3] = 0;
335 report_id = 3; 357 report_id = 3;
336 error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, 358 error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
337 report_id, rep_data, 4); 359 report_id, rep_data, 4, 1);
338 if (error >= 0) 360 if (error >= 0)
339 error = usb_get_report(intf, 361 error = wacom_get_report(intf,
340 WAC_HID_FEATURE_REPORT, report_id, 362 WAC_HID_FEATURE_REPORT,
341 rep_data, 4); 363 report_id, rep_data, 4, 1);
342 } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); 364 } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
343 } else if (features->type != TABLETPC) { 365 } else if (features->type != TABLETPC) {
344 do { 366 do {
345 rep_data[0] = 2; 367 rep_data[0] = 2;
346 rep_data[1] = 2; 368 rep_data[1] = 2;
347 error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, 369 error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
348 report_id, rep_data, 2); 370 report_id, rep_data, 2, 1);
349 if (error >= 0) 371 if (error >= 0)
350 error = usb_get_report(intf, 372 error = wacom_get_report(intf,
351 WAC_HID_FEATURE_REPORT, report_id, 373 WAC_HID_FEATURE_REPORT,
352 rep_data, 2); 374 report_id, rep_data, 2, 1);
353 } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); 375 } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
354 } 376 }
355 377
@@ -468,6 +490,220 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom)
468 } 490 }
469} 491}
470 492
493static int wacom_led_control(struct wacom *wacom)
494{
495 unsigned char *buf;
496 int retval;
497
498 buf = kzalloc(9, GFP_KERNEL);
499 if (!buf)
500 return -ENOMEM;
501
502 buf[0] = WAC_CMD_LED_CONTROL;
503 buf[1] = wacom->led.select >= 0 ? wacom->led.select | 4 : 0;
504 buf[2] = wacom->led.llv;
505 buf[3] = wacom->led.hlv;
506 buf[4] = wacom->led.img_lum;
507
508 retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
509 buf, 9, WAC_CMD_RETRIES);
510 kfree(buf);
511
512 return retval;
513}
514
515static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
516{
517 unsigned char *buf;
518 int i, retval;
519
520 buf = kzalloc(259, GFP_KERNEL);
521 if (!buf)
522 return -ENOMEM;
523
524 /* Send 'start' command */
525 buf[0] = WAC_CMD_ICON_START;
526 buf[1] = 1;
527 retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
528 buf, 2, WAC_CMD_RETRIES);
529 if (retval < 0)
530 goto out;
531
532 buf[0] = WAC_CMD_ICON_XFER;
533 buf[1] = button_id & 0x07;
534 for (i = 0; i < 4; i++) {
535 buf[2] = i;
536 memcpy(buf + 3, img + i * 256, 256);
537
538 retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER,
539 buf, 259, WAC_CMD_RETRIES);
540 if (retval < 0)
541 break;
542 }
543
544 /* Send 'stop' */
545 buf[0] = WAC_CMD_ICON_START;
546 buf[1] = 0;
547 wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
548 buf, 2, WAC_CMD_RETRIES);
549
550out:
551 kfree(buf);
552 return retval;
553}
554
555static ssize_t wacom_led_select_store(struct device *dev,
556 struct device_attribute *attr,
557 const char *buf, size_t count)
558{
559 struct wacom *wacom = dev_get_drvdata(dev);
560 unsigned int id;
561 int err;
562
563 err = kstrtouint(buf, 10, &id);
564 if (err)
565 return err;
566
567 mutex_lock(&wacom->lock);
568
569 wacom->led.select = id;
570 err = wacom_led_control(wacom);
571
572 mutex_unlock(&wacom->lock);
573
574 return err < 0 ? err : count;
575}
576
577static DEVICE_ATTR(status_led_select, S_IWUSR, NULL, wacom_led_select_store);
578
579static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
580 const char *buf, size_t count)
581{
582 unsigned int value;
583 int err;
584
585 err = kstrtouint(buf, 10, &value);
586 if (err)
587 return err;
588
589 mutex_lock(&wacom->lock);
590
591 *dest = value & 0x7f;
592 err = wacom_led_control(wacom);
593
594 mutex_unlock(&wacom->lock);
595
596 return err < 0 ? err : count;
597}
598
599#define DEVICE_LUMINANCE_ATTR(name, field) \
600static ssize_t wacom_##name##_luminance_store(struct device *dev, \
601 struct device_attribute *attr, const char *buf, size_t count) \
602{ \
603 struct wacom *wacom = dev_get_drvdata(dev); \
604 \
605 return wacom_luminance_store(wacom, &wacom->led.field, \
606 buf, count); \
607} \
608static DEVICE_ATTR(name##_luminance, S_IWUSR, \
609 NULL, wacom_##name##_luminance_store)
610
611DEVICE_LUMINANCE_ATTR(status0, llv);
612DEVICE_LUMINANCE_ATTR(status1, hlv);
613DEVICE_LUMINANCE_ATTR(buttons, img_lum);
614
615static ssize_t wacom_button_image_store(struct device *dev, int button_id,
616 const char *buf, size_t count)
617{
618 struct wacom *wacom = dev_get_drvdata(dev);
619 int err;
620
621 if (count != 1024)
622 return -EINVAL;
623
624 mutex_lock(&wacom->lock);
625
626 err = wacom_led_putimage(wacom, button_id, buf);
627
628 mutex_unlock(&wacom->lock);
629
630 return err < 0 ? err : count;
631}
632
633#define DEVICE_BTNIMG_ATTR(BUTTON_ID) \
634static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \
635 struct device_attribute *attr, const char *buf, size_t count) \
636{ \
637 return wacom_button_image_store(dev, BUTTON_ID, buf, count); \
638} \
639static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR, \
640 NULL, wacom_btnimg##BUTTON_ID##_store)
641
642DEVICE_BTNIMG_ATTR(0);
643DEVICE_BTNIMG_ATTR(1);
644DEVICE_BTNIMG_ATTR(2);
645DEVICE_BTNIMG_ATTR(3);
646DEVICE_BTNIMG_ATTR(4);
647DEVICE_BTNIMG_ATTR(5);
648DEVICE_BTNIMG_ATTR(6);
649DEVICE_BTNIMG_ATTR(7);
650
651static struct attribute *wacom_led_attrs[] = {
652 &dev_attr_status0_luminance.attr,
653 &dev_attr_status1_luminance.attr,
654 &dev_attr_status_led_select.attr,
655 &dev_attr_buttons_luminance.attr,
656 &dev_attr_button0_rawimg.attr,
657 &dev_attr_button1_rawimg.attr,
658 &dev_attr_button2_rawimg.attr,
659 &dev_attr_button3_rawimg.attr,
660 &dev_attr_button4_rawimg.attr,
661 &dev_attr_button5_rawimg.attr,
662 &dev_attr_button6_rawimg.attr,
663 &dev_attr_button7_rawimg.attr,
664 NULL
665};
666
667static struct attribute_group wacom_led_attr_group = {
668 .name = "wacom_led",
669 .attrs = wacom_led_attrs,
670};
671
672static int wacom_initialize_leds(struct wacom *wacom)
673{
674 int error;
675
676 if (wacom->wacom_wac.features.type >= INTUOS4 &&
677 wacom->wacom_wac.features.type <= INTUOS4L) {
678
679 /* Initialize default values */
680 wacom->led.select = 0;
681 wacom->led.llv = 30;
682 wacom->led.hlv = 20;
683 wacom->led.img_lum = 10;
684 wacom_led_control(wacom);
685
686 error = sysfs_create_group(&wacom->intf->dev.kobj,
687 &wacom_led_attr_group);
688 if (error) {
689 dev_err(&wacom->intf->dev,
690 "cannot create sysfs group err: %d\n", error);
691 return error;
692 }
693 }
694
695 return 0;
696}
697
698static void wacom_destroy_leds(struct wacom *wacom)
699{
700 if (wacom->wacom_wac.features.type >= INTUOS4 &&
701 wacom->wacom_wac.features.type <= INTUOS4L) {
702 sysfs_remove_group(&wacom->intf->dev.kobj,
703 &wacom_led_attr_group);
704 }
705}
706
471static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) 707static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
472{ 708{
473 struct usb_device *dev = interface_to_usbdev(intf); 709 struct usb_device *dev = interface_to_usbdev(intf);
@@ -556,16 +792,21 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
556 wacom->irq->transfer_dma = wacom->data_dma; 792 wacom->irq->transfer_dma = wacom->data_dma;
557 wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 793 wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
558 794
559 error = input_register_device(input_dev); 795 error = wacom_initialize_leds(wacom);
560 if (error) 796 if (error)
561 goto fail4; 797 goto fail4;
562 798
799 error = input_register_device(input_dev);
800 if (error)
801 goto fail5;
802
563 /* Note that if query fails it is not a hard failure */ 803 /* Note that if query fails it is not a hard failure */
564 wacom_query_tablet_data(intf, features); 804 wacom_query_tablet_data(intf, features);
565 805
566 usb_set_intfdata(intf, wacom); 806 usb_set_intfdata(intf, wacom);
567 return 0; 807 return 0;
568 808
809 fail5: wacom_destroy_leds(wacom);
569 fail4: wacom_remove_shared_data(wacom_wac); 810 fail4: wacom_remove_shared_data(wacom_wac);
570 fail3: usb_free_urb(wacom->irq); 811 fail3: usb_free_urb(wacom->irq);
571 fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); 812 fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
@@ -582,6 +823,7 @@ static void wacom_disconnect(struct usb_interface *intf)
582 823
583 usb_kill_urb(wacom->irq); 824 usb_kill_urb(wacom->irq);
584 input_unregister_device(wacom->wacom_wac.input); 825 input_unregister_device(wacom->wacom_wac.input);
826 wacom_destroy_leds(wacom);
585 usb_free_urb(wacom->irq); 827 usb_free_urb(wacom->irq);
586 usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, 828 usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
587 wacom->wacom_wac.data, wacom->data_dma); 829 wacom->wacom_wac.data, wacom->data_dma);
@@ -604,17 +846,16 @@ static int wacom_resume(struct usb_interface *intf)
604{ 846{
605 struct wacom *wacom = usb_get_intfdata(intf); 847 struct wacom *wacom = usb_get_intfdata(intf);
606 struct wacom_features *features = &wacom->wacom_wac.features; 848 struct wacom_features *features = &wacom->wacom_wac.features;
607 int rv; 849 int rv = 0;
608 850
609 mutex_lock(&wacom->lock); 851 mutex_lock(&wacom->lock);
610 852
611 /* switch to wacom mode first */ 853 /* switch to wacom mode first */
612 wacom_query_tablet_data(intf, features); 854 wacom_query_tablet_data(intf, features);
855 wacom_led_control(wacom);
613 856
614 if (wacom->open) 857 if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
615 rv = usb_submit_urb(wacom->irq, GFP_NOIO); 858 rv = -EIO;
616 else
617 rv = 0;
618 859
619 mutex_unlock(&wacom->lock); 860 mutex_unlock(&wacom->lock);
620 861