Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25721aef authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-4.18/multitouch' into for-linus

- improvement of duplicate usage handling in hid-input from Benjamin Tissoires
- Win 8.1 precisioun touchpad spec implementation from Benjamin Tissoires
parents 72d0beb4 abb36fe6
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -57,7 +57,9 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle
 * Register a new report for a device.
 */

struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
struct hid_report *hid_register_report(struct hid_device *device,
				       unsigned int type, unsigned int id,
				       unsigned int application)
{
	struct hid_report_enum *report_enum = device->report_enum + type;
	struct hid_report *report;
@@ -78,6 +80,7 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
	report->type = type;
	report->size = 0;
	report->device = device;
	report->application = application;
	report_enum->report_id_hash[id] = report;

	list_add_tail(&report->list, &report_enum->report_list);
@@ -221,11 +224,15 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
{
	struct hid_report *report;
	struct hid_field *field;
	unsigned usages;
	unsigned offset;
	unsigned i;
	unsigned int usages;
	unsigned int offset;
	unsigned int i;
	unsigned int application;

	application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);

	report = hid_register_report(parser->device, report_type, parser->global.report_id);
	report = hid_register_report(parser->device, report_type,
				     parser->global.report_id, application);
	if (!report) {
		hid_err(parser->device, "hid_register_report failed\n");
		return -1;
@@ -259,7 +266,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign

	field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
	field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
	field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
	field->application = application;

	for (i = 0; i < usages; i++) {
		unsigned j = i;
+15 −0
Original line number Diff line number Diff line
@@ -56,6 +56,20 @@ static bool hid_generic_match(struct hid_device *hdev,
	return true;
}

static int hid_generic_probe(struct hid_device *hdev,
			     const struct hid_device_id *id)
{
	int ret;

	hdev->quirks |= HID_QUIRK_INPUT_PER_APP;

	ret = hid_parse(hdev);
	if (ret)
		return ret;

	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}

static const struct hid_device_id hid_table[] = {
	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
	{ }
@@ -66,6 +80,7 @@ static struct hid_driver hid_generic = {
	.name = "hid-generic",
	.id_table = hid_table,
	.match = hid_generic_match,
	.probe = hid_generic_probe,
};
module_hid_driver(hid_generic);

+1 −1
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
		 * those reports reach gfrm_raw_event() from hid_input_report().
		 */
		if (!hid_register_report(hdev, HID_INPUT_REPORT,
					 GFRM100_SEARCH_KEY_REPORT_ID)) {
					 GFRM100_SEARCH_KEY_REPORT_ID, 0)) {
			ret = -ENOMEM;
			goto done;
		}
+113 −10
Original line number Diff line number Diff line
@@ -1110,8 +1110,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel

	set_bit(usage->type, input->evbit);

	while (usage->code <= max && test_and_set_bit(usage->code, bit))
		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
	/*
	 * This part is *really* controversial:
	 * - HID aims at being generic so we should do our best to export
	 *   all incoming events
	 * - HID describes what events are, so there is no reason for ABS_X
	 *   to be mapped to ABS_Y
	 * - HID is using *_MISC+N as a default value, but nothing prevents
	 *   *_MISC+N to overwrite a legitimate even, which confuses userspace
	 *   (for instance ABS_MISC + 7 is ABS_MT_SLOT, which has a different
	 *   processing)
	 *
	 * If devices still want to use this (at their own risk), they will
	 * have to use the quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE, but
	 * the default should be a reliable mapping.
	 */
	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
		if (device->quirks & HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE) {
			usage->code = find_next_zero_bit(bit,
							 max + 1,
							 usage->code);
		} else {
			device->status |= HID_STAT_DUP_DETECTED;
			goto ignore;
		}
	}

	if (usage->code > max)
		goto ignore;
@@ -1487,15 +1510,56 @@ static void report_features(struct hid_device *hid)
		}
}

