diff options
Diffstat (limited to 'drivers/hid/hid-wacom.c')
| -rw-r--r-- | drivers/hid/hid-wacom.c | 170 | 
1 files changed, 159 insertions, 11 deletions
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index fe23a1eb586..2f60da9ed06 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; @@ -69,6 +70,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)  { @@ -91,7 +177,10 @@ 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; +		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);  	} @@ -317,6 +406,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) @@ -717,17 +834,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 +873,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 +889,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 +900,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 +921,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);  |