Commit a2ff0059 authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-5.18/core' into for-linus

- rework of generic input handling which ultimately makes the processing of
  tablet events more generic and reliable (Benjamin Tissoires)
parents 41237041 42764f97
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -137,7 +137,11 @@ A few EV_KEY codes have special meanings:
    code should be set to a value of 1. When the tool is no longer interacting
    with the input device, the BTN_TOOL_<name> code should be reset to 0. All
    trackpads, tablets, and touchscreens should use at least one BTN_TOOL_<name>
    code when events are generated.
    code when events are generated. Likewise all trackpads, tablets, and
    touchscreens should export only one BTN_TOOL_<name> at a time. To not break
    existing userspace, it is recommended to not switch tool in one EV_SYN frame
    but first emitting the old BTN_TOOL_<name> at 0, then emit one SYN_REPORT
    and then set the new BTN_TOOL_<name> at 1.

* BTN_TOUCH:

+247 −33
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device,
	report_enum->report_id_hash[id] = report;

	list_add_tail(&report->list, &report_enum->report_list);
	INIT_LIST_HEAD(&report->field_entry_list);

	return report;
}
@@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned

	field = kzalloc((sizeof(struct hid_field) +
			 usages * sizeof(struct hid_usage) +
			 usages * sizeof(unsigned)), GFP_KERNEL);
			 3 * usages * sizeof(unsigned int)), GFP_KERNEL);
	if (!field)
		return NULL;

@@ -109,6 +110,8 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
	report->field[field->index] = field;
	field->usage = (struct hid_usage *)(field + 1);
	field->value = (s32 *)(field->usage + usages);
	field->new_value = (s32 *)(field->value + usages);
	field->usages_priorities = (s32 *)(field->new_value + usages);
	field->report = report;

	return field;
@@ -656,6 +659,8 @@ static void hid_free_report(struct hid_report *report)
{
	unsigned n;

	kfree(report->field_entries);

	for (n = 0; n < report->maxfield; n++)
		kfree(report->field[n]);
	kfree(report);
@@ -1525,25 +1530,41 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
}

/*
 * Analyse a received field, and fetch the data from it. The field
 * content is stored for next report processing (we do differential
 * reporting to the layer).
 * Checks if the given value is valid within this field
 */
static inline int hid_array_value_is_valid(struct hid_field *field,
					   __s32 value)
{
	__s32 min = field->logical_minimum;

static void hid_input_field(struct hid_device *hid, struct hid_field *field,
			    __u8 *data, int interrupt)
	/*
	 * Value needs to be between logical min and max, and
	 * (value - min) is used as an index in the usage array.
	 * This array is of size field->maxusage
	 */
	return value >= min &&
	       value <= field->logical_maximum &&
	       value - min < field->maxusage;
}

/*
 * Fetch the field from the data. The field content is stored for next
 * report processing (we do differential reporting to the layer).
 */
