Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: wacom: OLEDs control over sysfs for Intuos4

Thsi patch adds ability to control OLED micro displays on Wacom Intuos4
Wireless. The OLEDS are exposed as
/sys/class/hidraw/hidraw*/device/oled{No]_img
where No. is 0 to 7

Setting an image:

dd bs=256 if=img_file of=/sys/class/hidraw/hidraw{No}/device/oled0_img

The image has to contain 256 bytes (64x32px 1 bit). More detailed
description in Documentation/ABI/testing/sysfs-driver-wacom

Signed-off-by: Przemo Firszt <przemo@firszt.eu>
Acked-by: Ping Cheng <pingc@wacom.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Przemo Firszt and committed by
Jiri Kosina
e3c399ee 530a76c1

+156
+13
Documentation/ABI/testing/sysfs-driver-wacom
··· 1 + WWhat: /sys/class/hidraw/hidraw*/device/oled*_img 2 + Date: June 2012 3 + Contact: linux-bluetooth@vger.kernel.org 4 + Description: 5 + The /sys/class/hidraw/hidraw*/device/oled*_img files control 6 + OLED mocro displays on Intuos4 Wireless tablet. Accepted image 7 + has to contain 256 bytes (64x32 px 1 bit colour). The format 8 + is the same as PBM image 62x32px without header (64 bits per 9 + horizontal line, 32 lines). An example of setting OLED No. 0: 10 + dd bs=256 count=1 if=img_file of=[path to oled0_img]/oled0_img 11 + The attribute is read only and no local copy of the image is 12 + stored. 13 + 1 14 What: /sys/class/hidraw/hidraw*/device/speed 2 15 Date: April 2010 3 16 Kernel Version: 2.6.35
+143
drivers/hid/hid-wacom.c
··· 33 33 #define PAD_DEVICE_ID 0x0F 34 34 35 35 #define WAC_CMD_LED_CONTROL 0x20 36 + #define WAC_CMD_ICON_START_STOP 0x21 37 + #define WAC_CMD_ICON_TRANSFER 0x26 36 38 37 39 struct wacom_data { 38 40 __u16 tool; ··· 71 69 POWER_SUPPLY_PROP_SCOPE, 72 70 }; 73 71 72 + static void wacom_scramble(__u8 *image) 73 + { 74 + __u16 mask; 75 + __u16 s1; 76 + __u16 s2; 77 + __u16 r1 ; 78 + __u16 r2 ; 79 + __u16 r; 80 + __u8 buf[256]; 81 + int i, w, x, y, z; 82 + 83 + for (x = 0; x < 32; x++) { 84 + for (y = 0; y < 8; y++) 85 + buf[(8 * x) + (7 - y)] = image[(8 * x) + y]; 86 + } 87 + 88 + /* Change 76543210 into GECA6420 as required by Intuos4 WL 89 + * HGFEDCBA HFDB7531 90 + */ 91 + for (x = 0; x < 4; x++) { 92 + for (y = 0; y < 4; y++) { 93 + for (z = 0; z < 8; z++) { 94 + mask = 0x0001; 95 + r1 = 0; 96 + r2 = 0; 97 + i = (x << 6) + (y << 4) + z; 98 + s1 = buf[i]; 99 + s2 = buf[i+8]; 100 + for (w = 0; w < 8; w++) { 101 + r1 |= (s1 & mask); 102 + r2 |= (s2 & mask); 103 + s1 <<= 1; 104 + s2 <<= 1; 105 + mask <<= 2; 106 + } 107 + r = r1 | (r2 << 1); 108 + i = (x << 6) + (y << 4) + (z << 1); 109 + image[i] = 0xFF & r; 110 + image[i+1] = (0xFF00 & r) >> 8; 111 + } 112 + } 113 + } 114 + } 115 + 116 + static void wacom_set_image(struct hid_device *hdev, const char *image, 117 + __u8 icon_no) 118 + { 119 + __u8 rep_data[68]; 120 + __u8 p[256]; 121 + int ret, i, j; 122 + 123 + for (i = 0; i < 256; i++) 124 + p[i] = image[i]; 125 + 126 + rep_data[0] = WAC_CMD_ICON_START_STOP; 127 + rep_data[1] = 0; 128 + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 129 + HID_FEATURE_REPORT); 130 + if (ret < 0) 131 + goto err; 132 + 133 + rep_data[0] = WAC_CMD_ICON_TRANSFER; 134 + rep_data[1] = icon_no & 0x07; 135 + 136 + wacom_scramble(p); 137 + 138 + for (i = 0; i < 4; i++) { 139 + for (j = 0; j < 64; j++) 140 + rep_data[j + 3] = p[(i << 6) + j]; 141 + 142 + rep_data[2] = i; 143 + ret = hdev->hid_output_raw_report(hdev, rep_data, 67, 144 + HID_FEATURE_REPORT); 145 + } 146 + 147 + rep_data[0] = WAC_CMD_ICON_START_STOP; 148 + rep_data[1] = 0; 149 + 150 + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 151 + HID_FEATURE_REPORT); 152 + 153 + err: 154 + return; 155 + } 156 + 74 157 static void wacom_leds_set_brightness(struct led_classdev *led_dev, 75 158 enum led_brightness value) 76 159 { ··· 180 93 buf[1] = led; 181 94 buf[2] = value >> 2; 182 95 buf[3] = value; 96 + /* use fixed brightness for OLEDs */ 97 + buf[4] = 0x08; 183 98 hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); 184 99 kfree(buf); 185 100 } ··· 406 317 407 318 static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, 408 319 wacom_show_speed, wacom_store_speed); 320 + 321 + #define WACOM_STORE(OLED_ID) \ 322 + static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \ 323 + struct device_attribute *attr, \ 324 + const char *buf, size_t count) \ 325 + { \ 326 + struct hid_device *hdev = container_of(dev, struct hid_device, \ 327 + dev); \ 328 + \ 329 + if (count != 256) \ 330 + return -EINVAL; \ 331 + \ 332 + wacom_set_image(hdev, buf, OLED_ID); \ 333 + \ 334 + return count; \ 335 + } \ 336 + \ 337 + static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \ 338 + wacom_oled##OLED_ID##_store) 339 + 340 + WACOM_STORE(0); 341 + WACOM_STORE(1); 342 + WACOM_STORE(2); 343 + WACOM_STORE(3); 344 + WACOM_STORE(4); 345 + WACOM_STORE(5); 346 + WACOM_STORE(6); 347 + WACOM_STORE(7); 409 348 410 349 static int wacom_gr_parse_report(struct hid_device *hdev, 411 350 struct wacom_data *wdata, ··· 835 718 hid_warn(hdev, 836 719 "can't create sysfs speed attribute err: %d\n", ret); 837 720 721 + #define OLED_INIT(OLED_ID) \ 722 + do { \ 723 + ret = device_create_file(&hdev->dev, \ 724 + &dev_attr_oled##OLED_ID##_img); \ 725 + if (ret) \ 726 + hid_warn(hdev, \ 727 + "can't create sysfs oled attribute, err: %d\n", ret);\ 728 + } while (0) 729 + 730 + OLED_INIT(0); 731 + OLED_INIT(1); 732 + OLED_INIT(2); 733 + OLED_INIT(3); 734 + OLED_INIT(4); 735 + OLED_INIT(5); 736 + OLED_INIT(6); 737 + OLED_INIT(7); 738 + 838 739 wdata->features = 0; 839 740 wacom_set_features(hdev, 1); 840 741 ··· 917 782 struct wacom_data *wdata = hid_get_drvdata(hdev); 918 783 919 784 wacom_destroy_leds(hdev); 785 + device_remove_file(&hdev->dev, &dev_attr_oled0_img); 786 + device_remove_file(&hdev->dev, &dev_attr_oled1_img); 787 + device_remove_file(&hdev->dev, &dev_attr_oled2_img); 788 + device_remove_file(&hdev->dev, &dev_attr_oled3_img); 789 + device_remove_file(&hdev->dev, &dev_attr_oled4_img); 790 + device_remove_file(&hdev->dev, &dev_attr_oled5_img); 791 + device_remove_file(&hdev->dev, &dev_attr_oled6_img); 792 + device_remove_file(&hdev->dev, &dev_attr_oled7_img); 920 793 device_remove_file(&hdev->dev, &dev_attr_speed); 921 794 hid_hw_stop(hdev); 922 795