diff options
Diffstat (limited to 'drivers/hid/hid-wacom.c')
| -rw-r--r-- | drivers/hid/hid-wacom.c | 218 |
1 files changed, 182 insertions, 36 deletions
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index fe23a1eb586..902013ec041 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -5,7 +5,6 @@ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc * Copyright (c) 2006-2007 Jiri Kosina - * Copyright (c) 2007 Paul Walmsley * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru> * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net> @@ -33,6 +32,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; @@ -45,6 +46,7 @@ struct wacom_data { __u8 battery_capacity; __u8 power_raw; __u8 ps_connected; + __u8 bat_charging; struct power_supply battery; struct power_supply ac; __u8 led_selector; @@ -61,6 +63,7 @@ static enum power_supply_property wacom_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_STATUS, }; static enum power_supply_property wacom_ac_props[] = { @@ -69,6 +72,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 = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2, + HID_FEATURE_REPORT, HID_REQ_SET_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 = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + } + + rep_data[0] = WAC_CMD_ICON_START_STOP; + rep_data[1] = 0; + + ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + +err: + return; +} + static void wacom_leds_set_brightness(struct led_classdev *led_dev, enum led_brightness value) { @@ -91,8 +179,12 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev, if (buf) { buf[0] = WAC_CMD_LED_CONTROL; buf[1] = led; - buf[2] = value; - hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); + buf[2] = value >> 2; + buf[3] = value; + /* use fixed brightness for OLEDs */ + buf[4] = 0x08; + hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT, + HID_REQ_SET_REPORT); kfree(buf); } @@ -198,6 +290,15 @@ static int wacom_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: val->intval = wdata->battery_capacity; break; + case POWER_SUPPLY_PROP_STATUS: + if (wdata->bat_charging) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + if (wdata->battery_capacity == 100 && wdata->ps_connected) + val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + break; default: ret = -EINVAL; break; @@ -239,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed) rep_data[0] = 0x03 ; rep_data[1] = 0x00; limit = 3; do { - ret = hdev->hid_output_raw_report(hdev, rep_data, 2, - HID_FEATURE_REPORT); + ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); } while (ret < 0 && limit-- > 0); if (ret >= 0) { @@ -252,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed) rep_data[1] = 0x00; limit = 3; do { - ret = hdev->hid_output_raw_report(hdev, - rep_data, 2, HID_FEATURE_REPORT); + ret = hid_hw_raw_request(hdev, rep_data[0], + rep_data, 2, HID_FEATURE_REPORT, + HID_REQ_SET_REPORT); } while (ret < 0 && limit-- > 0); if (ret >= 0) { @@ -278,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed) rep_data[0] = 0x03; rep_data[1] = wdata->features; - ret = hdev->hid_output_raw_report(hdev, rep_data, 2, - HID_FEATURE_REPORT); + ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret >= 0) wdata->high_speed = speed; break; @@ -317,6 +419,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) @@ -610,7 +740,8 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, if (power_raw != wdata->power_raw) { wdata->power_raw = power_raw; wdata->battery_capacity = batcap_i4[power_raw & 0x07]; - wdata->ps_connected = power_raw & 0x08; + wdata->bat_charging = (power_raw & 0x08) ? 1 : 0; + wdata->ps_connected = (power_raw & 0x10) ? 1 : 0; } break; @@ -717,17 +848,33 @@ 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); if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) { sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); ret = wacom_initialize_leds(hdev); - if (ret) { + if (ret) hid_warn(hdev, "can't create led attribute, err: %d\n", ret); - goto destroy_leds; - } } wdata->battery.properties = wacom_battery_props; @@ -740,8 +887,8 @@ static int wacom_probe(struct hid_device *hdev, ret = power_supply_register(&hdev->dev, &wdata->battery); if (ret) { - hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n", - ret); + hid_err(hdev, "can't create sysfs battery attribute, err: %d\n", + ret); goto err_battery; } @@ -756,8 +903,8 @@ static int wacom_probe(struct hid_device *hdev, ret = power_supply_register(&hdev->dev, &wdata->ac); if (ret) { - hid_warn(hdev, - "can't create ac battery attribute, err: %d\n", ret); + hid_err(hdev, + "can't create ac battery attribute, err: %d\n", ret); goto err_ac; } @@ -767,10 +914,17 @@ static int wacom_probe(struct hid_device *hdev, err_ac: power_supply_unregister(&wdata->battery); err_battery: + 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); -destroy_leds: - wacom_destroy_leds(hdev); err_free: kfree(wdata); return ret; @@ -781,6 +935,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); @@ -805,23 +967,7 @@ static struct hid_driver wacom_driver = { .raw_event = wacom_raw_event, .input_mapped = wacom_input_mapped, }; +module_hid_driver(wacom_driver); -static int __init wacom_init(void) -{ - int ret; - - ret = hid_register_driver(&wacom_driver); - if (ret) - pr_err("can't register wacom driver\n"); - return ret; -} - -static void __exit wacom_exit(void) -{ - hid_unregister_driver(&wacom_driver); -} - -module_init(wacom_init); -module_exit(wacom_exit); MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL"); MODULE_LICENSE("GPL"); |