static void hid_input_fetch_field(struct hid_device *hid,
				  struct hid_field *field,
				  __u8 *data)
{
	unsigned n;
	unsigned count = field->report_count;
	unsigned offset = field->report_offset;
	unsigned size = field->report_size;
	__s32 min = field->logical_minimum;
	__s32 max = field->logical_maximum;
	__s32 *value;

	value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC);
	if (!value)
		return;
	value = field->new_value;
	memset(value, 0, count * sizeof(__s32));
	field->ignored = false;

	for (n = 0; n < count; n++) {

@@ -1554,35 +1575,228 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,

		/* Ignore report if ErrorRollOver */
		if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
		    value[n] >= min && value[n] <= max &&
		    value[n] - min < field->maxusage &&
		    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
			goto exit;
		    hid_array_value_is_valid(field, value[n]) &&
		    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) {
			field->ignored = true;
			return;
		}
	}
}

	for (n = 0; n < count; n++) {
/*
 * Process a received variable field.
 */

		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
			hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
			continue;
static void hid_input_var_field(struct hid_device *hid,
				struct hid_field *field,
				int interrupt)
{
	unsigned int count = field->report_count;
	__s32 *value = field->new_value;
	unsigned int n;

	for (n = 0; n < count; n++)
		hid_process_event(hid,
				  field,
				  &field->usage[n],
				  value[n],
				  interrupt);

	memcpy(field->value, value, count * sizeof(__s32));
}

		if (field->value[n] >= min && field->value[n] <= max
			&& field->value[n] - min < field->maxusage
			&& field->usage[field->value[n] - min].hid
			&& search(value, field->value[n], count))
				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
/*
 * Process a received array field. The field content is stored for
 * next report processing (we do differential reporting to the layer).
 */

		if (value[n] >= min && value[n] <= max
			&& value[n] - min < field->maxusage
			&& field->usage[value[n] - min].hid
			&& search(field->value, value[n], count))
				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
static void hid_input_array_field(struct hid_device *hid,
				  struct hid_field *field,
				  int interrupt)
{
	unsigned int n;
	unsigned int count = field->report_count;
	__s32 min = field->logical_minimum;
	__s32 *value;

	value = field->new_value;

	/* ErrorRollOver */
	if (field->ignored)
		return;

	for (n = 0; n < count; n++) {
		if (hid_array_value_is_valid(field, field->value[n]) &&
		    search(value, field->value[n], count))
			hid_process_event(hid,
					  field,
					  &field->usage[field->value[n] - min],
					  0,
					  interrupt);

		if (hid_array_value_is_valid(field, value[n]) &&
		    search(field->value, value[n], count))
			hid_process_event(hid,
					  field,
					  &field->usage[value[n] - min],
					  1,
					  interrupt);
	}

	memcpy(field->value, value, count * sizeof(__s32));
exit:
	kfree(value);
}

/*
 * Analyse a received report, and fetch the data from it. The field
 * content is stored for next report processing (we do differential
 * reporting to the layer).
 */
static void hid_process_report(struct hid_device *hid,
			       struct hid_report *report,
			       __u8 *data,
			       int interrupt)
{
	unsigned int a;
	struct hid_field_entry *entry;
	struct hid_field *field;

	/* first retrieve all incoming values in data */
	for (a = 0; a < report->maxfield; a++)
		hid_input_fetch_field(hid, field = report->field[a], data);

	if (!list_empty(&report->field_entry_list)) {
		/* INPUT_REPORT, we have a priority list of fields */
		list_for_each_entry(entry,
				    &report->field_entry_list,
				    list) {
			field = entry->field;

			if (field->flags & HID_MAIN_ITEM_VARIABLE)
				hid_process_event(hid,
						  field,
						  &field->usage[entry->index],
						  field->new_value[entry->index],
						  interrupt);
			else
				hid_input_array_field(hid, field, interrupt);
		}

		/* we need to do the memcpy at the end for var items */
		for (a = 0; a < report->maxfield; a++) {
			field = report->field[a];

			if (field->flags & HID_MAIN_ITEM_VARIABLE)
				memcpy(field->value, field->new_value,
				       field->report_count * sizeof(__s32));
		}
	} else {
		/* FEATURE_REPORT, regular processing */
		for (a = 0; a < report->maxfield; a++) {
			field = report->field[a];

			if (field->flags & HID_MAIN_ITEM_VARIABLE)
				hid_input_var_field(hid, field, interrupt);
			else
				hid_input_array_field(hid, field, interrupt);
		}
	}
}

/*
 * Insert a given usage_index in a field in the list
 * of processed usages in the report.
 *
 * The elements of lower priority score are processed
 * first.
 */
static void __hid_insert_field_entry(struct hid_device *hid,
				     struct hid_report *report,
				     struct hid_field_entry *entry,
				     struct hid_field *field,
				     unsigned int usage_index)
{
	struct hid_field_entry *next;

	entry->field = field;
	entry->index = usage_index;
	entry->priority = field->usages_priorities[usage_index];

	/* insert the element at the correct position */
	list_for_each_entry(next,
			    &report->field_entry_list,
			    list) {
		/*
		 * the priority of our element is strictly higher
		 * than the next one, insert it before
		 */
		if (entry->priority > next->priority) {
			list_add_tail(&entry->list, &next->list);
			return;
		}
	}

	/* lowest priority score: insert at the end */
	list_add_tail(&entry->list, &report->field_entry_list);
}

static void hid_report_process_ordering(struct hid_device *hid,
					struct hid_report *report)
{
	struct hid_field *field;
	struct hid_field_entry *entries;
	unsigned int a, u, usages;
	unsigned int count = 0;

	/* count the number of individual fields in the report */
	for (a = 0; a < report->maxfield; a++) {
		field = report->field[a];

		if (field->flags & HID_MAIN_ITEM_VARIABLE)
			count += field->report_count;
		else
			count++;
	}

	/* allocate the memory to process the fields */
	entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
	if (!entries)
		return;

	report->field_entries = entries;

	/*
	 * walk through all fields in the report and
	 * store them by priority order in report->field_entry_list
	 *
	 * - Var elements are individualized (field + usage_index)
	 * - Arrays are taken as one, we can not chose an order for them
	 */
	usages = 0;
	for (a = 0; a < report->maxfield; a++) {
		field = report->field[a];

		if (field->flags & HID_MAIN_ITEM_VARIABLE) {
			for (u = 0; u < field->report_count; u++) {
				__hid_insert_field_entry(hid, report,
							 &entries[usages],
							 field, u);
				usages++;
			}
		} else {
			__hid_insert_field_entry(hid, report, &entries[usages],
						 field, 0);
			usages++;
		}
	}
}

static void hid_process_ordering(struct hid_device *hid)
{
	struct hid_report *report;
	struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT];

	list_for_each_entry(report, &report_enum->report_list, list)
		hid_report_process_ordering(hid, report);
}

