diff options
Diffstat (limited to 'drivers/hid')
| -rw-r--r-- | drivers/hid/Kconfig | 36 | ||||
| -rw-r--r-- | drivers/hid/Makefile | 3 | ||||
| -rw-r--r-- | drivers/hid/hid-apple.c | 5 | ||||
| -rw-r--r-- | drivers/hid/hid-aureal.c | 54 | ||||
| -rw-r--r-- | drivers/hid/hid-core.c | 316 | ||||
| -rw-r--r-- | drivers/hid/hid-generic.c | 53 | ||||
| -rw-r--r-- | drivers/hid/hid-hyperv.c | 15 | ||||
| -rw-r--r-- | drivers/hid/hid-ids.h | 8 | ||||
| -rw-r--r-- | drivers/hid/hid-input.c | 36 | ||||
| -rw-r--r-- | drivers/hid/hid-lg.c | 55 | ||||
| -rw-r--r-- | drivers/hid/hid-lg.h | 5 | ||||
| -rw-r--r-- | drivers/hid/hid-lg4ff.c | 258 | ||||
| -rw-r--r-- | drivers/hid/hid-logitech-dj.c | 76 | ||||
| -rw-r--r-- | drivers/hid/hid-multitouch.c | 233 | ||||
| -rw-r--r-- | drivers/hid/hid-uclogic.c | 141 | ||||
| -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/hidraw.c | 19 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-core.c | 146 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hiddev.c | 9 | ||||
| -rw-r--r-- | drivers/hid/usbhid/usbhid.h | 1 | ||||
| -rw-r--r-- | drivers/hid/usbhid/usbmouse.c | 7 | 
24 files changed, 1494 insertions, 531 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index ffddcba32af..034c80a10f1 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" @@ -60,6 +64,18 @@ source "drivers/hid/usbhid/Kconfig"  menu "Special HID drivers"  	depends on HID +config HID_GENERIC +	tristate "Generic HID driver" +	depends on HID +	default y +	---help--- +	Support for generic HID devices. + +	To compile this driver as a module, choose M here: the module +	will be called hid-generic. + +	If unsure, say Y. +  config HID_A4TECH  	tristate "A4 tech mice" if EXPERT  	depends on USB_HID @@ -92,6 +108,12 @@ config HID_APPLE  	Say Y here if you want support for keyboards of	Apple iBooks, PowerBooks,  	MacBooks, MacBook Pros and Apple Aluminum. +config HID_AUREAL +	tristate "Aureal" +	depends on USB_HID +	---help--- +	Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes. +  config HID_BELKIN  	tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT  	depends on USB_HID @@ -448,7 +470,7 @@ config HID_PICOLCD_FB  	select FB_SYS_FOPS  	---help---  	  Provide access to PicoLCD's 256x64 monochrome display via a -	  frambuffer device. +	  framebuffer device.  config HID_PICOLCD_BACKLIGHT  	bool "Backlight control" if EXPERT @@ -595,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/Makefile b/drivers/hid/Makefile index 22f1d16cd79..ca6cc9f0485 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -9,6 +9,8 @@ endif  obj-$(CONFIG_HID)		+= hid.o +obj-$(CONFIG_HID_GENERIC)	+= hid-generic.o +  hid-$(CONFIG_HIDRAW)		+= hidraw.o  hid-logitech-y		:= hid-lg.o @@ -36,6 +38,7 @@ endif  obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o  obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o  obj-$(CONFIG_HID_APPLE)		+= hid-apple.o +obj-$(CONFIG_HID_AUREAL)        += hid-aureal.o  obj-$(CONFIG_HID_BELKIN)	+= hid-belkin.o  obj-$(CONFIG_HID_CHERRY)	+= hid-cherry.o  obj-$(CONFIG_HID_CHICONY)	+= hid-chicony.o diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 299d2387112..fa10f847f7d 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,  		}  	} -        if (iso_layout) { +	if (iso_layout) {  		if (asc->quirks & APPLE_ISO_KEYBOARD) {  			trans = apple_find_translation(apple_iso_keyboard, usage->code);  			if (trans) { @@ -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-aureal.c b/drivers/hid/hid-aureal.c new file mode 100644 index 00000000000..ba64b041b8b --- /dev/null +++ b/drivers/hid/hid-aureal.c @@ -0,0 +1,54 @@ +/* + *  HID driver for Aureal Cy se W-01RN USB_V3.1 devices + * + *  Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com> + *  Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net> + * + *  Based on HID sunplus driver by + *  Copyright (c) 1999 Andreas Gal + *  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 + */ +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> + +#include "hid-ids.h" + +static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc, +		unsigned int *rsize) +{ +	if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) { +		dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n"); +		rdesc[53] = 0x65; +	} return rdesc; +} + +static const struct hid_device_id aureal_devices[] = { +	{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, +	{ } +}; +MODULE_DEVICE_TABLE(hid, aureal_devices); + +static struct hid_driver aureal_driver = { +	.name = "aureal", +	.id_table = aureal_devices, +	.report_fixup = aureal_report_fixup, +}; + +static int __init aureal_init(void) +{ +	return hid_register_driver(&aureal_driver); +} + +static void __exit aureal_exit(void) +{ +	hid_unregister_driver(&aureal_driver); +} + +module_init(aureal_init); +module_exit(aureal_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4da66b4b977..8e3a6b26147 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign  		return -1;  	} -	if (parser->global.logical_maximum < parser->global.logical_minimum) { -		hid_err(parser->device, "logical range invalid %d %d\n", -				parser->global.logical_minimum, parser->global.logical_maximum); +	/* Handle both signed and unsigned cases properly */ +	if ((parser->global.logical_minimum < 0 && +		parser->global.logical_maximum < +		parser->global.logical_minimum) || +		(parser->global.logical_minimum >= 0 && +		(__u32)parser->global.logical_maximum < +		(__u32)parser->global.logical_minimum)) { +		dbg_hid("logical range invalid 0x%x 0x%x\n", +			parser->global.logical_minimum, +			parser->global.logical_maximum);  		return -1;  	} @@ -546,12 +553,11 @@ static void hid_free_report(struct hid_report *report)  }  /* - * Free a device structure, all reports, and all fields. + * Close report. This function returns the device + * state to the point prior to hid_open_report().   */ - -static void hid_device_release(struct device *dev) +static void hid_close_report(struct hid_device *device)  { -	struct hid_device *device = container_of(dev, struct hid_device, dev);  	unsigned i, j;  	for (i = 0; i < HID_REPORT_TYPES; i++) { @@ -562,11 +568,34 @@ static void hid_device_release(struct device *dev)  			if (report)  				hid_free_report(report);  		} +		memset(report_enum, 0, sizeof(*report_enum)); +		INIT_LIST_HEAD(&report_enum->report_list);  	}  	kfree(device->rdesc); +	device->rdesc = NULL; +	device->rsize = 0; +  	kfree(device->collection); -	kfree(device); +	device->collection = NULL; +	device->collection_size = 0; +	device->maxcollection = 0; +	device->maxapplication = 0; + +	device->status &= ~HID_STAT_PARSED; +} + +/* + * Free a device structure, all reports, and all fields. + */ + +static void hid_device_release(struct device *dev) +{ +	struct hid_device *hid = container_of(dev, struct hid_device, dev); + +	hid_close_report(hid); +	kfree(hid->dev_rdesc); +	kfree(hid);  }  /* @@ -636,6 +665,60 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)  	return NULL;  } +static void hid_scan_usage(struct hid_device *hid, u32 usage) +{ +	if (usage == HID_DG_CONTACTID) +		hid->group = HID_GROUP_MULTITOUCH; +} + +/* + * Scan a report descriptor before the device is added to the bus. + * Sets device groups and other properties that determine what driver + * to load. + */ +static int hid_scan_report(struct hid_device *hid) +{ +	unsigned int page = 0, delim = 0; +	__u8 *start = hid->dev_rdesc; +	__u8 *end = start + hid->dev_rsize; +	unsigned int u, u_min = 0, u_max = 0; +	struct hid_item item; + +	hid->group = HID_GROUP_GENERIC; +	while ((start = fetch_item(start, end, &item)) != NULL) { +		if (item.format != HID_ITEM_FORMAT_SHORT) +			return -EINVAL; +		if (item.type == HID_ITEM_TYPE_GLOBAL) { +			if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE) +				page = item_udata(&item) << 16; +		} else if (item.type == HID_ITEM_TYPE_LOCAL) { +			if (delim > 1) +				break; +			u = item_udata(&item); +			if (item.size <= 2) +				u += page; +			switch (item.tag) { +			case HID_LOCAL_ITEM_TAG_DELIMITER: +				delim += !!u; +				break; +			case HID_LOCAL_ITEM_TAG_USAGE: +				hid_scan_usage(hid, u); +				break; +			case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: +				u_min = u; +				break; +			case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: +				u_max = u; +				for (u = u_min; u <= u_max; u++) +					hid_scan_usage(hid, u); +				break; +			} +		} +	} + +	return 0; +} +  /**   * hid_parse_report - parse device report   * @@ -643,15 +726,37 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)   * @start: report start   * @size: report size   * + * Allocate the device report as read by the bus driver. This function should + * only be called from parse() in ll drivers. + */ +int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size) +{ +	hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL); +	if (!hid->dev_rdesc) +		return -ENOMEM; +	hid->dev_rsize = size; +	return 0; +} +EXPORT_SYMBOL_GPL(hid_parse_report); + +/** + * hid_open_report - open a driver-specific device report + * + * @device: hid device + *   * Parse a report description into a hid_device structure. Reports are   * enumerated, fields are attached to these reports.   * 0 returned on success, otherwise nonzero error value. + * + * This function (or the equivalent hid_parse() macro) should only be + * called from probe() in drivers, before starting the device.   */ -int hid_parse_report(struct hid_device *device, __u8 *start, -		unsigned size) +int hid_open_report(struct hid_device *device)  {  	struct hid_parser *parser;  	struct hid_item item; +	unsigned int size; +	__u8 *start;  	__u8 *end;  	int ret;  	static int (*dispatch_type[])(struct hid_parser *parser, @@ -662,6 +767,14 @@ int hid_parse_report(struct hid_device *device, __u8 *start,  		hid_parser_reserved  	}; +	if (WARN_ON(device->status & HID_STAT_PARSED)) +		return -EBUSY; + +	start = device->dev_rdesc; +	if (WARN_ON(!start)) +		return -ENODEV; +	size = device->dev_rsize; +  	if (device->driver->report_fixup)  		start = device->driver->report_fixup(device, start, &size); @@ -679,6 +792,15 @@ int hid_parse_report(struct hid_device *device, __u8 *start,  	parser->device = device;  	end = start + size; + +	device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS, +				     sizeof(struct hid_collection), GFP_KERNEL); +	if (!device->collection) { +		ret = -ENOMEM; +		goto err; +	} +	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; +  	ret = -EINVAL;  	while ((start = fetch_item(start, end, &item)) != NULL) { @@ -704,6 +826,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start,  				goto err;  			}  			vfree(parser); +			device->status |= HID_STAT_PARSED;  			return 0;  		}  	} @@ -711,9 +834,10 @@ int hid_parse_report(struct hid_device *device, __u8 *start,  	hid_err(device, "item fetching failed at offset %d\n", (int)(end - start));  err:  	vfree(parser); +	hid_close_report(device);  	return ret;  } -EXPORT_SYMBOL_GPL(hid_parse_report); +EXPORT_SYMBOL_GPL(hid_open_report);  /*   * Convert a signed n-bit integer to signed 32-bit integer. Common @@ -1032,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,  	return report;  } -void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,  		int interrupt)  {  	struct hid_report_enum *report_enum = hid->report_enum + type; @@ -1040,10 +1164,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,  	unsigned int a;  	int rsize, csize = size;  	u8 *cdata = data; +	int ret = 0;  	report = hid_get_report(report_enum, data);  	if (!report) -		return; +		goto out;  	if (report_enum->numbered) {  		cdata++; @@ -1063,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,  	if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)  		hid->hiddev_report_event(hid, report); -	if (hid->claimed & HID_CLAIMED_HIDRAW) -		hidraw_report_event(hid, data, size); +	if (hid->claimed & HID_CLAIMED_HIDRAW) { +		ret = hidraw_report_event(hid, data, size); +		if (ret) +			goto out; +	}  	for (a = 0; a < report->maxfield; a++)  		hid_input_field(hid, report->field[a], cdata, interrupt);  	if (hid->claimed & HID_CLAIMED_INPUT)  		hidinput_report_event(hid, report); +out: +	return ret;  }  EXPORT_SYMBOL_GPL(hid_report_raw_event); @@ -1147,7 +1277,7 @@ nomem:  		}  	} -	hid_report_raw_event(hid, type, data, size, interrupt); +	ret = hid_report_raw_event(hid, type, data, size, interrupt);  unlock:  	up(&hid->driver_lock); @@ -1158,7 +1288,8 @@ EXPORT_SYMBOL_GPL(hid_input_report);  static bool hid_match_one_id(struct hid_device *hdev,  		const struct hid_device_id *id)  { -	return id->bus == hdev->bus && +	return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) && +		(id->group == HID_GROUP_ANY || id->group == hdev->group) &&  		(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&  		(id->product == HID_ANY_ID || id->product == hdev->product);  } @@ -1234,10 +1365,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)  	if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,  				connect_mask & HID_CONNECT_HIDINPUT_FORCE))  		hdev->claimed |= HID_CLAIMED_INPUT; -	if (hdev->quirks & HID_QUIRK_MULTITOUCH) { -		/* this device should be handled by hid-multitouch, skip it */ -		return -ENODEV; -	}  	if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&  			!hdev->hiddev_connect(hdev, @@ -1314,13 +1441,10 @@ EXPORT_SYMBOL_GPL(hid_disconnect);  /* a list of devices for which there is a specialized driver on HID bus */  static const struct hid_device_id hid_have_special_driver[] = { -	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, @@ -1385,60 +1509,33 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, +	{ 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_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_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, -	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL, USB_DEVICE_ID_GAMETEL_MT_MODE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, - 	{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, @@ -1447,7 +1544,6 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, @@ -1480,8 +1576,6 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, @@ -1513,15 +1607,8 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT780) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT880) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, @@ -1538,9 +1625,6 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, @@ -1554,16 +1638,13 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, @@ -1578,16 +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_XAT, USB_DEVICE_ID_XAT_CSR) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX1) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX1) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR1) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX2) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX2) }, -	{ HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, +	{ 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) }, @@ -1631,6 +1703,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,  		return -ENOMEM;  	dynid->id.bus = bus; +	dynid->id.group = HID_GROUP_ANY;  	dynid->id.vendor = vendor;  	dynid->id.product = product;  	dynid->id.driver_data = driver_data; @@ -1679,18 +1752,7 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)  	struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);  	struct hid_device *hdev = container_of(dev, struct hid_device, dev); -	if ((hdev->quirks & HID_QUIRK_MULTITOUCH) && -		!strncmp(hdrv->name, "hid-multitouch", 14)) -		return 1; - -	if (!hid_match_device(hdev, hdrv)) -		return 0; - -	/* generic wants all that don't have specialized driver */ -	if (!strncmp(hdrv->name, "generic-", 8) && !hid_ignore_special_drivers) -		return !hid_match_id(hdev, hid_have_special_driver); - -	return 1; +	return hid_match_device(hdev, hdrv) != NULL;  }  static int hid_device_probe(struct device *dev) @@ -1707,23 +1769,22 @@ static int hid_device_probe(struct device *dev)  	if (!hdev->driver) {  		id = hid_match_device(hdev, hdrv);  		if (id == NULL) { -			if (!((hdev->quirks & HID_QUIRK_MULTITOUCH) && -				!strncmp(hdrv->name, "hid-multitouch", 14))) { -				ret = -ENODEV; -				goto unlock; -			} +			ret = -ENODEV; +			goto unlock;  		}  		hdev->driver = hdrv;  		if (hdrv->probe) {  			ret = hdrv->probe(hdev, id);  		} else { /* default probe */ -			ret = hid_parse(hdev); +			ret = hid_open_report(hdev);  			if (!ret)  				ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);  		} -		if (ret) +		if (ret) { +			hid_close_report(hdev);  			hdev->driver = NULL; +		}  	}  unlock:  	up(&hdev->driver_lock); @@ -1744,6 +1805,7 @@ static int hid_device_remove(struct device *dev)  			hdrv->remove(hdev);  		else /* default remove */  			hid_hw_stop(hdev); +		hid_close_report(hdev);  		hdev->driver = NULL;  	} @@ -1751,6 +1813,23 @@ static int hid_device_remove(struct device *dev)  	return 0;  } +static ssize_t modalias_show(struct device *dev, struct device_attribute *a, +			     char *buf) +{ +	struct hid_device *hdev = container_of(dev, struct hid_device, dev); +	int len; + +	len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n", +		       hdev->bus, hdev->group, hdev->vendor, hdev->product); + +	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} + +static struct device_attribute hid_dev_attrs[] = { +	__ATTR_RO(modalias), +	__ATTR_NULL, +}; +  static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)  {  	struct hid_device *hdev = container_of(dev, struct hid_device, dev); @@ -1768,8 +1847,8 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)  	if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))  		return -ENOMEM; -	if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X", -			hdev->bus, hdev->vendor, hdev->product)) +	if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X", +			   hdev->bus, hdev->group, hdev->vendor, hdev->product))  		return -ENOMEM;  	return 0; @@ -1777,6 +1856,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)  static struct bus_type hid_bus_type = {  	.name		= "hid", +	.dev_attrs	= hid_dev_attrs,  	.match		= hid_bus_match,  	.probe		= hid_device_probe,  	.remove		= hid_device_remove, @@ -2075,6 +2155,26 @@ int hid_add_device(struct hid_device *hdev)              && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))  		return -ENODEV; +	/* +	 * Read the device report descriptor once and use as template +	 * for the driver-specific modifications. +	 */ +	ret = hdev->ll_driver->parse(hdev); +	if (ret) +		return ret; +	if (!hdev->dev_rdesc) +		return -ENODEV; + +	/* +	 * Scan generic devices for group information +	 */ +	if (hid_ignore_special_drivers || +	    !hid_match_id(hdev, hid_have_special_driver)) { +		ret = hid_scan_report(hdev); +		if (ret) +			hid_warn(hdev, "bad device descriptor (%d)\n", ret); +	} +  	/* XXX hack, any other cleaner solution after the driver core  	 * is converted to allow more than 20 bytes as the device name? */  	dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, @@ -2103,7 +2203,6 @@ EXPORT_SYMBOL_GPL(hid_add_device);  struct hid_device *hid_allocate_device(void)  {  	struct hid_device *hdev; -	unsigned int i;  	int ret = -ENOMEM;  	hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); @@ -2114,23 +2213,13 @@ struct hid_device *hid_allocate_device(void)  	hdev->dev.release = hid_device_release;  	hdev->dev.bus = &hid_bus_type; -	hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS, -			sizeof(struct hid_collection), GFP_KERNEL); -	if (hdev->collection == NULL) -		goto err; -	hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS; - -	for (i = 0; i < HID_REPORT_TYPES; i++) -		INIT_LIST_HEAD(&hdev->report_enum[i].report_list); +	hid_close_report(hdev);  	init_waitqueue_head(&hdev->debug_wait);  	INIT_LIST_HEAD(&hdev->debug_list);  	sema_init(&hdev->driver_lock, 1);  	return hdev; -err: -	put_device(&hdev->dev); -	return ERR_PTR(ret);  }  EXPORT_SYMBOL_GPL(hid_allocate_device); @@ -2141,6 +2230,9 @@ static void hid_remove_device(struct hid_device *hdev)  		hid_debug_unregister(hdev);  		hdev->status &= ~HID_STAT_ADDED;  	} +	kfree(hdev->dev_rdesc); +	hdev->dev_rdesc = NULL; +	hdev->dev_rsize = 0;  }  /** diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c new file mode 100644 index 00000000000..a8b3148e03a --- /dev/null +++ b/drivers/hid/hid-generic.c @@ -0,0 +1,53 @@ +/* + *  HID support for Linux + * + *  Copyright (c) 1999 Andreas Gal + *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> + *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc + *  Copyright (c) 2007-2008 Oliver Neukum + *  Copyright (c) 2006-2012 Jiri Kosina + *  Copyright (c) 2012 Henrik Rydberg + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <asm/unaligned.h> +#include <asm/byteorder.h> + +#include <linux/hid.h> + +static const struct hid_device_id hid_table[] = { +	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) }, +	{ } +}; +MODULE_DEVICE_TABLE(hid, hid_table); + +static struct hid_driver hid_generic = { +	.name = "hid-generic", +	.id_table = hid_table, +}; + +static int __init hid_init(void) +{ +	return hid_register_driver(&hid_generic); +} + +static void __exit hid_exit(void) +{ +	hid_unregister_driver(&hid_generic); +} + +module_init(hid_init); +module_exit(hid_exit); + +MODULE_AUTHOR("Henrik Rydberg"); +MODULE_DESCRIPTION("HID generic driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 406632472c1..3d62781b899 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -430,6 +430,15 @@ cleanup:  	return ret;  } +static int mousevsc_hid_parse(struct hid_device *hid) +{ +	struct hv_device *dev = hid_get_drvdata(hid); +	struct mousevsc_dev *input_dev = hv_get_drvdata(dev); + +	return hid_parse_report(hid, input_dev->report_desc, +				input_dev->report_desc_size); +} +  static int mousevsc_hid_open(struct hid_device *hid)  {  	return 0; @@ -449,6 +458,7 @@ static void mousevsc_hid_stop(struct hid_device *hid)  }  static struct hid_ll_driver mousevsc_ll_driver = { +	.parse = mousevsc_hid_parse,  	.open = mousevsc_hid_open,  	.close = mousevsc_hid_close,  	.start = mousevsc_hid_start, @@ -506,13 +516,14 @@ static int mousevsc_probe(struct hv_device *device,  	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); +	hid_set_drvdata(hid_dev, device); +  	ret = hid_add_device(hid_dev);  	if (ret)  		goto probe_err1; -	ret = hid_parse_report(hid_dev, input_dev->report_desc, -				input_dev->report_desc_size); +	ret = hid_parse(hid_dev);  	if (ret) {  		hid_err(hid_dev, "parse failed\n");  		goto probe_err2; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e39aecb1f9f..9373f535dfe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -154,9 +154,15 @@  #define USB_DEVICE_ID_ATMEL_MULTITOUCH	0x211c  #define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER	0x2118 +#define USB_VENDOR_ID_AUREAL		0x0755 +#define USB_DEVICE_ID_AUREAL_W01RN	0x2626 +  #define USB_VENDOR_ID_AVERMEDIA		0x07ca  #define USB_DEVICE_ID_AVER_FM_MR800	0xb800 +#define USB_VENDOR_ID_BAANTO		0x2453 +#define USB_DEVICE_ID_BAANTO_MT_190W2	0x0100 +  #define USB_VENDOR_ID_BELKIN		0x050d  #define USB_DEVICE_ID_FLIP_KVM		0x3201 @@ -726,6 +732,7 @@  #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U	0x0004  #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U	0x0005  #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062	0x0064 +#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850	0x0522  #define USB_VENDOR_ID_UNITEC	0x227d  #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709	0x0709 @@ -749,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 002781c5a61..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 */ @@ -638,10 +657,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel  			map_key_clear(BTN_STYLUS2);  			break; -		case 0x51: /* ContactID */ -			device->quirks |= HID_QUIRK_MULTITOUCH; -			goto unknown; -  		default:  goto unknown;  		}  		break; @@ -1208,13 +1223,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)  		}  	} -	if (hid->quirks & HID_QUIRK_MULTITOUCH) { -		/* generic hid does not know how to handle multitouch devices */ -		if (hidinput) -			goto out_cleanup; -		goto out_unwind; -	} -  	if (hidinput && input_register_device(hidinput->input))  		goto out_cleanup; diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index e7a7bd1eb34..fc37ed6b108 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = {  static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,  		unsigned int *rsize)  { -	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); -	if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && +	if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&  			rdesc[84] == 0x8c && rdesc[85] == 0x02) {  		hid_info(hdev,  			 "fixing up Logitech keyboard report descriptor\n");  		rdesc[84] = rdesc[89] = 0x4d;  		rdesc[85] = rdesc[90] = 0x10;  	} -	if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && +	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&  			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&  			rdesc[49] == 0x81 && rdesc[50] == 0x06) {  		hid_info(hdev,  			 "fixing up rel/abs in Logitech report descriptor\n");  		rdesc[33] = rdesc[50] = 0x02;  	} -	if ((quirks & LG_FF4) && *rsize >= 101 && +	if ((drv_data->quirks & LG_FF4) && *rsize >= 101 &&  			rdesc[41] == 0x95 && rdesc[42] == 0x0B &&  			rdesc[47] == 0x05 && rdesc[48] == 0x09) {  		hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n"); @@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,  		  0,  0,  0,  0,  0,183,184,185,186,187,  		188,189,190,191,192,193,194,  0,  0,  0  	}; -	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);  	unsigned int hid = usage->hid;  	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && @@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,  			lg_dinovo_mapping(hi, usage, bit, max))  		return 1; -	if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) +	if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))  		return 1;  	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) @@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,  	/* Special handling for Logitech Cordless Desktop */  	if (field->application == HID_GD_MOUSE) { -		if ((quirks & LG_IGNORE_DOUBLED_WHEEL) && +		if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&  				(hid == 7 || hid == 8))  			return -1;  	} else { -		if ((quirks & LG_EXPANDED_KEYMAP) && +		if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&  				hid < ARRAY_SIZE(e_keymap) &&  				e_keymap[hid] != 0) {  			hid_map_usage(hi, usage, bit, max, EV_KEY, @@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,  		struct hid_field *field, struct hid_usage *usage,  		unsigned long **bit, int *max)  { -	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); -	if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && +	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&  			(field->flags & HID_MAIN_ITEM_RELATIVE))  		field->flags &= ~HID_MAIN_ITEM_RELATIVE; -	if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || +	if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||  			 usage->type == EV_REL || usage->type == EV_ABS))  		clear_bit(usage->code, *bit); @@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,  static int lg_event(struct hid_device *hdev, struct hid_field *field,  		struct hid_usage *usage, __s32 value)  { -	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); -	if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { +	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {  		input_event(field->hidinput->input, usage->type, usage->code,  				-value);  		return 1; @@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,  static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)  { -	unsigned long quirks = id->driver_data;  	unsigned int connect_mask = HID_CONNECT_DEFAULT; +	struct lg_drv_data *drv_data;  	int ret; -	hid_set_drvdata(hdev, (void *)quirks); +	drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL); +	if (!drv_data) { +		hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); +		return -ENOMEM; +	} +	drv_data->quirks = id->driver_data; +	 +	hid_set_drvdata(hdev, (void *)drv_data); -	if (quirks & LG_NOGET) +	if (drv_data->quirks & LG_NOGET)  		hdev->quirks |= HID_QUIRK_NOGET;  	ret = hid_parse(hdev); @@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)  		goto err_free;  	} -	if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) +	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))  		connect_mask &= ~HID_CONNECT_FF;  	ret = hid_hw_start(hdev, connect_mask); @@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)  		}  	} -	if (quirks & LG_FF) +	if (drv_data->quirks & LG_FF)  		lgff_init(hdev); -	if (quirks & LG_FF2) +	if (drv_data->quirks & LG_FF2)  		lg2ff_init(hdev); -	if (quirks & LG_FF3) +	if (drv_data->quirks & LG_FF3)  		lg3ff_init(hdev); -	if (quirks & LG_FF4) +	if (drv_data->quirks & LG_FF4)  		lg4ff_init(hdev);  	return 0;  err_free: +	kfree(drv_data);  	return ret;  }  static void lg_remove(struct hid_device *hdev)  { -	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); -	if(quirks & LG_FF4) +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); +	if (drv_data->quirks & LG_FF4)  		lg4ff_deinit(hdev);  	hid_hw_stop(hdev); +	kfree(drv_data);  }  static const struct hid_device_id lg_devices[] = { diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h index 4b097286dc7..d64cf8d2751 100644 --- a/drivers/hid/hid-lg.h +++ b/drivers/hid/hid-lg.h @@ -1,6 +1,11 @@  #ifndef __HID_LG_H  #define __HID_LG_H +struct lg_drv_data { +	unsigned long quirks; +	void *device_props;	/* Device specific properties */ +}; +  #ifdef CONFIG_LOGITECH_FF  int lgff_init(struct hid_device *hdev);  #else diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 6ecc9e22044..f3390ee6105 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1,7 +1,8 @@  /* - *  Force feedback support for Logitech Speed Force Wireless + *  Force feedback support for Logitech Gaming Wheels   * - *  http://wiibrew.org/wiki/Logitech_USB_steering_wheel + *  Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 & + *  Speed Force Wireless (WiiWheel)   *   *  Copyright (c) 2010 Simon Wood <simon@mungewell.org>   */ @@ -51,20 +52,18 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at  static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); -static bool list_inited; -  struct lg4ff_device_entry { -	char  *device_id;	/* Use name in respective kobject structure's address as the ID */  	__u16 range;  	__u16 min_range;  	__u16 max_range; -	__u8  leds; +#ifdef CONFIG_LEDS_CLASS +	__u8  led_state; +	struct led_classdev *led[5]; +#endif  	struct list_head list;  	void (*set_range)(struct hid_device *hid, u16 range);  }; -static struct lg4ff_device_entry device_list; -  static const signed short lg4ff_wheel_effects[] = {  	FF_CONSTANT,  	FF_AUTOCENTER, @@ -285,18 +284,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n  /* Read current range and display it in terminal */  static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)  { -	struct lg4ff_device_entry *uninitialized_var(entry); -	struct list_head *h;  	struct hid_device *hid = to_hid_device(dev); +	struct lg4ff_device_entry *entry; +	struct lg_drv_data *drv_data;  	size_t count; -	list_for_each(h, &device_list.list) { -		entry = list_entry(h, struct lg4ff_device_entry, list); -		if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) -			break; +	drv_data = hid_get_drvdata(hid); +	if (!drv_data) { +		hid_err(hid, "Private driver data not found!\n"); +		return 0;  	} -	if (h == &device_list.list) { -		dbg_hid("Device not found!"); + +	entry = drv_data->device_props; +	if (!entry) { +		hid_err(hid, "Device properties not found!\n");  		return 0;  	} @@ -308,19 +309,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att   * according to the type of the wheel */  static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)  { -	struct lg4ff_device_entry *uninitialized_var(entry); -	struct list_head *h;  	struct hid_device *hid = to_hid_device(dev); +	struct lg4ff_device_entry *entry; +	struct lg_drv_data *drv_data;  	__u16 range = simple_strtoul(buf, NULL, 10); -	list_for_each(h, &device_list.list) { -		entry = list_entry(h, struct lg4ff_device_entry, list); -		if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) -			break; +	drv_data = hid_get_drvdata(hid); +	if (!drv_data) { +		hid_err(hid, "Private driver data not found!\n"); +		return 0;  	} -	if (h == &device_list.list) { -		dbg_hid("Device not found!"); -		return count; + +	entry = drv_data->device_props; +	if (!entry) { +		hid_err(hid, "Device properties not found!\n"); +		return 0;  	}  	if (range == 0) @@ -336,6 +339,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at  	return count;  } +#ifdef CONFIG_LEDS_CLASS +static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) +{ +	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; +	struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + +	report->field[0]->value[0] = 0xf8; +	report->field[0]->value[1] = 0x12; +	report->field[0]->value[2] = leds; +	report->field[0]->value[3] = 0x00; +	report->field[0]->value[4] = 0x00; +	report->field[0]->value[5] = 0x00; +	report->field[0]->value[6] = 0x00; +	usbhid_submit_report(hid, report, USB_DIR_OUT); +} + +static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, +			enum led_brightness value) +{ +	struct device *dev = led_cdev->dev->parent; +	struct hid_device *hid = container_of(dev, struct hid_device, dev); +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); +	struct lg4ff_device_entry *entry; +	int i, state = 0; + +	if (!drv_data) { +		hid_err(hid, "Device data not found."); +		return; +	} + +	entry = (struct lg4ff_device_entry *)drv_data->device_props; + +	if (!entry) { +		hid_err(hid, "Device properties not found."); +		return; +	} + +	for (i = 0; i < 5; i++) { +		if (led_cdev != entry->led[i]) +			continue; +		state = (entry->led_state >> i) & 1; +		if (value == LED_OFF && state) { +			entry->led_state &= ~(1 << i); +			lg4ff_set_leds(hid, entry->led_state); +		} else if (value != LED_OFF && !state) { +			entry->led_state |= 1 << i; +			lg4ff_set_leds(hid, entry->led_state); +		} +		break; +	} +} + +static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev) +{ +	struct device *dev = led_cdev->dev->parent; +	struct hid_device *hid = container_of(dev, struct hid_device, dev); +	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); +	struct lg4ff_device_entry *entry; +	int i, value = 0; + +	if (!drv_data) { +		hid_err(hid, "Device data not found."); +		return LED_OFF; +	} + +	entry = (struct lg4ff_device_entry *)drv_data->device_props; + +	if (!entry) { +		hid_err(hid, "Device properties not found."); +		return LED_OFF; +	} + +	for (i = 0; i < 5; i++) +		if (led_cdev == entry->led[i]) { +			value = (entry->led_state >> i) & 1; +			break; +		} + +	return value ? LED_FULL : LED_OFF; +} +#endif +  int lg4ff_init(struct hid_device *hid)  {  	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); @@ -344,6 +429,7 @@ int lg4ff_init(struct hid_device *hid)  	struct hid_report *report;  	struct hid_field *field;  	struct lg4ff_device_entry *entry; +	struct lg_drv_data *drv_data;  	struct usb_device_descriptor *udesc;  	int error, i, j;  	__u16 bcdDevice, rev_maj, rev_min; @@ -423,28 +509,24 @@ int lg4ff_init(struct hid_device *hid)  		dev->ff->set_autocenter(dev, 0);  	} -		/* Initialize device_list if this is the first device to handle by lg4ff */ -	if (!list_inited) { -		INIT_LIST_HEAD(&device_list.list); -		list_inited = 1; +	/* Get private driver data */ +	drv_data = hid_get_drvdata(hid); +	if (!drv_data) { +		hid_err(hid, "Cannot add device, private driver data not allocated\n"); +		return -1;  	} -	/* Add the device to device_list */ +	/* Initialize device properties */  	entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);  	if (!entry) { -		hid_err(hid, "Cannot add device, insufficient memory.\n"); -		return -ENOMEM; -	} -	entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL); -	if (!entry->device_id) { -		hid_err(hid, "Cannot set device_id, insufficient memory.\n"); -		kfree(entry); +		hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");  		return -ENOMEM;  	} +	drv_data->device_props = entry; +  	entry->min_range = lg4ff_devices[i].min_range;  	entry->max_range = lg4ff_devices[i].max_range;  	entry->set_range = lg4ff_devices[i].set_range; -	list_add(&entry->list, &device_list.list);  	/* Create sysfs interface */  	error = device_create_file(&hid->dev, &dev_attr_range); @@ -457,32 +539,100 @@ int lg4ff_init(struct hid_device *hid)  	if (entry->set_range != NULL)  		entry->set_range(hid, entry->range); -	hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); +#ifdef CONFIG_LEDS_CLASS +	/* register led subsystem - G27 only */ +	entry->led_state = 0; +	for (j = 0; j < 5; j++) +		entry->led[j] = NULL; + +	if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { +		struct led_classdev *led; +		size_t name_sz; +		char *name; + +		lg4ff_set_leds(hid, 0); + +		name_sz = strlen(dev_name(&hid->dev)) + 8; + +		for (j = 0; j < 5; j++) { +			led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); +			if (!led) { +				hid_err(hid, "can't allocate memory for LED %d\n", j); +				goto err; +			} + +			name = (void *)(&led[1]); +			snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1); +			led->name = name; +			led->brightness = 0; +			led->max_brightness = 1; +			led->brightness_get = lg4ff_led_get_brightness; +			led->brightness_set = lg4ff_led_set_brightness; + +			entry->led[j] = led; +			error = led_classdev_register(&hid->dev, led); + +			if (error) { +				hid_err(hid, "failed to register LED %d. Aborting.\n", j); +err: +				/* Deregister LEDs (if any) */ +				for (j = 0; j < 5; j++) { +					led = entry->led[j]; +					entry->led[j] = NULL; +					if (!led) +						continue; +					led_classdev_unregister(led); +					kfree(led); +				} +				goto out;	/* Let the driver continue without LEDs */ +			} +		} +	} +out: +#endif +	hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");  	return 0;  }  int lg4ff_deinit(struct hid_device *hid)  { -	bool found = 0;  	struct lg4ff_device_entry *entry; -	struct list_head *h, *g; -	list_for_each_safe(h, g, &device_list.list) { -		entry = list_entry(h, struct lg4ff_device_entry, list); -		if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) { -			list_del(h); -			kfree(entry->device_id); -			kfree(entry); -			found = 1; -			break; -		} -	} +	struct lg_drv_data *drv_data; + +	device_remove_file(&hid->dev, &dev_attr_range); -	if (!found) { -		dbg_hid("Device entry not found!\n"); +	drv_data = hid_get_drvdata(hid); +	if (!drv_data) { +		hid_err(hid, "Error while deinitializing device, no private driver data.\n"); +		return -1; +	} +	entry = drv_data->device_props; +	if (!entry) { +		hid_err(hid, "Error while deinitializing device, no device properties data.\n");  		return -1;  	} -	device_remove_file(&hid->dev, &dev_attr_range); +#ifdef CONFIG_LEDS_CLASS +	{ +		int j; +		struct led_classdev *led; + +		/* Deregister LEDs (if any) */ +		for (j = 0; j < 5; j++) { + +			led = entry->led[j]; +			entry->led[j] = NULL; +			if (!led) +				continue; +			led_classdev_unregister(led); +			kfree(led); +		} +	} +#endif + +	/* Deallocate memory */ +	kfree(entry); +  	dbg_hid("Device successfully unregistered\n");  	return 0;  } diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 2b56efcbdf6..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" @@ -155,6 +156,14 @@ static const char media_descriptor[] = {  /* Maximum size of all defined hid reports in bytes (including report id) */  #define MAX_REPORT_SIZE 8 +/* Make sure all descriptors are present here */ +#define MAX_RDESC_SIZE				\ +	(sizeof(kbd_descriptor) +		\ +	 sizeof(mse_descriptor) +		\ +	 sizeof(consumer_descriptor) +		\ +	 sizeof(syscontrol_descriptor) +	\ +	 sizeof(media_descriptor)) +  /* Number of possible hid report types that can be created by this driver.   *   * Right now, RF report types have the same report types (or report id's) @@ -265,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; @@ -473,9 +482,17 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,  	return 0;  } +static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size) +{ +	memcpy(*rdesc + *rsize, data, size); +	*rsize += size; +} +  static int logi_dj_ll_parse(struct hid_device *hid)  {  	struct dj_device *djdev = hid->driver_data; +	unsigned int rsize = 0; +	char *rdesc;  	int retval;  	dbg_hid("%s\n", __func__); @@ -483,70 +500,38 @@ static int logi_dj_ll_parse(struct hid_device *hid)  	djdev->hdev->version = 0x0111;  	djdev->hdev->country = 0x00; +	rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL); +	if (!rdesc) +		return -ENOMEM; +  	if (djdev->reports_supported & STD_KEYBOARD) {  		dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",  			__func__, djdev->reports_supported); -		retval = hid_parse_report(hid, -					  (u8 *) kbd_descriptor, -					  sizeof(kbd_descriptor)); -		if (retval) { -			dbg_hid("%s: sending a kbd descriptor, hid_parse failed" -				" error: %d\n", __func__, retval); -			return retval; -		} +		rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));  	}  	if (djdev->reports_supported & STD_MOUSE) {  		dbg_hid("%s: sending a mouse descriptor, reports_supported: "  			"%x\n", __func__, djdev->reports_supported); -		retval = hid_parse_report(hid, -					  (u8 *) mse_descriptor, -					  sizeof(mse_descriptor)); -		if (retval) { -			dbg_hid("%s: sending a mouse descriptor, hid_parse " -				"failed error: %d\n", __func__, retval); -			return retval; -		} +		rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));  	}  	if (djdev->reports_supported & MULTIMEDIA) {  		dbg_hid("%s: sending a multimedia report descriptor: %x\n",  			__func__, djdev->reports_supported); -		retval = hid_parse_report(hid, -					  (u8 *) consumer_descriptor, -					  sizeof(consumer_descriptor)); -		if (retval) { -			dbg_hid("%s: sending a consumer_descriptor, hid_parse " -				"failed error: %d\n", __func__, retval); -			return retval; -		} +		rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));  	}  	if (djdev->reports_supported & POWER_KEYS) {  		dbg_hid("%s: sending a power keys report descriptor: %x\n",  			__func__, djdev->reports_supported); -		retval = hid_parse_report(hid, -					  (u8 *) syscontrol_descriptor, -					  sizeof(syscontrol_descriptor)); -		if (retval) { -			dbg_hid("%s: sending a syscontrol_descriptor, " -				"hid_parse failed error: %d\n", -				__func__, retval); -			return retval; -		} +		rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));  	}  	if (djdev->reports_supported & MEDIA_CENTER) {  		dbg_hid("%s: sending a media center report descriptor: %x\n",  			__func__, djdev->reports_supported); -		retval = hid_parse_report(hid, -					  (u8 *) media_descriptor, -					  sizeof(media_descriptor)); -		if (retval) { -			dbg_hid("%s: sending a media_descriptor, hid_parse " -				"failed error: %d\n", __func__, retval); -			return retval; -		} +		rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));  	}  	if (djdev->reports_supported & KBD_LEDS) { @@ -554,7 +539,10 @@ static int logi_dj_ll_parse(struct hid_device *hid)  			__func__, djdev->reports_supported);  	} -	return 0; +	retval = hid_parse_report(hid, rdesc, rsize); +	kfree(rdesc); + +	return retval;  }  static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 1d5b94167b5..6e3332a9997 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -70,9 +70,16 @@ struct mt_class {  	bool is_indirect;	/* true for touchpads */  }; +struct mt_fields { +	unsigned usages[HID_MAX_FIELDS]; +	unsigned int length; +}; +  struct mt_device {  	struct mt_slot curdata;	/* placeholder of incoming data */  	struct mt_class mtclass;	/* our mt device class */ +	struct mt_fields *fields;	/* temporary placeholder for storing the +					   multitouch fields */  	unsigned last_field_index;	/* last field index of the report */  	unsigned last_slot_field;	/* the last field of a slot */  	__s8 inputmode;		/* InputMode HID feature, -1 if non-existent */ @@ -110,6 +117,9 @@ struct mt_device {  #define MT_DEFAULT_MAXCONTACT	10 +#define MT_USB_DEVICE(v, p)	HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) +#define MT_BT_DEVICE(v, p)	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) +  /*   * these device-dependent functions determine what slot corresponds   * to a valid contact that was just read. @@ -275,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,  	input_set_abs_params(input, code, fmin, fmax, fuzz, 0);  } -static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td, +static void mt_store_field(struct hid_usage *usage, struct mt_device *td,  		struct hid_input *hi)  { -	if (!test_bit(usage->hid, hi->input->absbit)) -		td->last_slot_field = usage->hid; +	struct mt_fields *f = td->fields; + +	if (f->length >= HID_MAX_FIELDS) +		return; + +	f->usages[f->length++] = usage->hid;  }  static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -330,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,  				cls->sn_move);  			/* touchscreen emulation */  			set_abs(hi->input, ABS_X, field, cls->sn_move); -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_GD_Y: @@ -340,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,  				cls->sn_move);  			/* touchscreen emulation */  			set_abs(hi->input, ABS_Y, field, cls->sn_move); -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		} @@ -349,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,  	case HID_UP_DIGITIZER:  		switch (usage->hid) {  		case HID_DG_INRANGE: -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_DG_CONFIDENCE: -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_DG_TIPSWITCH:  			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);  			input_set_capability(hi->input, EV_KEY, BTN_TOUCH); -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_DG_CONTACTID:  			if (!td->maxcontacts)  				td->maxcontacts = MT_DEFAULT_MAXCONTACT;  			input_mt_init_slots(hi->input, td->maxcontacts); -			td->last_slot_field = usage->hid; +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			td->touches_by_report++;  			return 1; @@ -375,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,  					EV_ABS, ABS_MT_TOUCH_MAJOR);  			set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,  				cls->sn_width); -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_DG_HEIGHT: @@ -385,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,  				cls->sn_height);  			input_set_abs_params(hi->input,  					ABS_MT_ORIENTATION, 0, 1, 0, 0); -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_DG_TIPPRESSURE: @@ -396,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,  			/* touchscreen emulation */  			set_abs(hi->input, ABS_PRESSURE, field,  				cls->sn_pressure); -			set_last_slot_field(usage, td, hi); +			mt_store_field(usage, td, hi);  			td->last_field_index = field->index;  			return 1;  		case HID_DG_CONTACTCOUNT: @@ -635,6 +649,31 @@ static void mt_set_maxcontacts(struct hid_device *hdev)  	}  } +static void mt_post_parse_default_settings(struct mt_device *td) +{ +	__s32 quirks = td->mtclass.quirks; + +	/* unknown serial device needs special quirks */ +	if (td->touches_by_report == 1) { +		quirks |= MT_QUIRK_ALWAYS_VALID; +		quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; +		quirks &= ~MT_QUIRK_VALID_IS_INRANGE; +		quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; +	} + +	td->mtclass.quirks = quirks; +} + +static void mt_post_parse(struct mt_device *td) +{ +	struct mt_fields *f = td->fields; + +	if (td->touches_by_report > 0) { +		int field_count_per_touch = f->length / td->touches_by_report; +		td->last_slot_field = f->usages[field_count_per_touch - 1]; +	} +} +  static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)  {  	int ret, i; @@ -654,7 +693,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)  	 * that emit events over several HID messages.  	 */  	hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; -	hdev->quirks &= ~HID_QUIRK_MULTITOUCH;  	td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);  	if (!td) { @@ -666,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)  	td->maxcontact_report_id = -1;  	hid_set_drvdata(hdev, td); +	td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL); +	if (!td->fields) { +		dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); +		ret = -ENOMEM; +		goto fail; +	} +  	ret = hid_parse(hdev);  	if (ret != 0)  		goto fail; @@ -674,14 +719,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)  	if (ret)  		goto fail; -	if (!id && td->touches_by_report == 1) { -		/* the device has been sent by hid-generic */ -		mtclass = &td->mtclass; -		mtclass->quirks |= MT_QUIRK_ALWAYS_VALID; -		mtclass->quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; -		mtclass->quirks &= ~MT_QUIRK_VALID_IS_INRANGE; -		mtclass->quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; -	} +	mt_post_parse(td); + +	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) +		mt_post_parse_default_settings(td);  	td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),  				GFP_KERNEL); @@ -697,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)  	mt_set_maxcontacts(hdev);  	mt_set_input_mode(hdev); +	kfree(td->fields); +	td->fields = NULL; +  	return 0;  fail: +	kfree(td->fields);  	kfree(td);  	return ret;  } @@ -727,50 +772,54 @@ static const struct hid_device_id mt_devices[] = {  	/* 3M panels */  	{ .driver_data = MT_CLS_3M, -		HID_USB_DEVICE(USB_VENDOR_ID_3M, +		MT_USB_DEVICE(USB_VENDOR_ID_3M,  			USB_DEVICE_ID_3M1968) },  	{ .driver_data = MT_CLS_3M, -		HID_USB_DEVICE(USB_VENDOR_ID_3M, +		MT_USB_DEVICE(USB_VENDOR_ID_3M,  			USB_DEVICE_ID_3M2256) },  	{ .driver_data = MT_CLS_3M, -		HID_USB_DEVICE(USB_VENDOR_ID_3M, +		MT_USB_DEVICE(USB_VENDOR_ID_3M,  			USB_DEVICE_ID_3M3266) },  	/* ActionStar panels */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, +		MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,  			USB_DEVICE_ID_ACTIONSTAR_1011) },  	/* Atmel panels */  	{ .driver_data = MT_CLS_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_ATMEL, +		MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,  			USB_DEVICE_ID_ATMEL_MULTITOUCH) },  	{ .driver_data = MT_CLS_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_ATMEL, +		MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,  			USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, +	/* Baanto multitouch devices */ +	{ .driver_data = MT_CLS_DEFAULT, +		MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, +			USB_DEVICE_ID_BAANTO_MT_190W2) },  	/* Cando panels */  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_CANDO, +		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,  			USB_DEVICE_ID_CANDO_MULTI_TOUCH) },  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_CANDO, +		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,  			USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_CANDO, +		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,  			USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_CANDO, +		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,  			USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },  	/* Chunghwa Telecom touch panels */  	{  .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, +		MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,  			USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },  	/* CVTouch panels */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, +		MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,  			USB_DEVICE_ID_CVTOUCH_SCREEN) },  	/* Cypress panel */ @@ -780,225 +829,227 @@ static const struct hid_device_id mt_devices[] = {  	/* eGalax devices (resistive) */  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },  	/* eGalax devices (capacitive) */  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },  	{ .driver_data = MT_CLS_EGALAX, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },  	{ .driver_data = MT_CLS_EGALAX_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_DWAV, +		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,  			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },  	/* Elo TouchSystems IntelliTouch Plus panel */  	{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, -		HID_USB_DEVICE(USB_VENDOR_ID_ELO, +		MT_USB_DEVICE(USB_VENDOR_ID_ELO,  			USB_DEVICE_ID_ELO_TS2515) },  	/* GeneralTouch panel */  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, +		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,  			USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },  	/* Gametel game controller */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL, +		MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,  			USB_DEVICE_ID_GAMETEL_MT_MODE) },  	/* GoodTouch panels */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, +		MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,  			USB_DEVICE_ID_GOODTOUCH_000f) },  	/* Hanvon panels */  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, -		HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, +		MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,  			USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },  	/* Ideacom panel */  	{ .driver_data = MT_CLS_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, +		MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,  			USB_DEVICE_ID_IDEACOM_IDC6650) },  	{ .driver_data = MT_CLS_SERIAL, -		HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, +		MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,  			USB_DEVICE_ID_IDEACOM_IDC6651) },  	/* Ilitek dual touch panel */  	{  .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, +		MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,  			USB_DEVICE_ID_ILITEK_MULTITOUCH) },  	/* IRTOUCH panels */  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, -		HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, +		MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,  			USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },  	/* LG Display panels */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_LG, +		MT_USB_DEVICE(USB_VENDOR_ID_LG,  			USB_DEVICE_ID_LG_MULTITOUCH) },  	/* Lumio panels */  	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, -		HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, +		MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,  			USB_DEVICE_ID_CRYSTALTOUCH) },  	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, -		HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, +		MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,  			USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },  	/* MosArt panels */  	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, -		HID_USB_DEVICE(USB_VENDOR_ID_ASUS, +		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,  			USB_DEVICE_ID_ASUS_T91MT)},  	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, -		HID_USB_DEVICE(USB_VENDOR_ID_ASUS, +		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,  			USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },  	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, -		HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, +		MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,  			USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },  	/* Panasonic panels */  	{ .driver_data = MT_CLS_PANASONIC, -		HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, +		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,  			USB_DEVICE_ID_PANABOARD_UBT780) },  	{ .driver_data = MT_CLS_PANASONIC, -		HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, +		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,  			USB_DEVICE_ID_PANABOARD_UBT880) },  	/* PenMount panels */  	{ .driver_data = MT_CLS_CONFIDENCE, -		HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, +		MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,  			USB_DEVICE_ID_PENMOUNT_PCI) },  	/* PixArt optical touch screen */  	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_PIXART, +		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,  			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },  	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_PIXART, +		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,  			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },  	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, -		HID_USB_DEVICE(USB_VENDOR_ID_PIXART, +		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,  			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },  	/* PixCir-based panels */  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, -		HID_USB_DEVICE(USB_VENDOR_ID_HANVON, +		MT_USB_DEVICE(USB_VENDOR_ID_HANVON,  			USB_DEVICE_ID_HANVON_MULTITOUCH) },  	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, -		HID_USB_DEVICE(USB_VENDOR_ID_CANDO, +		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,  			USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },  	/* Quanta-based panels */  	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, -		HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, +		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,  			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },  	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, -		HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, +		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,  			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },  	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, -		HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, +		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,  			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },  	/* Stantum panels */  	{ .driver_data = MT_CLS_CONFIDENCE, -		HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, +		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,  			USB_DEVICE_ID_MTP)},  	{ .driver_data = MT_CLS_CONFIDENCE, -		HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, +		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,  			USB_DEVICE_ID_MTP_STM)},  	{ .driver_data = MT_CLS_CONFIDENCE, -		HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, +		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,  			USB_DEVICE_ID_MTP_SITRONIX)},  	/* TopSeed panels */  	{ .driver_data = MT_CLS_TOPSEED, -		HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, +		MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,  			USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },  	/* Touch International panels */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, +		MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,  			USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },  	/* Unitec panels */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, +		MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,  			USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, +		MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,  			USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },  	/* XAT */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XAT, +		MT_USB_DEVICE(USB_VENDOR_ID_XAT,  			USB_DEVICE_ID_XAT_CSR) },  	/* Xiroku */  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_SPX) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_MPX) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_CSR) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_SPX1) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_MPX1) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_CSR1) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_SPX2) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_MPX2) },  	{ .driver_data = MT_CLS_DEFAULT, -		HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, +		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,  			USB_DEVICE_ID_XIROKU_CSR2) }, +	/* Generic MT device */ +	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },  	{ }  };  MODULE_DEVICE_TABLE(hid, mt_devices); diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index 1f112891033..3aba02be1f2 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -14,6 +14,7 @@  #include <linux/device.h>  #include <linux/hid.h>  #include <linux/module.h> +#include <linux/usb.h>  #include "hid-ids.h" @@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = {  	0xC0                /*  End Collection                      */  }; +/* + * See TWHL850 description, device and HID report descriptors at + * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850 + */ + +/* Size of the original descriptors of TWHL850 tablet */ +#define TWHL850_RDESC_ORIG_SIZE0	182 +#define TWHL850_RDESC_ORIG_SIZE1	161 +#define TWHL850_RDESC_ORIG_SIZE2	92 + +/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */ +static __u8 twhl850_rdesc_fixed0[] = { +	0x05, 0x0D,         /*  Usage Page (Digitizer),             */ +	0x09, 0x02,         /*  Usage (Pen),                        */ +	0xA1, 0x01,         /*  Collection (Application),           */ +	0x85, 0x09,         /*      Report ID (9),                  */ +	0x09, 0x20,         /*      Usage (Stylus),                 */ +	0xA0,               /*      Collection (Physical),          */ +	0x14,               /*          Logical Minimum (0),        */ +	0x25, 0x01,         /*          Logical Maximum (1),        */ +	0x75, 0x01,         /*          Report Size (1),            */ +	0x95, 0x03,         /*          Report Count (3),           */ +	0x09, 0x42,         /*          Usage (Tip Switch),         */ +	0x09, 0x44,         /*          Usage (Barrel Switch),      */ +	0x09, 0x46,         /*          Usage (Tablet Pick),        */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0x95, 0x01,         /*          Report Count (1),           */ +	0x09, 0x32,         /*          Usage (In Range),           */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0x75, 0x10,         /*          Report Size (16),           */ +	0xA4,               /*          Push,                       */ +	0x05, 0x01,         /*          Usage Page (Desktop),       */ +	0x65, 0x13,         /*          Unit (Inch),                */ +	0x55, 0xFD,         /*          Unit Exponent (-3),         */ +	0x34,               /*          Physical Minimum (0),       */ +	0x09, 0x30,         /*          Usage (X),                  */ +	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */ +	0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x09, 0x31,         /*          Usage (Y),                  */ +	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */ +	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0xB4,               /*          Pop,                        */ +	0x09, 0x30,         /*          Usage (Tip Pressure),       */ +	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0xC0,               /*      End Collection,                 */ +	0xC0                /*  End Collection                      */ +}; + +/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */ +static __u8 twhl850_rdesc_fixed1[] = { +	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),          */ +	0x05, 0x09,         /*          Usage Page (Button),        */ +	0x75, 0x01,         /*          Report Size (1),            */ +	0x95, 0x03,         /*          Report Count (3),           */ +	0x19, 0x01,         /*          Usage Minimum (01h),        */ +	0x29, 0x03,         /*          Usage Maximum (03h),        */ +	0x14,               /*          Logical Minimum (0),        */ +	0x25, 0x01,         /*          Logical Maximum (1),        */ +	0x81, 0x02,         /*          Input (Variable),           */ +	0x95, 0x05,         /*          Report Count (5),           */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0x05, 0x01,         /*          Usage Page (Desktop),       */ +	0x09, 0x30,         /*          Usage (X),                  */ +	0x09, 0x31,         /*          Usage (Y),                  */ +	0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */ +	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */ +	0x75, 0x10,         /*          Report Size (16),           */ +	0x95, 0x02,         /*          Report Count (2),           */ +	0x81, 0x06,         /*          Input (Variable, Relative), */ +	0x09, 0x38,         /*          Usage (Wheel),              */ +	0x15, 0xFF,         /*          Logical Minimum (-1),       */ +	0x25, 0x01,         /*          Logical Maximum (1),        */ +	0x95, 0x01,         /*          Report Count (1),           */ +	0x75, 0x08,         /*          Report Size (8),            */ +	0x81, 0x06,         /*          Input (Variable, Relative), */ +	0x81, 0x03,         /*          Input (Constant, Variable), */ +	0xC0,               /*      End Collection,                 */ +	0xC0                /*  End Collection                      */ +}; + +/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */ +static __u8 twhl850_rdesc_fixed2[] = { +	0x05, 0x01,         /*  Usage Page (Desktop),               */ +	0x09, 0x06,         /*  Usage (Keyboard),                   */ +	0xA1, 0x01,         /*  Collection (Application),           */ +	0x85, 0x03,         /*      Report ID (3),                  */ +	0x05, 0x07,         /*      Usage Page (Keyboard),          */ +	0x14,               /*      Logical Minimum (0),            */ +	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */ +	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */ +	0x25, 0x01,         /*      Logical Maximum (1),            */ +	0x75, 0x01,         /*      Report Size (1),                */ +	0x95, 0x08,         /*      Report Count (8),               */ +	0x81, 0x02,         /*      Input (Variable),               */ +	0x18,               /*      Usage Minimum (None),           */ +	0x29, 0xFF,         /*      Usage Maximum (FFh),            */ +	0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */ +	0x75, 0x08,         /*      Report Size (8),                */ +	0x95, 0x06,         /*      Report Count (6),               */ +	0x80,               /*      Input,                          */ +	0xC0                /*  End Collection                      */ +}; +  static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,  					unsigned int *rsize)  { +	struct usb_interface *iface = to_usb_interface(hdev->dev.parent); +	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber; +  	switch (hdev->product) {  	case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:  		if (*rsize == PF1209_RDESC_ORIG_SIZE) { @@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,  			*rsize = sizeof(wp1062_rdesc_fixed);  		}  		break; +	case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850: +		switch (iface_num) { +		case 0: +			if (*rsize == TWHL850_RDESC_ORIG_SIZE0) { +				rdesc = twhl850_rdesc_fixed0; +				*rsize = sizeof(twhl850_rdesc_fixed0); +			} +			break; +		case 1: +			if (*rsize == TWHL850_RDESC_ORIG_SIZE1) { +				rdesc = twhl850_rdesc_fixed1; +				*rsize = sizeof(twhl850_rdesc_fixed1); +			} +			break; +		case 2: +			if (*rsize == TWHL850_RDESC_ORIG_SIZE2) { +				rdesc = twhl850_rdesc_fixed2; +				*rsize = sizeof(twhl850_rdesc_fixed2); +			} +			break; +		} +		break;  	}  	return rdesc; @@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = {  				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,  				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, +				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },  	{ }  };  MODULE_DEVICE_TABLE(hid, uclogic_devices); 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/hidraw.c b/drivers/hid/hidraw.c index cf7d6d58e79..36fa77b40ff 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,  		len = list->buffer[list->tail].len > count ?  			count : list->buffer[list->tail].len; -		if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { -			ret = -EFAULT; -			goto out; +		if (list->buffer[list->tail].value) { +			if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { +				ret = -EFAULT; +				goto out; +			} +			ret = len;  		} -		ret = len;  		kfree(list->buffer[list->tail].value);  		list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); @@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {  	.llseek =	noop_llseek,  }; -void hidraw_report_event(struct hid_device *hid, u8 *data, int len) +int hidraw_report_event(struct hid_device *hid, u8 *data, int len)  {  	struct hidraw *dev = hid->hidraw;  	struct hidraw_list *list; +	int ret = 0;  	list_for_each_entry(list, &dev->list, node) { -		list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC); +		if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) { +			ret = -ENOMEM; +			break; +		}  		list->buffer[list->head].len = len;  		list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);  		kill_fasync(&list->fasync, SIGIO, POLL_IN);  	}  	wake_up_interruptible(&dev->wait); +	return ret;  }  EXPORT_SYMBOL_GPL(hidraw_report_event); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 5bf91dbad59..482f936fc29 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -28,6 +28,7 @@  #include <linux/input.h>  #include <linux/wait.h>  #include <linux/workqueue.h> +#include <linux/string.h>  #include <linux/usb.h> @@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid)  			!test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&  			!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {  		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); -		if (rc != 0) +		if (rc != 0) {  			clear_bit(HID_IN_RUNNING, &usbhid->iofl); +			if (rc == -ENOSPC) +				set_bit(HID_NO_BANDWIDTH, &usbhid->iofl); +		} else { +			clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl); +		}  	}  	spin_unlock_irqrestore(&usbhid->lock, flags);  	return rc; @@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid)  	if (time_after(jiffies, usbhid->stop_retry)) { -		/* Retries failed, so do a port reset */ -		if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { +		/* Retries failed, so do a port reset unless we lack bandwidth*/ +		if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) +		     && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { +  			schedule_work(&usbhid->reset_work);  			goto done;  		} @@ -203,7 +211,7 @@ static int usbhid_restart_out_queue(struct usbhid_device *usbhid)  		return 0;  	if ((kicked = (usbhid->outhead != usbhid->outtail))) { -		dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); +		hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);  		r = usb_autopm_get_interface_async(usbhid->intf);  		if (r < 0) @@ -230,7 +238,7 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)  		return 0;  	if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { -		dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); +		hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);  		r = usb_autopm_get_interface_async(usbhid->intf);  		if (r < 0) @@ -399,6 +407,16 @@ static int hid_submit_ctrl(struct hid_device *hid)   * Output interrupt completion handler.   */ +static int irq_out_pump_restart(struct hid_device *hid) +{ +	struct usbhid_device *usbhid = hid->driver_data; + +	if (usbhid->outhead != usbhid->outtail) +		return hid_submit_out(hid); +	else +		return -1; +} +  static void hid_irq_out(struct urb *urb)  {  	struct hid_device *hid = urb->context; @@ -428,7 +446,7 @@ static void hid_irq_out(struct urb *urb)  	else  		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); -	if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) { +	if (!irq_out_pump_restart(hid)) {  		/* Successfully submitted next urb in queue */  		spin_unlock_irqrestore(&usbhid->lock, flags);  		return; @@ -443,6 +461,15 @@ static void hid_irq_out(struct urb *urb)  /*   * Control pipe completion handler.   */ +static int ctrl_pump_restart(struct hid_device *hid) +{ +	struct usbhid_device *usbhid = hid->driver_data; + +	if (usbhid->ctrlhead != usbhid->ctrltail) +		return hid_submit_ctrl(hid); +	else +		return -1; +}  static void hid_ctrl(struct urb *urb)  { @@ -476,7 +503,7 @@ static void hid_ctrl(struct urb *urb)  	else  		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); -	if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) { +	if (!ctrl_pump_restart(hid)) {  		/* Successfully submitted next urb in queue */  		spin_unlock(&usbhid->lock);  		return; @@ -535,11 +562,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re  			 * the queue is known to run  			 * but an earlier request may be stuck  			 * we may need to time out -			 * no race because this is called under +			 * no race because the URB is blocked under  			 * spinlock  			 */ -			if (time_after(jiffies, usbhid->last_out + HZ * 5)) +			if (time_after(jiffies, usbhid->last_out + HZ * 5)) { +				usb_block_urb(usbhid->urbout); +				/* drop lock to not deadlock if the callback is called */ +				spin_unlock(&usbhid->lock);  				usb_unlink_urb(usbhid->urbout); +				spin_lock(&usbhid->lock); +				usb_unblock_urb(usbhid->urbout); +				/* +				 * if the unlinking has already completed +				 * the pump will have been stopped +				 * it must be restarted now +				 */ +				if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) +					if (!irq_out_pump_restart(hid)) +						set_bit(HID_OUT_RUNNING, &usbhid->iofl); + + +			}  		}  		return;  	} @@ -583,11 +626,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re  		 * the queue is known to run  		 * but an earlier request may be stuck  		 * we may need to time out -		 * no race because this is called under +		 * no race because the URB is blocked under  		 * spinlock  		 */ -		if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) +		if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) { +			usb_block_urb(usbhid->urbctrl); +			/* drop lock to not deadlock if the callback is called */ +			spin_unlock(&usbhid->lock);  			usb_unlink_urb(usbhid->urbctrl); +			spin_lock(&usbhid->lock); +			usb_unblock_urb(usbhid->urbctrl); +			/* +			 * if the unlinking has already completed +			 * the pump will have been stopped +			 * it must be restarted now +			 */ +			if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) +				if (!ctrl_pump_restart(hid)) +					set_bit(HID_CTRL_RUNNING, &usbhid->iofl); +		}  	}  } @@ -700,7 +757,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,  int usbhid_open(struct hid_device *hid)  {  	struct usbhid_device *usbhid = hid->driver_data; -	int res; +	int res = 0;  	mutex_lock(&hid_open_mut);  	if (!hid->open++) { @@ -708,17 +765,27 @@ int usbhid_open(struct hid_device *hid)  		/* the device must be awake to reliably request remote wakeup */  		if (res < 0) {  			hid->open--; -			mutex_unlock(&hid_open_mut); -			return -EIO; +			res = -EIO; +			goto done;  		}  		usbhid->intf->needs_remote_wakeup = 1; -		if (hid_start_in(hid)) -			hid_io_error(hid); -  +		res = hid_start_in(hid); +		if (res) { +			if (res != -ENOSPC) { +				hid_io_error(hid); +				res = 0; +			} else { +				/* no use opening if resources are insufficient */ +				hid->open--; +				res = -EBUSY; +				usbhid->intf->needs_remote_wakeup = 0; +			} +		}  		usb_autopm_put_interface(usbhid->intf);  	} +done:  	mutex_unlock(&hid_open_mut); -	return 0; +	return res;  }  void usbhid_close(struct hid_device *hid) @@ -1347,7 +1414,34 @@ static int hid_post_reset(struct usb_interface *intf)  	struct usb_device *dev = interface_to_usbdev (intf);  	struct hid_device *hid = usb_get_intfdata(intf);  	struct usbhid_device *usbhid = hid->driver_data; +	struct usb_host_interface *interface = intf->cur_altsetting;  	int status; +	char *rdesc; + +	/* Fetch and examine the HID report descriptor. If this +	 * has changed, then rebind. Since usbcore's check of the +	 * configuration descriptors passed, we already know that +	 * the size of the HID report descriptor has not changed. +	 */ +	rdesc = kmalloc(hid->rsize, GFP_KERNEL); +	if (!rdesc) { +		dbg_hid("couldn't allocate rdesc memory (post_reset)\n"); +		return 1; +	} +	status = hid_get_class_descriptor(dev, +				interface->desc.bInterfaceNumber, +				HID_DT_REPORT, rdesc, hid->rsize); +	if (status < 0) { +		dbg_hid("reading report descriptor failed (post_reset)\n"); +		kfree(rdesc); +		return 1; +	} +	status = memcmp(rdesc, hid->rdesc, hid->rsize); +	kfree(rdesc); +	if (status != 0) { +		dbg_hid("report descriptor changed\n"); +		return 1; +	}  	spin_lock_irq(&usbhid->lock);  	clear_bit(HID_RESET_PENDING, &usbhid->iofl); @@ -1504,28 +1598,15 @@ static struct usb_driver hid_driver = {  	.supports_autosuspend = 1,  }; -static const struct hid_device_id hid_usb_table[] = { -	{ HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) }, -	{ } -}; -  struct usb_interface *usbhid_find_interface(int minor)  {  	return usb_find_interface(&hid_driver, minor);  } -static struct hid_driver hid_usb_driver = { -	.name = "generic-usb", -	.id_table = hid_usb_table, -}; -  static int __init hid_init(void)  {  	int retval = -ENOMEM; -	retval = hid_register_driver(&hid_usb_driver); -	if (retval) -		goto hid_register_fail;  	retval = usbhid_quirks_init(quirks_param);  	if (retval)  		goto usbhid_quirks_init_fail; @@ -1538,8 +1619,6 @@ static int __init hid_init(void)  usb_register_fail:  	usbhid_quirks_exit();  usbhid_quirks_init_fail: -	hid_unregister_driver(&hid_usb_driver); -hid_register_fail:  	return retval;  } @@ -1547,7 +1626,6 @@ static void __exit hid_exit(void)  {  	usb_deregister(&hid_driver);  	usbhid_quirks_exit(); -	hid_unregister_driver(&hid_usb_driver);  }  module_init(hid_init); 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 }, diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index b1ec0e2aeb5..14599e25679 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -34,6 +34,7 @@  #include <linux/hid.h>  #include <linux/hiddev.h>  #include <linux/compat.h> +#include <linux/vmalloc.h>  #include "usbhid.h"  #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file)  		} else {  			mutex_unlock(&list->hiddev->existancelock);  			kfree(list->hiddev); -			kfree(list); +			vfree(list);  			return 0;  		}  	}  	mutex_unlock(&list->hiddev->existancelock); -	kfree(list); +	vfree(list);  	return 0;  } @@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file)  	hid = usb_get_intfdata(intf);  	hiddev = hid->hiddev; -	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) +	if (!(list = vzalloc(sizeof(struct hiddev_list))))  		return -ENOMEM;  	mutex_init(&list->thread_lock);  	list->hiddev = hiddev; @@ -322,7 +323,7 @@ bail_unlock:  	mutex_unlock(&hiddev->existancelock);  bail:  	file->private_data = NULL; -	kfree(list); +	vfree(list);  	return res;  } diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index cb8f703efde..1883d7b9487 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);  #define HID_STARTED		8  #define HID_REPORTED_IDLE	9  #define HID_KEYS_PRESSED	10 +#define HID_NO_BANDWIDTH	11  /*   * USB-specific HID struct, to be pointed to diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index 0f6be45d43d..bf16d72dc37 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -92,9 +92,10 @@ static void usb_mouse_irq(struct urb *urb)  resubmit:  	status = usb_submit_urb (urb, GFP_ATOMIC);  	if (status) -		err ("can't resubmit intr, %s-%s/input0, status %d", -				mouse->usbdev->bus->bus_name, -				mouse->usbdev->devpath, status); +		dev_err(&mouse->usbdev->dev, +			"can't resubmit intr, %s-%s/input0, status %d\n", +			mouse->usbdev->bus->bus_name, +			mouse->usbdev->devpath, status);  }  static int usb_mouse_open(struct input_dev *dev)  |