diff options
Diffstat (limited to 'drivers/hid/hid-core.c')
| -rw-r--r-- | drivers/hid/hid-core.c | 122 | 
1 files changed, 102 insertions, 20 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b8470b1a10f..8ed66fd1ea8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -319,7 +319,7 @@ static s32 item_sdata(struct hid_item *item)  static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)  { -	__u32 raw_value; +	__s32 raw_value;  	switch (item->tag) {  	case HID_GLOBAL_ITEM_TAG_PUSH: @@ -370,10 +370,11 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)  		return 0;  	case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: -		/* Units exponent negative numbers are given through a -		 * two's complement. -		 * See "6.2.2.7 Global Items" for more information. */ -		raw_value = item_udata(item); +		/* Many devices provide unit exponent as a two's complement +		 * nibble due to the common misunderstanding of HID +		 * specification 1.11, 6.2.2.7 Global Items. Attempt to handle +		 * both this and the standard encoding. */ +		raw_value = item_sdata(item);  		if (!(raw_value & 0xfffffff0))  			parser->global.unit_exponent = hid_snto32(raw_value, 4);  		else @@ -717,6 +718,9 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)  	case HID_MAIN_ITEM_TAG_END_COLLECTION:  		break;  	case HID_MAIN_ITEM_TAG_INPUT: +		/* ignore constant inputs, they will be ignored by hid-input */ +		if (data & HID_MAIN_ITEM_CONSTANT) +			break;  		for (i = 0; i < parser->local.usage_index; i++)  			hid_scan_input_usage(parser, parser->local.usage[i]);  		break; @@ -775,6 +779,14 @@ static int hid_scan_report(struct hid_device *hid)  	    (hid->group == HID_GROUP_MULTITOUCH))  		hid->group = HID_GROUP_MULTITOUCH_WIN_8; +	/* +	* Vendor specific handlings +	*/ +	if ((hid->vendor == USB_VENDOR_ID_SYNAPTICS) && +	    (hid->group == HID_GROUP_GENERIC)) +		/* hid-rmi should take care of them, not hid-generic */ +		hid->group = HID_GROUP_RMI; +  	vfree(parser);  	return 0;  } @@ -838,7 +850,17 @@ struct hid_report *hid_validate_values(struct hid_device *hid,  	 * ->numbered being checked, which may not always be the case when  	 * drivers go to access report values.  	 */ -	report = hid->report_enum[type].report_id_hash[id]; +	if (id == 0) { +		/* +		 * Validating on id 0 means we should examine the first +		 * report in the list. +		 */ +		report = list_entry( +				hid->report_enum[type].report_list.next, +				struct hid_report, list); +	} else { +		report = hid->report_enum[type].report_id_hash[id]; +	}  	if (!report) {  		hid_err(hid, "missing %s %u\n", hid_report_names[type], id);  		return NULL; @@ -1247,6 +1269,12 @@ void hid_output_report(struct hid_report *report, __u8 *data)  }  EXPORT_SYMBOL_GPL(hid_output_report); +static int hid_report_len(struct hid_report *report) +{ +	/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */ +	return ((report->size - 1) >> 3) + 1 + (report->id > 0); +} +  /*   * Allocator for buffer that is going to be passed to hid_output_report()   */ @@ -1257,7 +1285,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)  	 * of implement() working on 8 byte chunks  	 */ -	int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7; +	int len = hid_report_len(report) + 7;  	return kmalloc(len, flags);  } @@ -1313,6 +1341,41 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,  	return report;  } +/* + * Implement a generic .request() callback, using .raw_request() + * DO NOT USE in hid drivers directly, but through hid_hw_request instead. + */ +void __hid_request(struct hid_device *hid, struct hid_report *report, +		int reqtype) +{ +	char *buf; +	int ret; +	int len; + +	buf = hid_alloc_report_buf(report, GFP_KERNEL); +	if (!buf) +		return; + +	len = hid_report_len(report); + +	if (reqtype == HID_REQ_SET_REPORT) +		hid_output_report(report, buf); + +	ret = hid->ll_driver->raw_request(hid, report->id, buf, len, +					  report->type, reqtype); +	if (ret < 0) { +		dbg_hid("unable to complete request: %d\n", ret); +		goto out; +	} + +	if (reqtype == HID_REQ_GET_REPORT) +		hid_input_report(hid, report->type, buf, ret, 0); + +out: +	kfree(buf); +} +EXPORT_SYMBOL_GPL(__hid_request); +  int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,  		int interrupt)  { @@ -1417,10 +1480,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i  	if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {  		ret = hdrv->raw_event(hid, report, data, size); -		if (ret < 0) { -			ret = ret < 0 ? ret : 0; +		if (ret < 0)  			goto unlock; -		}  	}  	ret = hid_report_raw_event(hid, type, data, size, interrupt); @@ -1604,6 +1665,7 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ 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_ACRUX, 0xf705) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) }, @@ -1679,6 +1741,7 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, +	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },  	{ 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_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, @@ -1692,6 +1755,7 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },  	{ 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) }, @@ -1715,12 +1779,16 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },  	{ 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_GENIUS_GILA_GAMING_MOUSE) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, @@ -1752,6 +1820,7 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, @@ -1774,6 +1843,7 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, @@ -1799,19 +1869,28 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },  #if IS_ENABLED(CONFIG_HID_ROCCAT) -	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEXTD) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },  #endif +#if IS_ENABLED(CONFIG_HID_SAITEK)  	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) }, +#endif  	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, @@ -1821,6 +1900,8 @@ static const struct hid_device_id hid_have_special_driver[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },  	{ 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_PS4_CONTROLLER) }, +	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, @@ -2106,6 +2187,7 @@ static const struct hid_device_id hid_ignore_list[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) }, @@ -2262,6 +2344,7 @@ static const struct hid_device_id hid_ignore_list[] = {  	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },  	{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },  	{ }  }; @@ -2373,15 +2456,6 @@ bool hid_ignore(struct hid_device *hdev)  				hdev->type == HID_TYPE_USBNONE)  			return true;  		break; -	case USB_VENDOR_ID_DWAV: -		/* These are handled by usbtouchscreen. hdev->type is probably -		 * HID_TYPE_USBNONE, but we say !HID_TYPE_USBMOUSE to match -		 * usbtouchscreen. */ -		if ((hdev->product == USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER || -		     hdev->product == USB_DEVICE_ID_DWAV_TOUCHCONTROLLER) && -		    hdev->type != HID_TYPE_USBMOUSE) -			return true; -		break;  	case USB_VENDOR_ID_VELLEMAN:  		/* These are not HID devices.  They are handled by comedi. */  		if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST && @@ -2426,6 +2500,14 @@ int hid_add_device(struct hid_device *hdev)  		return -ENODEV;  	/* +	 * Check for the mandatory transport channel. +	 */ +	 if (!hdev->ll_driver->raw_request) { +		hid_err(hdev, "transport driver missing .raw_request()\n"); +		return -EINVAL; +	 } + +	/*  	 * Read the device report descriptor once and use as template  	 * for the driver-specific modifications.  	 */  | 
