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

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

Merge branch 'for-4.16/hid-quirks-cleanup/_base' into for-linus

This series from Benjamin Tissoires finally removes one of the big PITAs
in the hid-core, which is the absolute need of having added all the new
device IDs into the horrid hid_have_special_driver[]
parents 7cb4774e 332347d4
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -396,6 +396,17 @@ config HID_ITE
	---help---
	Support for ITE devices not fully compliant with HID standard.

config HID_JABRA
	tristate "Jabra USB HID Driver"
	depends on HID
	---help---
	Support for Jabra USB HID devices.

	Prevents mapping of vendor defined HID usages to input events. Without
	this driver HID	reports from Jabra devices may incorrectly be seen as
	mouse button events.
	Say M here if you may ever plug in a Jabra USB device.

config HID_TWINHAN
	tristate "Twinhan IR remote control"
	depends on HID
+2 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#
# Makefile for the HID driver
#
hid-y			:= hid-core.o hid-input.o
hid-y			:= hid-core.o hid-input.o hid-quirks.o
hid-$(CONFIG_DEBUG_FS)		+= hid-debug.o

obj-$(CONFIG_HID)		+= hid.o
@@ -52,6 +52,7 @@ obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
obj-$(CONFIG_HID_HYPERV_MOUSE)	+= hid-hyperv.o
obj-$(CONFIG_HID_ICADE)		+= hid-icade.o
obj-$(CONFIG_HID_ITE)		+= hid-ite.o
obj-$(CONFIG_HID_JABRA)		+= hid-jabra.o
obj-$(CONFIG_HID_KENSINGTON)	+= hid-kensington.o
obj-$(CONFIG_HID_KEYTOUCH)	+= hid-keytouch.o
obj-$(CONFIG_HID_KYE)		+= hid-kye.o
+56 −876

File changed.

Preview size limit exceeded, changes collapsed.

+67 −1
Original line number Diff line number Diff line
@@ -24,8 +24,71 @@

#include <linux/hid.h>

static struct hid_driver hid_generic;

static int __unmap_hid_generic(struct device *dev, void *data)
{
	struct hid_driver *hdrv = data;
	struct hid_device *hdev = to_hid_device(dev);

	/* only unbind matching devices already bound to hid-generic */
	if (hdev->driver != &hid_generic ||
	    hid_match_device(hdev, hdrv) == NULL)
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_release_driver(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

static void hid_generic_add_driver(struct hid_driver *hdrv)
{
	bus_for_each_dev(&hid_bus_type, NULL, hdrv, __unmap_hid_generic);
}

static void hid_generic_removed_driver(struct hid_driver *hdrv)
{
	int ret;

	ret = driver_attach(&hid_generic.driver);
}

static int __check_hid_generic(struct device_driver *drv, void *data)
{
	struct hid_driver *hdrv = to_hid_driver(drv);
	struct hid_device *hdev = data;

	if (hdrv == &hid_generic)
		return 0;

	return hid_match_device(hdev, hdrv) != NULL;
}

static bool hid_generic_match(struct hid_device *hdev,
			      bool ignore_special_driver)
{
	if (ignore_special_driver)
		return true;

	if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)
		return false;

	/*
	 * If any other driver wants the device, leave the device to this other
	 * driver.
	 */
	if (bus_for_each_drv(&hid_bus_type, NULL, hdev, __check_hid_generic))
		return false;

	return true;
}

static const struct hid_device_id hid_table[] = {
	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
	{ }
};
MODULE_DEVICE_TABLE(hid, hid_table);
@@ -33,6 +96,9 @@ MODULE_DEVICE_TABLE(hid, hid_table);
static struct hid_driver hid_generic = {
	.name = "hid-generic",
	.id_table = hid_table,
	.match = hid_generic_match,
	.bus_add_driver = hid_generic_add_driver,
	.bus_removed_driver = hid_generic_removed_driver,
};
module_hid_driver(hid_generic);

+58 −0
Original line number Diff line number Diff line
/*
 *  Jabra USB HID Driver
 *
 *  Copyright (c) 2017 Niels Skou Olsen <nolsen@jabra.com>
 */

/*
 * 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/hid.h>
#include <linux/module.h>

#include "hid-ids.h"

#define HID_UP_VENDOR_DEFINED_MIN	0xff000000
#define HID_UP_VENDOR_DEFINED_MAX	0xffff0000

static int jabra_input_mapping(struct hid_device *hdev,
			       struct hid_input *hi,
			       struct hid_field *field,
			       struct hid_usage *usage,
			       unsigned long **bit, int *max)
{
	int is_vendor_defined =
		((usage->hid & HID_USAGE_PAGE) >= HID_UP_VENDOR_DEFINED_MIN &&
		 (usage->hid & HID_USAGE_PAGE) <= HID_UP_VENDOR_DEFINED_MAX);

	dbg_hid("hid=0x%08x appl=0x%08x coll_idx=0x%02x usage_idx=0x%02x: %s\n",
		usage->hid,
		field->application,
		usage->collection_index,
		usage->usage_index,
		is_vendor_defined ? "ignored" : "defaulted");

	/* Ignore vendor defined usages, default map standard usages */
	return is_vendor_defined ? -1 : 0;
}

static const struct hid_device_id jabra_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_JABRA, HID_ANY_ID) },
	{ }
};
MODULE_DEVICE_TABLE(hid, jabra_devices);

static struct hid_driver jabra_driver = {
	.name = "jabra",
	.id_table = jabra_devices,
	.input_mapping = jabra_input_mapping,
};
module_hid_driver(jabra_driver);

MODULE_AUTHOR("Niels Skou Olsen <nolsen@jabra.com>");
MODULE_DESCRIPTION("Jabra USB HID Driver");
MODULE_LICENSE("GPL");
Loading