diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-driver-wacom | 8 | ||||
| -rw-r--r-- | drivers/hid/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/hid/hid-apple.c | 3 | ||||
| -rw-r--r-- | drivers/hid/hid-core.c | 2 | ||||
| -rw-r--r-- | drivers/hid/hid-ids.h | 1 | ||||
| -rw-r--r-- | drivers/hid/hid-input.c | 25 | ||||
| -rw-r--r-- | drivers/hid/hid-logitech-dj.c | 5 | ||||
| -rw-r--r-- | drivers/hid/hid-wacom.c | 302 | ||||
| -rw-r--r-- | drivers/hid/hid-waltop.c | 230 | ||||
| -rw-r--r-- | drivers/hid/hid-wiimote-core.c | 16 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | 
11 files changed, 461 insertions, 148 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index 0130d6683c1..56c54558c8a 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -9,6 +9,14 @@ Description:  		or 0 otherwise. Writing to this file one of these values  		switches reporting speed. +What:		/sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/ +Date:		May 2012 +Kernel Version:	3.5 +Contact:	linux-bluetooth@vger.kernel.org +Description: +		LED selector for Intuos4 WL. There are 4 leds, but only one LED +		can be lit at a time. Max brightness is 127. +  What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led  Date:		August 2011  Contact:	linux-input@vger.kernel.org diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 80175c37a6a..e9c68fedfcf 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -32,9 +32,13 @@ config HID  	  If unsure, say Y.  config HID_BATTERY_STRENGTH -	bool +	bool "Battery level reporting for HID devices"  	depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY  	default n +	---help--- +	This option adds support of reporting battery strength (for HID devices +	that support this feature) through power_supply class so that userspace +	tools, such as upower, can display it.  config HIDRAW  	bool "/dev/hidraw raw HID device support" @@ -613,16 +617,10 @@ config THRUSTMASTER_FF  config HID_WACOM  	tristate "Wacom Bluetooth devices support"  	depends on BT_HIDP -	---help--- -	Support for Wacom Graphire Bluetooth tablet. - -config HID_WACOM_POWER_SUPPLY -	bool "Wacom Bluetooth devices power supply status support" -	depends on HID_WACOM +	depends on LEDS_CLASS  	select POWER_SUPPLY  	---help--- -	  Say Y here if you want to enable power supply status monitoring for -	  Wacom Bluetooth devices. +	Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.  config HID_WIIMOTE  	tristate "Nintendo Wii Remote support" diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 7a79e39efc7..fa10f847f7d 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -458,6 +458,9 @@ static const struct hid_device_id apple_devices[] = {  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),  		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |  			APPLE_ISO_KEYBOARD }, +	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, +				USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), +		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),  		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9831a2ccae3..8e3a6b26147 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1511,7 +1511,6 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), },  	{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, @@ -1660,6 +1659,7 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4ff994166c0..9373f535dfe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -756,6 +756,7 @@  #define USB_DEVICE_ID_WALTOP_PID_0038			0x0038  #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH	0x0501  #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH	0x0500 +#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET	0x0502  #define USB_VENDOR_ID_WISEGROUP		0x0925  #define USB_DEVICE_ID_SMARTJOY_PLUS	0x0005 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7b43186b022..132b0019365 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -225,7 +225,10 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)  	 * Verify and convert units.  	 * See HID specification v1.11 6.2.2.7 Global Items for unit decoding  	 */ -	if (code == ABS_X || code == ABS_Y || code == ABS_Z) { +	switch (code) { +	case ABS_X: +	case ABS_Y: +	case ABS_Z:  		if (field->unit == 0x11) {		/* If centimeters */  			/* Convert to millimeters */  			unit_exponent += 1; @@ -239,7 +242,13 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)  		} else {  			return 0;  		} -	} else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) { +		break; + +	case ABS_RX: +	case ABS_RY: +	case ABS_RZ: +	case ABS_TILT_X: +	case ABS_TILT_Y:  		if (field->unit == 0x14) {		/* If degrees */  			/* Convert to radians */  			prev = logical_extents; @@ -250,7 +259,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)  		} else if (field->unit != 0x12) {	/* If not radians */  			return 0;  		} -	} else { +		break; + +	default:  		return 0;  	} @@ -623,6 +634,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel  			map_key_clear(BTN_TOOL_RUBBER);  			break; +		case 0x3d: /* X Tilt */ +			map_abs_clear(ABS_TILT_X); +			break; + +		case 0x3e: /* Y Tilt */ +			map_abs_clear(ABS_TILT_Y); +			break; +  		case 0x33: /* Touch */  		case 0x42: /* TipSwitch */  		case 0x43: /* TipSwitch2 */ diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index e1c38bba437..5e8a7ed4234 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -26,6 +26,7 @@  #include <linux/hid.h>  #include <linux/module.h>  #include <linux/usb.h> +#include <asm/unaligned.h>  #include "usbhid/usbhid.h"  #include "hid-ids.h"  #include "hid-logitech-dj.h" @@ -273,8 +274,8 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,  		goto dj_device_allocate_fail;  	} -	dj_dev->reports_supported = le32_to_cpu( -		dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]); +	dj_dev->reports_supported = get_unaligned_le32( +		dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);  	dj_dev->hdev = dj_hiddev;  	dj_dev->dj_receiver_dev = djrcv_dev;  	dj_dev->device_index = dj_report->device_index; diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 067e2963314..fe23a1eb586 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -24,15 +24,16 @@  #include <linux/device.h>  #include <linux/hid.h>  #include <linux/module.h> +#include <linux/leds.h>  #include <linux/slab.h> -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY  #include <linux/power_supply.h> -#endif  #include "hid-ids.h"  #define PAD_DEVICE_ID	0x0F +#define WAC_CMD_LED_CONTROL     0x20 +  struct wacom_data {  	__u16 tool;  	__u16 butstate; @@ -41,16 +42,20 @@ struct wacom_data {  	__u32 id;  	__u32 serial;  	unsigned char high_speed; -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY -	int battery_capacity; +	__u8 battery_capacity; +	__u8 power_raw; +	__u8 ps_connected;  	struct power_supply battery;  	struct power_supply ac; -#endif +	__u8 led_selector; +	struct led_classdev *leds[4];  }; -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY -/*percent of battery capacity, 0 means AC online*/ -static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 }; +/*percent of battery capacity for Graphire +  8th value means AC online and show 100% capacity */ +static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 }; +/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/ +static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };  static enum power_supply_property wacom_battery_props[] = {  	POWER_SUPPLY_PROP_PRESENT, @@ -64,13 +69,123 @@ static enum power_supply_property wacom_ac_props[] = {  	POWER_SUPPLY_PROP_SCOPE,  }; +static void wacom_leds_set_brightness(struct led_classdev *led_dev, +						enum led_brightness value) +{ +	struct device *dev = led_dev->dev->parent; +	struct hid_device *hdev; +	struct wacom_data *wdata; +	unsigned char *buf; +	__u8 led = 0; +	int i; + +	hdev = container_of(dev, struct hid_device, dev); +	wdata = hid_get_drvdata(hdev); +	for (i = 0; i < 4; ++i) { +		if (wdata->leds[i] == led_dev) +			wdata->led_selector = i; +	} + +	led = wdata->led_selector | 0x04; +	buf = kzalloc(9, GFP_KERNEL); +	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); +		kfree(buf); +	} + +	return; +} + +static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev) +{ +	struct wacom_data *wdata; +	struct device *dev = led_dev->dev->parent; +	int value = 0; +	int i; + +	wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); + +	for (i = 0; i < 4; ++i) { +		if (wdata->leds[i] == led_dev) { +			value = wdata->leds[i]->brightness; +			break; +		} +	} + +	return value; +} + + +static int wacom_initialize_leds(struct hid_device *hdev) +{ +	struct wacom_data *wdata = hid_get_drvdata(hdev); +	struct led_classdev *led; +	struct device *dev = &hdev->dev; +	size_t namesz = strlen(dev_name(dev)) + 12; +	char *name; +	int i, ret; + +	wdata->led_selector = 0; + +	for (i = 0; i < 4; i++) { +		led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); +		if (!led) { +			hid_warn(hdev, +				 "can't allocate memory for LED selector\n"); +			ret = -ENOMEM; +			goto err; +		} + +		name = (void *)&led[1]; +		snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i); +		led->name = name; +		led->brightness = 0; +		led->max_brightness = 127; +		led->brightness_get = wacom_leds_get_brightness; +		led->brightness_set = wacom_leds_set_brightness; + +		wdata->leds[i] = led; + +		ret = led_classdev_register(dev, wdata->leds[i]); + +		if (ret) { +			wdata->leds[i] = NULL; +			kfree(led); +			hid_warn(hdev, "can't register LED\n"); +			goto err; +		} +	} + +err: +	return ret; +} + +static void wacom_destroy_leds(struct hid_device *hdev) +{ +	struct wacom_data *wdata = hid_get_drvdata(hdev); +	struct led_classdev *led; +	int i; + +	for (i = 0; i < 4; ++i) { +		if (wdata->leds[i]) { +			led = wdata->leds[i]; +			wdata->leds[i] = NULL; +			led_classdev_unregister(led); +			kfree(led); +		} +	} + +} +  static int wacom_battery_get_property(struct power_supply *psy,  				enum power_supply_property psp,  				union power_supply_propval *val)  {  	struct wacom_data *wdata = container_of(psy,  					struct wacom_data, battery); -	int power_state = batcap[wdata->battery_capacity];  	int ret = 0;  	switch (psp) { @@ -81,11 +196,7 @@ static int wacom_battery_get_property(struct power_supply *psy,  		val->intval = POWER_SUPPLY_SCOPE_DEVICE;  		break;  	case POWER_SUPPLY_PROP_CAPACITY: -		/* show 100% battery capacity when charging */ -		if (power_state == 0) -			val->intval = 100; -		else -			val->intval = power_state; +		val->intval = wdata->battery_capacity;  		break;  	default:  		ret = -EINVAL; @@ -99,17 +210,13 @@ static int wacom_ac_get_property(struct power_supply *psy,  				union power_supply_propval *val)  {  	struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); -	int power_state = batcap[wdata->battery_capacity];  	int ret = 0;  	switch (psp) {  	case POWER_SUPPLY_PROP_PRESENT:  		/* fall through */  	case POWER_SUPPLY_PROP_ONLINE: -		if (power_state == 0) -			val->intval = 1; -		else -			val->intval = 0; +		val->intval = wdata->ps_connected;  		break;  	case POWER_SUPPLY_PROP_SCOPE:  		val->intval = POWER_SUPPLY_SCOPE_DEVICE; @@ -120,41 +227,16 @@ static int wacom_ac_get_property(struct power_supply *psy,  	}  	return ret;  } -#endif -static void wacom_set_features(struct hid_device *hdev) -{ -	int ret; -	__u8 rep_data[2]; - -	/*set high speed, tablet mode*/ -	rep_data[0] = 0x03; -	rep_data[1] = 0x20; -	ret = hdev->hid_output_raw_report(hdev, rep_data, 2, -				HID_FEATURE_REPORT); -	return; -} - -static void wacom_poke(struct hid_device *hdev, u8 speed) +static void wacom_set_features(struct hid_device *hdev, u8 speed)  {  	struct wacom_data *wdata = hid_get_drvdata(hdev);  	int limit, ret; -	char rep_data[2]; - -	rep_data[0] = 0x03 ; rep_data[1] = 0x00; -	limit = 3; -	do { -		ret = hdev->hid_output_raw_report(hdev, rep_data, 2, -				HID_FEATURE_REPORT); -	} while (ret < 0 && limit-- > 0); - -	if (ret >= 0) { -		if (speed == 0) -			rep_data[0] = 0x05; -		else -			rep_data[0] = 0x06; +	__u8 rep_data[2]; -		rep_data[1] = 0x00; +	switch (hdev->product) { +	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: +		rep_data[0] = 0x03 ; rep_data[1] = 0x00;  		limit = 3;  		do {  			ret = hdev->hid_output_raw_report(hdev, rep_data, 2, @@ -162,17 +244,47 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)  		} while (ret < 0 && limit-- > 0);  		if (ret >= 0) { -			wdata->high_speed = speed; -			return; +			if (speed == 0) +				rep_data[0] = 0x05; +			else +				rep_data[0] = 0x06; + +			rep_data[1] = 0x00; +			limit = 3; +			do { +				ret = hdev->hid_output_raw_report(hdev, +					rep_data, 2, HID_FEATURE_REPORT); +			} while (ret < 0 && limit-- > 0); + +			if (ret >= 0) { +				wdata->high_speed = speed; +				return; +			}  		} + +		/* +		 * Note that if the raw queries fail, it's not a hard failure +		 * and it is safe to continue +		 */ +		hid_warn(hdev, "failed to poke device, command %d, err %d\n", +			 rep_data[0], ret); +		break; +	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: +		if (speed == 1) +			wdata->features &= ~0x20; +		else +			wdata->features |= 0x20; + +		rep_data[0] = 0x03; +		rep_data[1] = wdata->features; + +		ret = hdev->hid_output_raw_report(hdev, rep_data, 2, +					HID_FEATURE_REPORT); +		if (ret >= 0) +			wdata->high_speed = speed; +		break;  	} -	/* -	 * Note that if the raw queries fail, it's not a hard failure and it -	 * is safe to continue -	 */ -	hid_warn(hdev, "failed to poke device, command %d, err %d\n", -		 rep_data[0], ret);  	return;  } @@ -196,7 +308,7 @@ static ssize_t wacom_store_speed(struct device *dev,  		return -EINVAL;  	if (new_speed == 0 || new_speed == 1) { -		wacom_poke(hdev, new_speed); +		wacom_set_features(hdev, new_speed);  		return strnlen(buf, PAGE_SIZE);  	} else  		return -EINVAL; @@ -310,12 +422,16 @@ static int wacom_gr_parse_report(struct hid_device *hdev,  		input_sync(input);  	} -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY -	/* Store current battery capacity */ +	/* Store current battery capacity and power supply state*/  	rw = (data[7] >> 2 & 0x07); -	if (rw != wdata->battery_capacity) -		wdata->battery_capacity = rw; -#endif +	if (rw != wdata->power_raw) { +		wdata->power_raw = rw; +		wdata->battery_capacity = batcap_gr[rw]; +		if (rw == 7) +			wdata->ps_connected = 1; +		else +			wdata->ps_connected = 0; +	}  	return 1;  } @@ -369,6 +485,7 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,  {  	__u16 x, y, pressure;  	__u8 distance; +	__u8 tilt_x, tilt_y;  	switch (data[1]) {  	case 0x80: /* Out of proximity report */ @@ -405,6 +522,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,  		pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)  			| (data[1] & 0x01);  		distance = (data[9] >> 2) & 0x3f; +		tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7); +		tilt_y = data[8] & 0x7f;  		input_report_key(input, BTN_TOUCH, pressure > 1); @@ -415,6 +534,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,  		input_report_abs(input, ABS_Y, y);  		input_report_abs(input, ABS_PRESSURE, pressure);  		input_report_abs(input, ABS_DISTANCE, distance); +		input_report_abs(input, ABS_TILT_X, tilt_x); +		input_report_abs(input, ABS_TILT_Y, tilt_y);  		input_report_abs(input, ABS_MISC, wdata->id);  		input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);  		input_report_key(input, wdata->tool, 1); @@ -455,6 +576,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,  	struct input_dev *input;  	unsigned char *data = (unsigned char *) raw_data;  	int i; +	__u8 power_raw;  	if (!(hdev->claimed & HID_CLAIMED_INPUT))  		return 0; @@ -462,13 +584,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,  	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);  	input = hidinput->input; -	/* Check if this is a tablet report */ -	if (data[0] != 0x03) -		return 0; -  	switch (hdev->product) {  	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: -		return wacom_gr_parse_report(hdev, wdata, input, data); +		if (data[0] == 0x03) { +			return wacom_gr_parse_report(hdev, wdata, input, data); +		} else { +			hid_err(hdev, "Unknown report: %d,%d size:%d\n", +					data[0], data[1], size); +			return 0; +		}  		break;  	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:  		i = 1; @@ -482,6 +606,13 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,  			wacom_i4_parse_report(hdev, wdata, input, data + i);  			i += 10;  			wacom_i4_parse_report(hdev, wdata, input, data + i); +			power_raw = data[i+10]; +			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; +			} +  			break;  		default:  			hid_err(hdev, "Unknown report: %d,%d size:%d\n", @@ -546,6 +677,8 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,  		input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);  		input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);  		input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0); +		input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0); +		input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);  		break;  	} @@ -584,19 +717,19 @@ static int wacom_probe(struct hid_device *hdev,  		hid_warn(hdev,  			 "can't create sysfs speed attribute err: %d\n", ret); -	switch (hdev->product) { -	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: -		/* Set Wacom mode 2 with high reporting speed */ -		wacom_poke(hdev, 1); -		break; -	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: +	wdata->features = 0; +	wacom_set_features(hdev, 1); + +	if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {  		sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); -		wdata->features = 0; -		wacom_set_features(hdev); -		break; +		ret = wacom_initialize_leds(hdev); +		if (ret) { +			hid_warn(hdev, +				 "can't create led attribute, err: %d\n", ret); +			goto destroy_leds; +		}  	} -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY  	wdata->battery.properties = wacom_battery_props;  	wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);  	wdata->battery.get_property = wacom_battery_get_property; @@ -629,16 +762,15 @@ static int wacom_probe(struct hid_device *hdev,  	}  	power_supply_powers(&wdata->ac, &hdev->dev); -#endif  	return 0; -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY  err_ac:  	power_supply_unregister(&wdata->battery);  err_battery:  	device_remove_file(&hdev->dev, &dev_attr_speed);  	hid_hw_stop(hdev); -#endif +destroy_leds: +	wacom_destroy_leds(hdev);  err_free:  	kfree(wdata);  	return ret; @@ -646,16 +778,14 @@ err_free:  static void wacom_remove(struct hid_device *hdev)  { -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY  	struct wacom_data *wdata = hid_get_drvdata(hdev); -#endif + +	wacom_destroy_leds(hdev);  	device_remove_file(&hdev->dev, &dev_attr_speed);  	hid_hw_stop(hdev); -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY  	power_supply_unregister(&wdata->battery);  	power_supply_unregister(&wdata->ac); -#endif  	kfree(hid_get_drvdata(hdev));  } @@ -693,5 +823,5 @@ static void __exit wacom_exit(void)  module_init(wacom_init);  module_exit(wacom_exit); +MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");  MODULE_LICENSE("GPL"); - diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c index 2cfd95c4467..745e4e9a8cf 100644 --- a/drivers/hid/hid-waltop.c +++ b/drivers/hid/hid-waltop.c @@ -502,28 +502,146 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {  	0xC0                /*  End Collection                      */  }; -struct waltop_state { -	u8 pressure0; -	u8 pressure1; +/* + * See Sirius Battery Free Tablet description, device and HID report descriptors + * at + * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet + */ + +/* Size of the original report descriptor of Sirius Battery Free Tablet */ +#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE	335 + +/* Fixed Sirius Battery Free Tablet descriptor */ +static __u8 sirius_battery_free_tablet_rdesc_fixed[] = { +	0x05, 0x0D,         /*  Usage Page (Digitizer),             */ +	0x09, 0x02,         /*  Usage (Pen),                        */ +	0xA1, 0x01,         /*  Collection (Application),           */ +	0x85, 0x10,         /*      Report ID (16),                 */ +	0x09, 0x20,         /*      Usage (Stylus),                 */ +	0xA0,               /*      Collection (Physical),          */ +	0x95, 0x01,         /*          Report Count (1),           */ +	0x15, 0x01,         /*          Logical Minimum (1),        */ +	0x25, 0x03,         /*          Logical Maximum (3),        */ +	0x75, 0x02,         /*          Report Size (2),            */ +	0x09, 0x42,         /*          Usage (Tip Switch),         */ +	0x09, 0x44,         /*          Usage (Barrel Switch),      */ +	0x09, 0x46,         /*          Usage (Tablet Pick),        */ +	0x80,               /*          Input,                      */ +	0x14,               /*          Logical Minimum (0),        */ +	0x25, 0x01,         /*          Logical Maximum (1),        */ +	0x75, 0x01,         /*          Report Size (1),            */ +	0x09, 0x3C,         /*          Usage (Invert),             */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0x09, 0x32,         /*          Usage (In Range),           */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x95, 0x03,         /*          Report Count (3),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0xA4,               /*          Push,                       */ +	0x05, 0x01,         /*          Usage Page (Desktop),       */ +	0x55, 0xFD,         /*          Unit Exponent (-3),         */ +	0x65, 0x13,         /*          Unit (Inch),                */ +	0x34,               /*          Physical Minimum (0),       */ +	0x14,               /*          Logical Minimum (0),        */ +	0x75, 0x10,         /*          Report Size (16),           */ +	0x95, 0x01,         /*          Report Count (1),           */ +	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */ +	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */ +	0x09, 0x30,         /*          Usage (X),                  */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */ +	0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */ +	0x09, 0x31,         /*          Usage (Y),                  */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0xB4,               /*          Pop,                        */ +	0x75, 0x10,         /*          Report Size (16),           */ +	0x95, 0x01,         /*          Report Count (1),           */ +	0x14,               /*          Logical Minimum (0),        */ +	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */ +	0x09, 0x30,         /*          Usage (Tip Pressure),       */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0xA4,               /*          Push,                       */ +	0x55, 0xFE,         /*          Unit Exponent (-2),         */ +	0x65, 0x12,         /*          Unit (Radians),             */ +	0x35, 0x97,         /*          Physical Minimum (-105),    */ +	0x45, 0x69,         /*          Physical Maximum (105),     */ +	0x15, 0x97,         /*          Logical Minimum (-105),     */ +	0x25, 0x69,         /*          Logical Maximum (105),      */ +	0x75, 0x08,         /*          Report Size (8),            */ +	0x95, 0x02,         /*          Report Count (2),           */ +	0x09, 0x3D,         /*          Usage (X Tilt),             */ +	0x09, 0x3E,         /*          Usage (Y Tilt),             */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0xB4,               /*          Pop,                        */ +	0xC0,               /*      End Collection,                 */ +	0xC0,               /*  End Collection,                     */ +	0x05, 0x01,         /*  Usage Page (Desktop),               */ +	0x09, 0x02,         /*  Usage (Mouse),                      */ +	0xA1, 0x01,         /*  Collection (Application),           */ +	0x85, 0x01,         /*      Report ID (1),                  */ +	0x09, 0x01,         /*      Usage (Pointer),                */ +	0xA0,               /*      Collection (Physical),          */ +	0x75, 0x08,         /*          Report Size (8),            */ +	0x95, 0x03,         /*          Report Count (3),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0x09, 0x38,         /*          Usage (Wheel),              */ +	0x15, 0xFF,         /*          Logical Minimum (-1),       */ +	0x25, 0x01,         /*          Logical Maximum (1),        */ +	0x75, 0x08,         /*          Report Size (8),            */ +	0x95, 0x01,         /*          Report Count (1),           */ +	0x81, 0x06,         /*          Input (Variable, Relative), */ +	0x75, 0x08,         /*          Report Size (8),            */ +	0x95, 0x03,         /*          Report Count (3),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0xC0,               /*      End Collection,                 */ +	0xC0,               /*  End Collection,                     */ +	0x05, 0x01,         /*  Usage Page (Desktop),               */ +	0x09, 0x06,         /*  Usage (Keyboard),                   */ +	0xA1, 0x01,         /*  Collection (Application),           */ +	0x85, 0x0D,         /*      Report ID (13),                 */ +	0x05, 0x07,         /*      Usage Page (Keyboard),          */ +	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */ +	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */ +	0x14,               /*      Logical Minimum (0),            */ +	0x25, 0x01,         /*      Logical Maximum (1),            */ +	0x75, 0x01,         /*      Report Size (1),                */ +	0x95, 0x08,         /*      Report Count (8),               */ +	0x81, 0x02,         /*      Input (Variable),               */ +	0x75, 0x08,         /*      Report Size (8),                */ +	0x95, 0x01,         /*      Report Count (1),               */ +	0x81, 0x01,         /*      Input (Constant),               */ +	0x18,               /*      Usage Minimum (None),           */ +	0x29, 0x65,         /*      Usage Maximum (KB Application), */ +	0x14,               /*      Logical Minimum (0),            */ +	0x25, 0x65,         /*      Logical Maximum (101),          */ +	0x75, 0x08,         /*      Report Size (8),                */ +	0x95, 0x05,         /*      Report Count (5),               */ +	0x80,               /*      Input,                          */ +	0xC0,               /*  End Collection,                     */ +	0x05, 0x0C,         /*  Usage Page (Consumer),              */ +	0x09, 0x01,         /*  Usage (Consumer Control),           */ +	0xA1, 0x01,         /*  Collection (Application),           */ +	0x85, 0x0C,         /*      Report ID (12),                 */ +	0x09, 0xE9,         /*      Usage (Volume Inc),             */ +	0x09, 0xEA,         /*      Usage (Volume Dec),             */ +	0x14,               /*      Logical Minimum (0),            */ +	0x25, 0x01,         /*      Logical Maximum (1),            */ +	0x75, 0x01,         /*      Report Size (1),                */ +	0x95, 0x02,         /*      Report Count (2),               */ +	0x81, 0x02,         /*      Input (Variable),               */ +	0x75, 0x06,         /*      Report Size (6),                */ +	0x95, 0x01,         /*      Report Count (1),               */ +	0x81, 0x03,         /*      Input (Constant, Variable),     */ +	0x75, 0x10,         /*      Report Size (16),               */ +	0x95, 0x03,         /*      Report Count (3),               */ +	0x81, 0x03,         /*      Input (Constant, Variable),     */ +	0xC0                /*  End Collection                      */  };  static int waltop_probe(struct hid_device *hdev,  			const struct hid_device_id *id)  {  	int ret; -	struct waltop_state *s; - -	s = kzalloc(sizeof(*s), GFP_KERNEL); -	if (s == NULL) { -		hid_err(hdev, "can't allocate device state\n"); -		ret = -ENOMEM; -		goto err; -	} - -	s->pressure0 = 0; -	s->pressure1 = 0; - -	hid_set_drvdata(hdev, s);  	ret = hid_parse(hdev);  	if (ret) { @@ -539,7 +657,6 @@ static int waltop_probe(struct hid_device *hdev,  	return 0;  err: -	kfree(s);  	return ret;  } @@ -583,6 +700,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,  			*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);  		}  		break; +	case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET: +		if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) { +			rdesc = sirius_battery_free_tablet_rdesc_fixed; +			*rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed); +		} +		break;  	}  	return rdesc;  } @@ -590,39 +713,72 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,  static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,  		     u8 *data, int size)  { -	/* If this is a pen input report of a tablet with PID 0038 */ -	if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 && -	    report->type == HID_INPUT_REPORT && -	    report->id == 16 && -	    size == 8) { -		struct waltop_state *s = hid_get_drvdata(hdev); - +	/* If this is a pen input report */ +	if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {  		/* -		 * Ignore maximum pressure reported when a barrel button is -		 * pressed. +		 * Ignore reported pressure when a barrel button is pressed, +		 * because it is rarely correct.  		 */  		/* If a barrel button is pressed */  		if ((data[1] & 0xF) > 1) { -			/* Use the last known pressure */ -			data[6] = s->pressure0; -			data[7] = s->pressure1; -		} else { -			/* Remember reported pressure */ -			s->pressure0 = data[6]; -			s->pressure1 = data[7]; +			/* Report zero pressure */ +			data[6] = 0; +			data[7] = 0;  		}  	} +	/* If this is a pen input report of Sirius Battery Free Tablet */ +	if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET && +	    report->type == HID_INPUT_REPORT && +	    report->id == 16 && +	    size == 10) { +		/* +		 * The tablet reports tilt as roughly sin(a)*21 (18 means 60 +		 * degrees). +		 * +		 * This array stores angles as radians * 100, corresponding to +		 * reported values up to 60 degrees, as expected by userspace. +		 */ +		static const s8 tilt_to_radians[] = { +			0, 5, 10, 14, 19, 24, 29, 34, 40, 45, +			50, 56, 62, 68, 74, 81, 88, 96, 105 +		}; + +		s8 tilt_x = (s8)data[8]; +		s8 tilt_y = (s8)data[9]; +		s8 sign_x = tilt_x >= 0 ? 1 : -1; +		s8 sign_y = tilt_y >= 0 ? 1 : -1; + +		tilt_x *= sign_x; +		tilt_y *= sign_y; + +		/* +		 * Reverse the Y Tilt direction to match the HID standard and +		 * userspace expectations. See HID Usage Tables v1.12 16.3.2 +		 * Tilt Orientation. +		 */ +		sign_y *= -1; + +		/* +		 * This effectively clamps reported tilt to 60 degrees - the +		 * range expected by userspace +		 */ +		if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1) +			tilt_x = ARRAY_SIZE(tilt_to_radians) - 1; +		if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1) +			tilt_y = ARRAY_SIZE(tilt_to_radians) - 1; + +		data[8] = tilt_to_radians[tilt_x] * sign_x; +		data[9] = tilt_to_radians[tilt_y] * sign_y; +	} +  	return 0;  }  static void waltop_remove(struct hid_device *hdev)  { -	struct waltop_state *s = hid_get_drvdata(hdev); -  	hid_hw_stop(hdev); -	kfree(s);  }  static const struct hid_device_id waltop_devices[] = { @@ -638,6 +794,8 @@ static const struct hid_device_id waltop_devices[] = {  				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,  				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, +			 USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },  	{ }  };  MODULE_DEVICE_TABLE(hid, waltop_devices); diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index cac3589b1ed..84e2fbec5fb 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -769,7 +769,7 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,  	/*  	 * Basic IR data is encoded into 3 bytes. The first two bytes are the -	 * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits +	 * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits  	 * of both.  	 * If data is packed, then the 3rd byte is put first and slightly  	 * reordered. This allows to interleave packed and non-packed data to @@ -778,17 +778,11 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,  	 */  	if (packed) { -		x = ir[1] << 2; -		y = ir[2] << 2; - -		x |= ir[0] & 0x3; -		y |= (ir[0] >> 2) & 0x3; +		x = ir[1] | ((ir[0] & 0x03) << 8); +		y = ir[2] | ((ir[0] & 0x0c) << 6);  	} else { -		x = ir[0] << 2; -		y = ir[1] << 2; - -		x |= (ir[2] >> 4) & 0x3; -		y |= (ir[2] >> 6) & 0x3; +		x = ir[0] | ((ir[2] & 0x30) << 4); +		y = ir[1] | ((ir[2] & 0xc0) << 2);  	}  	input_report_abs(wdata->ir, xid, x); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 782c63955f2..0597ee604f6 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -88,6 +88,7 @@ static const struct hid_blacklist {  	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },  	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },  	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT }, +	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },  	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },  	{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },  |