/*
@@ -1746,7 +1960,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
	struct hid_report_enum *report_enum = hid->report_enum + type;
	struct hid_report *report;
	struct hid_driver *hdrv;
	unsigned int a;
	u32 rsize, csize = size;
	u8 *cdata = data;
	int ret = 0;
@@ -1782,8 +1995,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
	}

	if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
		for (a = 0; a < report->maxfield; a++)
			hid_input_field(hid, report->field[a], cdata, interrupt);
		hid_process_report(hid, report, cdata, interrupt);
		hdrv = hid->driver;
		if (hdrv && hdrv->report)
			hdrv->report(hid, report);
@@ -1970,6 +2182,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
		return -ENODEV;
	}

	hid_process_ordering(hdev);

	if ((hdev->claimed & HID_CLAIMED_INPUT) &&
			(connect_mask & HID_CONNECT_FF) && hdev->ff_init)
		hdev->ff_init(hdev);
+295 −69
Original line number Diff line number Diff line
@@ -48,6 +48,51 @@ static const struct {
	__s32 y;
}  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};

struct usage_priority {
	__u32 usage;			/* the HID usage associated */
	bool global;			/* we assume all usages to be slotted,
					 * unless global
					 */
	unsigned int slot_overwrite;	/* for globals: allows to set the usage
					 * before or after the slots
					 */
};

/*
 * hid-input will convert this list into priorities:
 * the first element will have the highest priority
 * (the length of the following array) and the last
 * element the lowest (1).
 *
 * hid-input will then shift the priority by 8 bits to leave some space
 * in case drivers want to interleave other fields.
 *
 * To accommodate slotted devices, the slot priority is
 * defined in the next 8 bits (defined by 0xff - slot).
 *
 * If drivers want to add fields before those, hid-input will
 * leave out the first 8 bits of the priority value.
 *
 * This still leaves us 65535 individual priority values.
 */
static const struct usage_priority hidinput_usages_priorities[] = {
	{ /* Eraser (eraser touching) must always come before tipswitch */
	  .usage = HID_DG_ERASER,
	},
	{ /* Invert must always come before In Range */
	  .usage = HID_DG_INVERT,
	},
	{ /* Is the tip of the tool touching? */
	  .usage = HID_DG_TIPSWITCH,
	},
	{ /* Tip Pressure might emulate tip switch */
	  .usage = HID_DG_TIPPRESSURE,
	},
	{ /* In Range needs to come after the other tool states */
	  .usage = HID_DG_INRANGE,
	},
};

#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))
@@ -586,11 +631,13 @@ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_f
}

static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
				     struct hid_usage *usage)
				     struct hid_usage *usage, unsigned int usage_index)
{
	struct input_dev *input = hidinput->input;
	struct hid_device *device = input_get_drvdata(input);
	const struct usage_priority *usage_priority = NULL;
	int max = 0, code;
	unsigned int i = 0;
	unsigned long *bit = NULL;

