diff options
author | Przemo Firszt <przemo@firszt.eu> | 2012-07-31 13:27:56 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-08-15 04:29:11 -0400 |
commit | e3c399ee4afebda7fd0a96a748e665a26853c246 (patch) | |
tree | c0b5350e8c42b0999cd1b2a96015a3e17959a78a /drivers/hid | |
parent | 530a76c14f40012354074a02254b41cb171e122f (diff) |
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>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-wacom.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 848842e0df14..0f02358888a9 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #define PAD_DEVICE_ID 0x0F | 33 | #define PAD_DEVICE_ID 0x0F |
34 | 34 | ||
35 | #define WAC_CMD_LED_CONTROL 0x20 | 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 | struct wacom_data { | 39 | struct wacom_data { |
38 | __u16 tool; | 40 | __u16 tool; |
@@ -69,6 +71,91 @@ static enum power_supply_property wacom_ac_props[] = { | |||
69 | POWER_SUPPLY_PROP_SCOPE, | 71 | POWER_SUPPLY_PROP_SCOPE, |
70 | }; | 72 | }; |
71 | 73 | ||
74 | static void wacom_scramble(__u8 *image) | ||
75 | { | ||
76 | __u16 mask; | ||
77 | __u16 s1; | ||
78 | __u16 s2; | ||
79 | __u16 r1 ; | ||
80 | __u16 r2 ; | ||
81 | __u16 r; | ||
82 | __u8 buf[256]; | ||
83 | int i, w, x, y, z; | ||
84 | |||
85 | for (x = 0; x < 32; x++) { | ||
86 | for (y = 0; y < 8; y++) | ||
87 | buf[(8 * x) + (7 - y)] = image[(8 * x) + y]; | ||
88 | } | ||
89 | |||
90 | /* Change 76543210 into GECA6420 as required by Intuos4 WL | ||
91 | * HGFEDCBA HFDB7531 | ||
92 | */ | ||
93 | for (x = 0; x < 4; x++) { | ||
94 | for (y = 0; y < 4; y++) { | ||
95 | for (z = 0; z < 8; z++) { | ||
96 | mask = 0x0001; | ||
97 | r1 = 0; | ||
98 | r2 = 0; | ||
99 | i = (x << 6) + (y << 4) + z; | ||
100 | s1 = buf[i]; | ||
101 | s2 = buf[i+8]; | ||
102 | for (w = 0; w < 8; w++) { | ||
103 | r1 |= (s1 & mask); | ||
104 | r2 |= (s2 & mask); | ||
105 | s1 <<= 1; | ||
106 | s2 <<= 1; | ||
107 | mask <<= 2; | ||
108 | } | ||
109 | r = r1 | (r2 << 1); | ||
110 | i = (x << 6) + (y << 4) + (z << 1); | ||
111 | image[i] = 0xFF & r; | ||
112 | image[i+1] = (0xFF00 & r) >> 8; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static void wacom_set_image(struct hid_device *hdev, const char *image, | ||
119 | __u8 icon_no) | ||
120 | { | ||
121 | __u8 rep_data[68]; | ||
122 | __u8 p[256]; | ||
123 | int ret, i, j; | ||
124 | |||
125 | for (i = 0; i < 256; i++) | ||
126 | p[i] = image[i]; | ||
127 | |||
128 | rep_data[0] = WAC_CMD_ICON_START_STOP; | ||
129 | rep_data[1] = 0; | ||
130 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
131 | HID_FEATURE_REPORT); | ||
132 | if (ret < 0) | ||
133 | goto err; | ||
134 | |||
135 | rep_data[0] = WAC_CMD_ICON_TRANSFER; | ||
136 | rep_data[1] = icon_no & 0x07; | ||
137 | |||
138 | wacom_scramble(p); | ||
139 | |||
140 | for (i = 0; i < 4; i++) { | ||
141 | for (j = 0; j < 64; j++) | ||
142 | rep_data[j + 3] = p[(i << 6) + j]; | ||
143 | |||
144 | rep_data[2] = i; | ||
145 | ret = hdev->hid_output_raw_report(hdev, rep_data, 67, | ||
146 | HID_FEATURE_REPORT); | ||
147 | } | ||
148 | |||
149 | rep_data[0] = WAC_CMD_ICON_START_STOP; | ||
150 | rep_data[1] = 0; | ||
151 | |||
152 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
153 | HID_FEATURE_REPORT); | ||
154 | |||
155 | err: | ||
156 | return; | ||
157 | } | ||
158 | |||
72 | static void wacom_leds_set_brightness(struct led_classdev *led_dev, | 159 | static void wacom_leds_set_brightness(struct led_classdev *led_dev, |
73 | enum led_brightness value) | 160 | enum led_brightness value) |
74 | { | 161 | { |
@@ -93,6 +180,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev, | |||
93 | buf[1] = led; | 180 | buf[1] = led; |
94 | buf[2] = value >> 2; | 181 | buf[2] = value >> 2; |
95 | buf[3] = value; | 182 | buf[3] = value; |
183 | /* use fixed brightness for OLEDs */ | ||
184 | buf[4] = 0x08; | ||
96 | hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); | 185 | hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); |
97 | kfree(buf); | 186 | kfree(buf); |
98 | } | 187 | } |
@@ -318,6 +407,34 @@ static ssize_t wacom_store_speed(struct device *dev, | |||
318 | static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, | 407 | static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, |
319 | wacom_show_speed, wacom_store_speed); | 408 | wacom_show_speed, wacom_store_speed); |
320 | 409 | ||
410 | #define WACOM_STORE(OLED_ID) \ | ||
411 | static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \ | ||
412 | struct device_attribute *attr, \ | ||
413 | const char *buf, size_t count) \ | ||
414 | { \ | ||
415 | struct hid_device *hdev = container_of(dev, struct hid_device, \ | ||
416 | dev); \ | ||
417 | \ | ||
418 | if (count != 256) \ | ||
419 | return -EINVAL; \ | ||
420 | \ | ||
421 | wacom_set_image(hdev, buf, OLED_ID); \ | ||
422 | \ | ||
423 | return count; \ | ||
424 | } \ | ||
425 | \ | ||
426 | static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \ | ||
427 | wacom_oled##OLED_ID##_store) | ||
428 | |||
429 | WACOM_STORE(0); | ||
430 | WACOM_STORE(1); | ||
431 | WACOM_STORE(2); | ||
432 | WACOM_STORE(3); | ||
433 | WACOM_STORE(4); | ||
434 | WACOM_STORE(5); | ||
435 | WACOM_STORE(6); | ||
436 | WACOM_STORE(7); | ||
437 | |||
321 | static int wacom_gr_parse_report(struct hid_device *hdev, | 438 | static int wacom_gr_parse_report(struct hid_device *hdev, |
322 | struct wacom_data *wdata, | 439 | struct wacom_data *wdata, |
323 | struct input_dev *input, unsigned char *data) | 440 | struct input_dev *input, unsigned char *data) |
@@ -718,6 +835,24 @@ static int wacom_probe(struct hid_device *hdev, | |||
718 | hid_warn(hdev, | 835 | hid_warn(hdev, |
719 | "can't create sysfs speed attribute err: %d\n", ret); | 836 | "can't create sysfs speed attribute err: %d\n", ret); |
720 | 837 | ||
838 | #define OLED_INIT(OLED_ID) \ | ||
839 | do { \ | ||
840 | ret = device_create_file(&hdev->dev, \ | ||
841 | &dev_attr_oled##OLED_ID##_img); \ | ||
842 | if (ret) \ | ||
843 | hid_warn(hdev, \ | ||
844 | "can't create sysfs oled attribute, err: %d\n", ret);\ | ||
845 | } while (0) | ||
846 | |||
847 | OLED_INIT(0); | ||
848 | OLED_INIT(1); | ||
849 | OLED_INIT(2); | ||
850 | OLED_INIT(3); | ||
851 | OLED_INIT(4); | ||
852 | OLED_INIT(5); | ||
853 | OLED_INIT(6); | ||
854 | OLED_INIT(7); | ||
855 | |||
721 | wdata->features = 0; | 856 | wdata->features = 0; |
722 | wacom_set_features(hdev, 1); | 857 | wacom_set_features(hdev, 1); |
723 | 858 | ||
@@ -782,6 +917,14 @@ static void wacom_remove(struct hid_device *hdev) | |||
782 | struct wacom_data *wdata = hid_get_drvdata(hdev); | 917 | struct wacom_data *wdata = hid_get_drvdata(hdev); |
783 | 918 | ||
784 | wacom_destroy_leds(hdev); | 919 | wacom_destroy_leds(hdev); |
920 | device_remove_file(&hdev->dev, &dev_attr_oled0_img); | ||
921 | device_remove_file(&hdev->dev, &dev_attr_oled1_img); | ||
922 | device_remove_file(&hdev->dev, &dev_attr_oled2_img); | ||
923 | device_remove_file(&hdev->dev, &dev_attr_oled3_img); | ||
924 | device_remove_file(&hdev->dev, &dev_attr_oled4_img); | ||
925 | device_remove_file(&hdev->dev, &dev_attr_oled5_img); | ||
926 | device_remove_file(&hdev->dev, &dev_attr_oled6_img); | ||
927 | device_remove_file(&hdev->dev, &dev_attr_oled7_img); | ||
785 | device_remove_file(&hdev->dev, &dev_attr_speed); | 928 | device_remove_file(&hdev->dev, &dev_attr_speed); |
786 | hid_hw_stop(hdev); | 929 | hid_hw_stop(hdev); |
787 | 930 | ||