|
@@ -33,6 +33,8 @@
|
|
|
#define PAD_DEVICE_ID 0x0F
|
|
|
|
|
|
#define WAC_CMD_LED_CONTROL 0x20
|
|
|
+#define WAC_CMD_ICON_START_STOP 0x21
|
|
|
+#define WAC_CMD_ICON_TRANSFER 0x26
|
|
|
|
|
|
struct wacom_data {
|
|
|
__u16 tool;
|
|
@@ -69,6 +71,91 @@ static enum power_supply_property wacom_ac_props[] = {
|
|
|
POWER_SUPPLY_PROP_SCOPE,
|
|
|
};
|
|
|
|
|
|
+static void wacom_scramble(__u8 *image)
|
|
|
+{
|
|
|
+ __u16 mask;
|
|
|
+ __u16 s1;
|
|
|
+ __u16 s2;
|
|
|
+ __u16 r1 ;
|
|
|
+ __u16 r2 ;
|
|
|
+ __u16 r;
|
|
|
+ __u8 buf[256];
|
|
|
+ int i, w, x, y, z;
|
|
|
+
|
|
|
+ for (x = 0; x < 32; x++) {
|
|
|
+ for (y = 0; y < 8; y++)
|
|
|
+ buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Change 76543210 into GECA6420 as required by Intuos4 WL
|
|
|
+ * HGFEDCBA HFDB7531
|
|
|
+ */
|
|
|
+ for (x = 0; x < 4; x++) {
|
|
|
+ for (y = 0; y < 4; y++) {
|
|
|
+ for (z = 0; z < 8; z++) {
|
|
|
+ mask = 0x0001;
|
|
|
+ r1 = 0;
|
|
|
+ r2 = 0;
|
|
|
+ i = (x << 6) + (y << 4) + z;
|
|
|
+ s1 = buf[i];
|
|
|
+ s2 = buf[i+8];
|
|
|
+ for (w = 0; w < 8; w++) {
|
|
|
+ r1 |= (s1 & mask);
|
|
|
+ r2 |= (s2 & mask);
|
|
|
+ s1 <<= 1;
|
|
|
+ s2 <<= 1;
|
|
|
+ mask <<= 2;
|
|
|
+ }
|
|
|
+ r = r1 | (r2 << 1);
|
|
|
+ i = (x << 6) + (y << 4) + (z << 1);
|
|
|
+ image[i] = 0xFF & r;
|
|
|
+ image[i+1] = (0xFF00 & r) >> 8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void wacom_set_image(struct hid_device *hdev, const char *image,
|
|
|
+ __u8 icon_no)
|
|
|
+{
|
|
|
+ __u8 rep_data[68];
|
|
|
+ __u8 p[256];
|
|
|
+ int ret, i, j;
|
|
|
+
|
|
|
+ for (i = 0; i < 256; i++)
|
|
|
+ p[i] = image[i];
|
|
|
+
|
|
|
+ rep_data[0] = WAC_CMD_ICON_START_STOP;
|
|
|
+ rep_data[1] = 0;
|
|
|
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
|
|
+ HID_FEATURE_REPORT);
|
|
|
+ if (ret < 0)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ rep_data[0] = WAC_CMD_ICON_TRANSFER;
|
|
|
+ rep_data[1] = icon_no & 0x07;
|
|
|
+
|
|
|
+ wacom_scramble(p);
|
|
|
+
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
+ for (j = 0; j < 64; j++)
|
|
|
+ rep_data[j + 3] = p[(i << 6) + j];
|
|
|
+
|
|
|
+ rep_data[2] = i;
|
|
|
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
|
|
|
+ HID_FEATURE_REPORT);
|
|
|
+ }
|
|
|
+
|
|
|
+ rep_data[0] = WAC_CMD_ICON_START_STOP;
|
|
|
+ rep_data[1] = 0;
|
|
|
+
|
|
|
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
|
|
+ HID_FEATURE_REPORT);
|
|
|
+
|
|
|
+err:
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
static void wacom_leds_set_brightness(struct led_classdev *led_dev,
|
|
|
enum led_brightness value)
|
|
|
{
|
|
@@ -93,6 +180,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
|
|
|
buf[1] = led;
|
|
|
buf[2] = value >> 2;
|
|
|
buf[3] = value;
|
|
|
+ /* use fixed brightness for OLEDs */
|
|
|
+ buf[4] = 0x08;
|
|
|
hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
|
|
|
kfree(buf);
|
|
|
}
|
|
@@ -318,6 +407,34 @@ static ssize_t wacom_store_speed(struct device *dev,
|
|
|
static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
|
wacom_show_speed, wacom_store_speed);
|
|
|
|
|
|
+#define WACOM_STORE(OLED_ID) \
|
|
|
+static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \
|
|
|
+ struct device_attribute *attr, \
|
|
|
+ const char *buf, size_t count) \
|
|
|
+{ \
|
|
|
+ struct hid_device *hdev = container_of(dev, struct hid_device, \
|
|
|
+ dev); \
|
|
|
+ \
|
|
|
+ if (count != 256) \
|
|
|
+ return -EINVAL; \
|
|
|
+ \
|
|
|
+ wacom_set_image(hdev, buf, OLED_ID); \
|
|
|
+ \
|
|
|
+ return count; \
|
|
|
+} \
|
|
|
+ \
|
|
|
+static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \
|
|
|
+ wacom_oled##OLED_ID##_store)
|
|
|
+
|
|
|
+WACOM_STORE(0);
|
|
|
+WACOM_STORE(1);
|
|
|
+WACOM_STORE(2);
|
|
|
+WACOM_STORE(3);
|
|
|
+WACOM_STORE(4);
|
|
|
+WACOM_STORE(5);
|
|
|
+WACOM_STORE(6);
|
|
|
+WACOM_STORE(7);
|
|
|
+
|
|
|
static int wacom_gr_parse_report(struct hid_device *hdev,
|
|
|
struct wacom_data *wdata,
|
|
|
struct input_dev *input, unsigned char *data)
|
|
@@ -718,6 +835,24 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
hid_warn(hdev,
|
|
|
"can't create sysfs speed attribute err: %d\n", ret);
|
|
|
|
|
|
+#define OLED_INIT(OLED_ID) \
|
|
|
+ do { \
|
|
|
+ ret = device_create_file(&hdev->dev, \
|
|
|
+ &dev_attr_oled##OLED_ID##_img); \
|
|
|
+ if (ret) \
|
|
|
+ hid_warn(hdev, \
|
|
|
+ "can't create sysfs oled attribute, err: %d\n", ret);\
|
|
|
+ } while (0)
|
|
|
+
|
|
|
+OLED_INIT(0);
|
|
|
+OLED_INIT(1);
|
|
|
+OLED_INIT(2);
|
|
|
+OLED_INIT(3);
|
|
|
+OLED_INIT(4);
|
|
|
+OLED_INIT(5);
|
|
|
+OLED_INIT(6);
|
|
|
+OLED_INIT(7);
|
|
|
+
|
|
|
wdata->features = 0;
|
|
|
wacom_set_features(hdev, 1);
|
|
|
|
|
@@ -782,6 +917,14 @@ static void wacom_remove(struct hid_device *hdev)
|
|
|
struct wacom_data *wdata = hid_get_drvdata(hdev);
|
|
|
|
|
|
wacom_destroy_leds(hdev);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled0_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled1_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled2_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled3_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled4_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled5_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled6_img);
|
|
|
+ device_remove_file(&hdev->dev, &dev_attr_oled7_img);
|
|
|
device_remove_file(&hdev->dev, &dev_attr_speed);
|
|
|
hid_hw_stop(hdev);
|
|
|
|