1256 lines · 36.5 KB · C
RawDownload
/* *  Copyright (c) 2000-2001 Vojtech Pavlik *  Copyright (c) 2006-2010 Jiri Kosina * *  HID to Linux Input mapping */ /* * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include <linux/module.h>#include <linux/slab.h>#include <linux/kernel.h> #include <linux/hid.h>#include <linux/hid-debug.h> #include "hid-ids.h" #define unk	KEY_UNKNOWN static const unsigned char hid_keyboard[256] = {	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,	115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,	122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk}; static const struct {	__s32 x;	__s32 y;}  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; #define map_abs(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))#define map_rel(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))#define map_key(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))#define map_led(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c)) #define map_abs_clear(c)	hid_map_usage_clear(hidinput, usage, &bit, \		&max, EV_ABS, (c))#define map_key_clear(c)	hid_map_usage_clear(hidinput, usage, &bit, \		&max, EV_KEY, (c)) static bool match_scancode(struct hid_usage *usage,			   unsigned int cur_idx, unsigned int scancode){	return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;} static bool match_keycode(struct hid_usage *usage,			  unsigned int cur_idx, unsigned int keycode){	/*	 * We should exclude unmapped usages when doing lookup by keycode.	 */	return (usage->type == EV_KEY && usage->code == keycode);} static bool match_index(struct hid_usage *usage,			unsigned int cur_idx, unsigned int idx){	return cur_idx == idx;} typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,				unsigned int cur_idx, unsigned int val); static struct hid_usage *hidinput_find_key(struct hid_device *hid,					   hid_usage_cmp_t match,					   unsigned int value,					   unsigned int *usage_idx){	unsigned int i, j, k, cur_idx = 0;	struct hid_report *report;	struct hid_usage *usage; 	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {		list_for_each_entry(report, &hid->report_enum[k].report_list, list) {			for (i = 0; i < report->maxfield; i++) {				for (j = 0; j < report->field[i]->maxusage; j++) {					usage = report->field[i]->usage + j;					if (usage->type == EV_KEY || usage->type == 0) {						if (match(usage, cur_idx, value)) {							if (usage_idx)								*usage_idx = cur_idx;							return usage;						}						cur_idx++;					}				}			}		}	}	return NULL;} static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,					const struct input_keymap_entry *ke,					unsigned int *index){	struct hid_usage *usage;	unsigned int scancode; 	if (ke->flags & INPUT_KEYMAP_BY_INDEX)		usage = hidinput_find_key(hid, match_index, ke->index, index);	else if (input_scancode_to_scalar(ke, &scancode) == 0)		usage = hidinput_find_key(hid, match_scancode, scancode, index);	else		usage = NULL; 	return usage;} static int hidinput_getkeycode(struct input_dev *dev,			       struct input_keymap_entry *ke){	struct hid_device *hid = input_get_drvdata(dev);	struct hid_usage *usage;	unsigned int scancode, index; 	usage = hidinput_locate_usage(hid, ke, &index);	if (usage) {		ke->keycode = usage->type == EV_KEY ?				usage->code : KEY_RESERVED;		ke->index = index;		scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);		ke->len = sizeof(scancode);		memcpy(ke->scancode, &scancode, sizeof(scancode));		return 0;	} 	return -EINVAL;} static int hidinput_setkeycode(struct input_dev *dev,			       const struct input_keymap_entry *ke,			       unsigned int *old_keycode){	struct hid_device *hid = input_get_drvdata(dev);	struct hid_usage *usage; 	usage = hidinput_locate_usage(hid, ke, NULL);	if (usage) {		*old_keycode = usage->type == EV_KEY ?				usage->code : KEY_RESERVED;		usage->code = ke->keycode; 		clear_bit(*old_keycode, dev->keybit);		set_bit(usage->code, dev->keybit);		dbg_hid("Assigned keycode %d to HID usage code %x\n",			usage->code, usage->hid); 		/*		 * Set the keybit for the old keycode if the old keycode is used		 * by another key		 */		if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))			set_bit(*old_keycode, dev->keybit); 		return 0;	} 	return -EINVAL;}  /** * hidinput_calc_abs_res - calculate an absolute axis resolution * @field: the HID report field to calculate resolution for * @code: axis code * * The formula is: *                         (logical_maximum - logical_minimum) * resolution = ---------------------------------------------------------- *              (physical_maximum - physical_minimum) * 10 ^ unit_exponent * * as seen in the HID specification v1.11 6.2.2.7 Global Items. * * Only exponent 1 length units are processed. Centimeters and inches are * converted to millimeters. Degrees are converted to radians. */static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code){	__s32 unit_exponent = field->unit_exponent;	__s32 logical_extents = field->logical_maximum -					field->logical_minimum;	__s32 physical_extents = field->physical_maximum -					field->physical_minimum;	__s32 prev; 	/* Check if the extents are sane */	if (logical_extents <= 0 || physical_extents <= 0)		return 0; 	/*	 * Verify and convert units.	 * See HID specification v1.11 6.2.2.7 Global Items for unit decoding	 */	switch (code) {	case ABS_X:	case ABS_Y:	case ABS_Z:		if (field->unit == 0x11) {		/* If centimeters */			/* Convert to millimeters */			unit_exponent += 1;		} else if (field->unit == 0x13) {	/* If inches */			/* Convert to millimeters */			prev = physical_extents;			physical_extents *= 254;			if (physical_extents < prev)				return 0;			unit_exponent -= 1;		} else {			return 0;		}		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;			logical_extents *= 573;			if (logical_extents < prev)				return 0;			unit_exponent += 1;		} else if (field->unit != 0x12) {	/* If not radians */			return 0;		}		break; 	default:		return 0;	} 	/* Apply negative unit exponent */	for (; unit_exponent < 0; unit_exponent++) {		prev = logical_extents;		logical_extents *= 10;		if (logical_extents < prev)			return 0;	}	/* Apply positive unit exponent */	for (; unit_exponent > 0; unit_exponent--) {		prev = physical_extents;		physical_extents *= 10;		if (physical_extents < prev)			return 0;	} 	/* Calculate resolution */	return logical_extents / physical_extents;} #ifdef CONFIG_HID_BATTERY_STRENGTHstatic enum power_supply_property hidinput_battery_props[] = {	POWER_SUPPLY_PROP_PRESENT,	POWER_SUPPLY_PROP_ONLINE,	POWER_SUPPLY_PROP_CAPACITY,	POWER_SUPPLY_PROP_MODEL_NAME,	POWER_SUPPLY_PROP_STATUS,	POWER_SUPPLY_PROP_SCOPE,}; #define HID_BATTERY_QUIRK_PERCENT	(1 << 0) /* always reports percent */#define HID_BATTERY_QUIRK_FEATURE	(1 << 1) /* ask for feature report */ static const struct hid_device_id hid_battery_quirks[] = {	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,			       USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),	  HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },	{}}; static unsigned find_battery_quirk(struct hid_device *hdev){	unsigned quirks = 0;	const struct hid_device_id *match; 	match = hid_match_id(hdev, hid_battery_quirks);	if (match != NULL)		quirks = match->driver_data; 	return quirks;} static int hidinput_get_battery_property(struct power_supply *psy,					 enum power_supply_property prop,					 union power_supply_propval *val){	struct hid_device *dev = container_of(psy, struct hid_device, battery);	int ret = 0;	__u8 buf[2] = {}; 	switch (prop) {	case POWER_SUPPLY_PROP_PRESENT:	case POWER_SUPPLY_PROP_ONLINE:		val->intval = 1;		break; 	case POWER_SUPPLY_PROP_CAPACITY:		ret = dev->hid_get_raw_report(dev, dev->battery_report_id,					      buf, sizeof(buf),					      dev->battery_report_type); 		if (ret != 2) {			if (ret >= 0)				ret = -EINVAL;			break;		} 		if (dev->battery_min < dev->battery_max &&		    buf[1] >= dev->battery_min &&		    buf[1] <= dev->battery_max)			val->intval = (100 * (buf[1] - dev->battery_min)) /				(dev->battery_max - dev->battery_min);		break; 	case POWER_SUPPLY_PROP_MODEL_NAME:		val->strval = dev->name;		break; 	case POWER_SUPPLY_PROP_STATUS:		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;		break; 	case POWER_SUPPLY_PROP_SCOPE:		val->intval = POWER_SUPPLY_SCOPE_DEVICE;		break; 	default:		ret = -EINVAL;		break;	} 	return ret;} static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field){	struct power_supply *battery = &dev->battery;	int ret;	unsigned quirks;	s32 min, max; 	if (field->usage->hid != HID_DC_BATTERYSTRENGTH)		return false;	/* no match */ 	if (battery->name != NULL)		goto out;	/* already initialized? */ 	battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);	if (battery->name == NULL)		goto out; 	battery->type = POWER_SUPPLY_TYPE_BATTERY;	battery->properties = hidinput_battery_props;	battery->num_properties = ARRAY_SIZE(hidinput_battery_props);	battery->use_for_apm = 0;	battery->get_property = hidinput_get_battery_property; 	quirks = find_battery_quirk(dev); 	hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",		dev->bus, dev->vendor, dev->product, dev->version, quirks); 	min = field->logical_minimum;	max = field->logical_maximum; 	if (quirks & HID_BATTERY_QUIRK_PERCENT) {		min = 0;		max = 100;	} 	if (quirks & HID_BATTERY_QUIRK_FEATURE)		report_type = HID_FEATURE_REPORT; 	dev->battery_min = min;	dev->battery_max = max;	dev->battery_report_type = report_type;	dev->battery_report_id = field->report->id; 	ret = power_supply_register(&dev->dev, battery);	if (ret != 0) {		hid_warn(dev, "can't register power supply: %d\n", ret);		kfree(battery->name);		battery->name = NULL;	} 	power_supply_powers(battery, &dev->dev); out:	return true;} static void hidinput_cleanup_battery(struct hid_device *dev){	if (!dev->battery.name)		return; 	power_supply_unregister(&dev->battery);	kfree(dev->battery.name);	dev->battery.name = NULL;}#else  /* !CONFIG_HID_BATTERY_STRENGTH */static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,				   struct hid_field *field){	return false;} static void hidinput_cleanup_battery(struct hid_device *dev){}#endif	/* CONFIG_HID_BATTERY_STRENGTH */ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,				     struct hid_usage *usage){	struct input_dev *input = hidinput->input;	struct hid_device *device = input_get_drvdata(input);	int max = 0, code;	unsigned long *bit = NULL; 	field->hidinput = hidinput; 	if (field->flags & HID_MAIN_ITEM_CONSTANT)		goto ignore; 	/* only LED usages are supported in output fields */	if (field->report_type == HID_OUTPUT_REPORT &&			(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {		goto ignore;	} 	if (device->driver->input_mapping) {		int ret = device->driver->input_mapping(device, hidinput, field,				usage, &bit, &max);		if (ret > 0)			goto mapped;		if (ret < 0)			goto ignore;	} 	switch (usage->hid & HID_USAGE_PAGE) {	case HID_UP_UNDEFINED:		goto ignore; 	case HID_UP_KEYBOARD:		set_bit(EV_REP, input->evbit); 		if ((usage->hid & HID_USAGE) < 256) {			if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;			map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);		} else			map_key(KEY_UNKNOWN); 		break; 	case HID_UP_BUTTON:		code = ((usage->hid - 1) & HID_USAGE); 		switch (field->application) {		case HID_GD_MOUSE:		case HID_GD_POINTER:  code += BTN_MOUSE; break;		case HID_GD_JOYSTICK:				if (code <= 0xf)					code += BTN_JOYSTICK;

Lines 1–500 of 1256.