	field->hidinput = hidinput;
@@ -608,6 +655,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
		goto ignore;
	}

	/* assign a priority based on the static list declared here */
	for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
		if (usage->hid == hidinput_usages_priorities[i].usage) {
			usage_priority = &hidinput_usages_priorities[i];

			field->usages_priorities[usage_index] =
				(ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
			break;
		}
	}

	/*
	 * For slotted devices, we need to also add the slot index
	 * in the priority.
	 */
	if (usage_priority && usage_priority->global)
		field->usages_priorities[usage_index] |=
			usage_priority->slot_overwrite;
	else
		field->usages_priorities[usage_index] |=
			(0xff - field->slot_idx) << 16;

	if (device->driver->input_mapping) {
		int ret = device->driver->input_mapping(device, hidinput, field,
				usage, &bit, &max);
@@ -828,10 +897,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
			break;

		case 0x32: /* InRange */
			switch (field->physical & 0xff) {
			case 0x21: map_key(BTN_TOOL_MOUSE); break;
			case 0x22: map_key(BTN_TOOL_FINGER); break;
			default: map_key(BTN_TOOL_PEN); break;
			switch (field->physical) {
			case HID_DG_PUCK:
				map_key(BTN_TOOL_MOUSE);
				break;
			case HID_DG_FINGER:
				map_key(BTN_TOOL_FINGER);
				break;
			default:
				/*
				 * If the physical is not given,
				 * rely on the application.
				 */
				if (!field->physical) {
					switch (field->application) {
					case HID_DG_TOUCHSCREEN:
					case HID_DG_TOUCHPAD:
						map_key_clear(BTN_TOOL_FINGER);
						break;
					default:
						map_key_clear(BTN_TOOL_PEN);
					}
				} else {
					map_key(BTN_TOOL_PEN);
				}
				break;
			}
			break;

@@ -1315,9 +1405,38 @@ static void hidinput_handle_scroll(struct hid_usage *usage,
	input_event(input, EV_REL, usage->code, hi_res);
}

static void hid_report_release_tool(struct hid_report *report, struct input_dev *input,
				    unsigned int tool)
{
	/* if the given tool is not currently reported, ignore */
	if (!test_bit(tool, input->key))
		return;

	/*
	 * if the given tool was previously set, release it,
	 * release any TOUCH and send an EV_SYN
	 */
	input_event(input, EV_KEY, BTN_TOUCH, 0);
	input_event(input, EV_KEY, tool, 0);
	input_event(input, EV_SYN, SYN_REPORT, 0);

	report->tool = 0;
}

static void hid_report_set_tool(struct hid_report *report, struct input_dev *input,
				unsigned int new_tool)
{
	if (report->tool != new_tool)
		hid_report_release_tool(report, input, report->tool);

	input_event(input, EV_KEY, new_tool, 1);
	report->tool = new_tool;
}

void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
	struct input_dev *input;
	struct hid_report *report = field->report;
	unsigned *quirks = &hid->quirks;

	if (!usage->type)
@@ -1333,12 +1452,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct

	input = field->hidinput->input;

	if (usage->type == EV_ABS &&
	    (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
	     ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) {
		value = field->logical_maximum - value;
	}

	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
		int hat_dir = usage->hat_dir;
		if (!hat_dir)
@@ -1349,48 +1462,129 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
		return;
	}

	if (usage->hid == HID_DG_INVERT) {
		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
	/*
	 * Ignore out-of-range values as per HID specification,
	 * section 5.10 and 6.2.25, when NULL state bit is present.
	 * When it's not, clamp the value to match Microsoft's input
	 * driver as mentioned in "Required HID usages for digitizers":
	 * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp
	 *
	 * The logical_minimum < logical_maximum check is done so that we
	 * don't unintentionally discard values sent by devices which
	 * don't specify logical min and max.
	 */
	if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
	    field->logical_minimum < field->logical_maximum) {
		if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
		    (value < field->logical_minimum ||
		     value > field->logical_maximum)) {
			dbg_hid("Ignoring out-of-range value %x\n", value);
			return;
		}
		value = clamp(value,
			      field->logical_minimum,
			      field->logical_maximum);
	}

	if (usage->hid == HID_DG_INRANGE) {
		if (value) {
			input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
	switch (usage->hid) {
	case HID_DG_ERASER:
		report->tool_active |= !!value;

		/*
		 * if eraser is set, we must enforce BTN_TOOL_RUBBER
		 * to accommodate for devices not following the spec.
		 */
		if (value)
			hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
		else if (report->tool != BTN_TOOL_RUBBER)
			/* value is off, tool is not rubber, ignore */
			return;
		}
		input_event(input, usage->type, usage->code, 0);
		input_event(input, usage->type, BTN_TOOL_RUBBER, 0);

		/* let hid-input set BTN_TOUCH */
		break;

	case HID_DG_INVERT:
		report->tool_active |= !!value;

		/*
		 * If invert is set, we store BTN_TOOL_RUBBER.
		 */
		if (value)
			hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
		else if (!report->tool_active)
			/* tool_active not set means Invert and Eraser are not set */
			hid_report_release_tool(report, input, BTN_TOOL_RUBBER);

		/* no further processing */
		return;

	case HID_DG_INRANGE:
		report->tool_active |= !!value;

		if (report->tool_active) {
			/*
			 * if tool is not set but is marked as active,
			 * assume ours
			 */
			if (!report->tool)
				hid_report_set_tool(report, input, usage->code);
		} else {
			hid_report_release_tool(report, input, usage->code);
		}

	if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) {
		/* reset tool_active for the next event */
		report->tool_active = false;

		/* no further processing */
		return;

	case HID_DG_TIPSWITCH:
		report->tool_active |= !!value;

		/* if tool is set to RUBBER we should ignore the current value */
		if (report->tool == BTN_TOOL_RUBBER)
			return;

		break;

	case HID_DG_TIPPRESSURE:
		if (*quirks & HID_QUIRK_NOTOUCH) {
			int a = field->logical_minimum;
			int b = field->logical_maximum;
		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));

			if (value > a + ((b - a) >> 3)) {
				input_event(input, EV_KEY, BTN_TOUCH, 1);
				report->tool_active = true;
			}
		}
		break;

	if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
	case HID_UP_PID | 0x83UL: /* Simultaneous Effects Max */
		dbg_hid("Maximum Effects - %d\n",value);
		return;
	}

	if (usage->hid == (HID_UP_PID | 0x7fUL)) {
	case HID_UP_PID | 0x7fUL:
		dbg_hid("PID Pool Report\n");
		return;
	}

	if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
	switch (usage->type) {
	case EV_KEY:
		if (usage->code == 0) /* Key 0 is "unassigned", not KEY_UNKNOWN */
			return;
		break;

	if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
					usage->code == REL_HWHEEL_HI_RES)) {
	case EV_REL:
		if (usage->code == REL_WHEEL_HI_RES ||
		    usage->code == REL_HWHEEL_HI_RES) {
			hidinput_handle_scroll(usage, input, value);
			return;
		}
		break;

	if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
			(usage->code == ABS_VOLUME)) {
	case EV_ABS:
		if ((field->flags & HID_MAIN_ITEM_RELATIVE) &&
		    usage->code == ABS_VOLUME) {
			int count = abs(value);
			int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
			int i;
@@ -1402,30 +1596,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
				input_sync(input);
			}
			return;
	}

	/*
	 * Ignore out-of-range values as per HID specification,
	 * section 5.10 and 6.2.25, when NULL state bit is present.
	 * When it's not, clamp the value to match Microsoft's input
	 * driver as mentioned in "Required HID usages for digitizers":
	 * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp
	 *
	 * The logical_minimum < logical_maximum check is done so that we
	 * don't unintentionally discard values sent by devices which
	 * don't specify logical min and max.
	 */
	if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
	    (field->logical_minimum < field->logical_maximum)) {
		if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
		    (value < field->logical_minimum ||
		     value > field->logical_maximum)) {
			dbg_hid("Ignoring out-of-range value %x\n", value);
			return;
		}
		value = clamp(value,
			      field->logical_minimum,
			      field->logical_maximum);
		} else if (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
			   ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))
			value = field->logical_maximum - value;
		break;
	}

	/*
@@ -1930,12 +2105,63 @@ static struct hid_input *hidinput_match_application(struct hid_report *report)
static inline void hidinput_configure_usages(struct hid_input *hidinput,
					     struct hid_report *report)
{
	int i, j;
	int i, j, k;
	int first_field_index = 0;
	int slot_collection_index = -1;
	int prev_collection_index = -1;
	unsigned int slot_idx = 0;
	struct hid_field *field;

	/*
	 * First tag all the fields that are part of a slot,
	 * a slot needs to have one Contact ID in the collection
	 */
	for (i = 0; i < report->maxfield; i++) {
		field = report->field[i];

		/* ignore fields without usage */
		if (field->maxusage < 1)
			continue;

		/*
		 * janitoring when collection_index changes
		 */
		if (prev_collection_index != field->usage->collection_index) {
			prev_collection_index = field->usage->collection_index;
			first_field_index = i;
		}

		/*
		 * if we already found a Contact ID in the collection,
		 * tag and continue to the next.
		 */
		if (slot_collection_index == field->usage->collection_index) {
			field->slot_idx = slot_idx;
			continue;
		}

		/* check if the current field has Contact ID */
		for (j = 0; j < field->maxusage; j++) {
			if (field->usage[j].hid == HID_DG_CONTACTID) {
				slot_collection_index = field->usage->collection_index;
				slot_idx++;

				/*
				 * mark all previous fields and this one in the
				 * current collection to be slotted.
				 */
				for (k = first_field_index; k <= i; k++)
					report->field[k]->slot_idx = slot_idx;
				break;
			}
		}
	}

	for (i = 0; i < report->maxfield; i++)
		for (j = 0; j < report->field[i]->maxusage; j++)
			hidinput_configure_usage(hidinput, report->field[i],
						 report->field[i]->usage + j);
						 report->field[i]->usage + j,
						 j);
}