static struct hid_input *hidinput_allocate(struct hid_device *hid)
static struct hid_input *hidinput_allocate(struct hid_device *hid,
					   unsigned int application)
{
	struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
	struct input_dev *input_dev = input_allocate_device();
	if (!hidinput || !input_dev) {
		kfree(hidinput);
		input_free_device(input_dev);
		hid_err(hid, "Out of memory during hid input probe\n");
		return NULL;
	const char *suffix = NULL;

	if (!hidinput || !input_dev)
		goto fail;

	if ((hid->quirks & HID_QUIRK_INPUT_PER_APP) &&
	    hid->maxapplication > 1) {
		switch (application) {
		case HID_GD_KEYBOARD:
			suffix = "Keyboard";
			break;
		case HID_GD_KEYPAD:
			suffix = "Keypad";
			break;
		case HID_GD_MOUSE:
			suffix = "Mouse";
			break;
		case HID_DG_STYLUS:
			suffix = "Pen";
			break;
		case HID_DG_TOUCHSCREEN:
			suffix = "Touchscreen";
			break;
		case HID_DG_TOUCHPAD:
			suffix = "Touchpad";
			break;
		case HID_GD_SYSTEM_CONTROL:
			suffix = "System Control";
			break;
		case HID_CP_CONSUMER_CONTROL:
			suffix = "Consumer Control";
			break;
		case HID_GD_WIRELESS_RADIO_CTLS:
			suffix = "Wireless Radio Control";
			break;
		default:
			break;
		}
	}

	if (suffix) {
		hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
					   hid->name, suffix);
		if (!hidinput->name)
			goto fail;
	}

	input_set_drvdata(input_dev, hid);
@@ -1505,7 +1569,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
	input_dev->setkeycode = hidinput_setkeycode;
	input_dev->getkeycode = hidinput_getkeycode;

	input_dev->name = hid->name;
	input_dev->name = hidinput->name ? hidinput->name : hid->name;
	input_dev->phys = hid->phys;
	input_dev->uniq = hid->uniq;
	input_dev->id.bustype = hid->bus;
@@ -1513,10 +1577,19 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
	input_dev->id.product = hid->product;
	input_dev->id.version = hid->version;
	input_dev->dev.parent = &hid->dev;

	hidinput->input = input_dev;
	list_add_tail(&hidinput->list, &hid->inputs);

	INIT_LIST_HEAD(&hidinput->reports);

	return hidinput;

fail:
	kfree(hidinput);
	input_free_device(input_dev);
	hid_err(hid, "Out of memory during hid input probe\n");
	return NULL;
}

static bool hidinput_has_been_populated(struct hid_input *hidinput)
@@ -1562,6 +1635,7 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,

	list_del(&hidinput->list);
	input_free_device(hidinput->input);
	kfree(hidinput->name);

	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
		if (k == HID_OUTPUT_REPORT &&
@@ -1594,6 +1668,20 @@ static struct hid_input *hidinput_match(struct hid_report *report)
	return NULL;
}

static struct hid_input *hidinput_match_application(struct hid_report *report)
{
	struct hid_device *hid = report->device;
	struct hid_input *hidinput;

	list_for_each_entry(hidinput, &hid->inputs, list) {
		if (hidinput->report &&
		    hidinput->report->application == report->application)
			return hidinput;
	}

	return NULL;
}

static inline void hidinput_configure_usages(struct hid_input *hidinput,
					     struct hid_report *report)
{
@@ -1616,11 +1704,14 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
	struct hid_driver *drv = hid->driver;
	struct hid_report *report;
	struct hid_input *next, *hidinput = NULL;
	unsigned int application;
	int i, k;

	INIT_LIST_HEAD(&hid->inputs);
	INIT_WORK(&hid->led_work, hidinput_led_worker);

	hid->status &= ~HID_STAT_DUP_DETECTED;

	if (!force) {
		for (i = 0; i < hid->maxcollection; i++) {
			struct hid_collection *col = &hid->collection[i];
@@ -1646,15 +1737,20 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
			if (!report->maxfield)
				continue;

			application = report->application;

			/*
			 * Find the previous hidinput report attached
			 * to this report id.
			 */
			if (hid->quirks & HID_QUIRK_MULTI_INPUT)
				hidinput = hidinput_match(report);
			else if (hid->maxapplication > 1 &&
				 (hid->quirks & HID_QUIRK_INPUT_PER_APP))
				hidinput = hidinput_match_application(report);

			if (!hidinput) {
				hidinput = hidinput_allocate(hid);
				hidinput = hidinput_allocate(hid, application);
				if (!hidinput)
					goto out_unwind;
			}
@@ -1663,6 +1759,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)

			if (hid->quirks & HID_QUIRK_MULTI_INPUT)
				hidinput->report = report;

			list_add_tail(&report->hidinput_list,
				      &hidinput->reports);
		}
	}

@@ -1687,6 +1786,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
		goto out_unwind;
	}

	if (hid->status & HID_STAT_DUP_DETECTED)
		hid_dbg(hid,
			"Some usages could not be mapped, please use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE if this is legitimate.\n");

	return 0;

out_unwind:
+3 −3
Original line number Diff line number Diff line
@@ -531,12 +531,12 @@ static int magicmouse_probe(struct hid_device *hdev,

	if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
		report = hid_register_report(hdev, HID_INPUT_REPORT,
			MOUSE_REPORT_ID);
			MOUSE_REPORT_ID, 0);
	else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
		report = hid_register_report(hdev, HID_INPUT_REPORT,
			TRACKPAD_REPORT_ID);
			TRACKPAD_REPORT_ID, 0);
		report = hid_register_report(hdev, HID_INPUT_REPORT,
			DOUBLE_REPORT_ID);
			DOUBLE_REPORT_ID, 0);
	}

	if (!report) {
Loading