/*
+21 −2
Original line number Diff line number Diff line
@@ -347,7 +347,7 @@ struct hid_item {
 */
#define MAX_USBHID_BOOT_QUIRKS 4

#define HID_QUIRK_INVERT			BIT(0)
/* BIT(0) reserved for backward compatibility, was HID_QUIRK_INVERT */
#define HID_QUIRK_NOTOUCH			BIT(1)
#define HID_QUIRK_IGNORE			BIT(2)
#define HID_QUIRK_NOGET				BIT(3)
@@ -476,31 +476,50 @@ struct hid_field {
	unsigned  report_count;		/* number of this field in the report */
	unsigned  report_type;		/* (input,output,feature) */
	__s32    *value;		/* last known value(s) */
	__s32    *new_value;		/* newly read value(s) */
	__s32    *usages_priorities;	/* priority of each usage when reading the report
					 * bits 8-16 are reserved for hid-input usage
					 */
	__s32     logical_minimum;
	__s32     logical_maximum;
	__s32     physical_minimum;
	__s32     physical_maximum;
	__s32     unit_exponent;
	unsigned  unit;
	bool      ignored;		/* this field is ignored in this event */
	struct hid_report *report;	/* associated report */
	unsigned index;			/* index into report->field[] */
	/* hidinput data */
	struct hid_input *hidinput;	/* associated input structure */
	__u16 dpad;			/* dpad input code */
	unsigned int slot_idx;		/* slot index in a report */
};

#define HID_MAX_FIELDS 256

struct hid_field_entry {
	struct list_head list;
	struct hid_field *field;
	unsigned int index;
	__s32 priority;
};

struct hid_report {
	struct list_head list;
	struct list_head hidinput_list;
	struct list_head field_entry_list;		/* ordered list of input fields */
	unsigned int id;				/* id of this report */
	unsigned int type;				/* report type */
	unsigned int application;			/* application usage for this report */
	struct hid_field *field[HID_MAX_FIELDS];	/* fields of the report */
	struct hid_field_entry *field_entries;		/* allocated memory of input field_entry */
	unsigned maxfield;				/* maximum valid field index */
	unsigned size;					/* size of the report (bits) */
	struct hid_device *device;			/* associated device */

	/* tool related state */
	bool tool_active;				/* whether the current tool is active */
	unsigned int tool;				/* BTN_TOOL_* */
};

#define HID_MAX_IDS 256