HID: move connect quirks
Move connecting from usbhid to the hid layer and fix also hidp in
that manner.
This removes all the ignore/force hidinput/hiddev connecting quirks.
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 26e16083..ebca00e 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -107,7 +107,7 @@
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 2a68661..f0b1778 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -309,6 +309,7 @@
{
unsigned long quirks = id->driver_data;
struct apple_sc *asc;
+ unsigned int connect_mask = HID_CONNECT_DEFAULT;
int ret;
/* return something else or move to hid layer? device will reside
@@ -328,18 +329,18 @@
hid_set_drvdata(hdev, asc);
- if (quirks & APPLE_HIDDEV)
- hdev->quirks |= HID_QUIRK_HIDDEV;
- if (quirks & APPLE_IGNORE_HIDINPUT)
- hdev->quirks |= HID_QUIRK_IGNORE_HIDINPUT;
-
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "parse failed\n");
goto err_free;
}
- ret = hid_hw_start(hdev);
+ if (quirks & APPLE_HIDDEV)
+ connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+ if (quirks & APPLE_IGNORE_HIDINPUT)
+ connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+ ret = hid_hw_start(hdev, connect_mask);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index 050b989..12c8a9b 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -54,16 +54,14 @@
hid_set_drvdata(hdev, (void *)quirks);
- if (quirks & BELKIN_HIDDEV)
- hdev->quirks |= HID_QUIRK_HIDDEV;
-
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "parse failed\n");
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+ ((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index ea5f8bc..699547c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1113,6 +1113,80 @@
}
EXPORT_SYMBOL_GPL(hid_input_report);
+int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
+{
+ static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
+ "Joystick", "Gamepad", "Keyboard", "Keypad",
+ "Multi-Axis Controller"
+ };
+ const char *type, *bus;
+ char buf[64];
+ unsigned int i;
+ int len;
+
+ if (hdev->bus != BUS_USB)
+ connect_mask &= ~HID_CONNECT_HIDDEV;
+
+ if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
+ connect_mask & HID_CONNECT_HIDINPUT_FORCE))
+ hdev->claimed |= HID_CLAIMED_INPUT;
+ if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
+ !hdev->hiddev_connect(hdev,
+ connect_mask & HID_CONNECT_HIDDEV_FORCE))
+ hdev->claimed |= HID_CLAIMED_HIDDEV;
+ if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
+ hdev->claimed |= HID_CLAIMED_HIDRAW;
+
+ if (!hdev->claimed) {
+ dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
+ "hidraw\n");
+ return -ENODEV;
+ }
+
+ if ((hdev->claimed & HID_CLAIMED_INPUT) &&
+ (connect_mask & HID_CONNECT_FF) && hdev->ff_init)
+ hdev->ff_init(hdev);
+
+ len = 0;
+ if (hdev->claimed & HID_CLAIMED_INPUT)
+ len += sprintf(buf + len, "input");
+ if (hdev->claimed & HID_CLAIMED_HIDDEV)
+ len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
+ hdev->minor);
+ if (hdev->claimed & HID_CLAIMED_HIDRAW)
+ len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
+ ((struct hidraw *)hdev->hidraw)->minor);
+
+ type = "Device";
+ for (i = 0; i < hdev->maxcollection; i++) {
+ struct hid_collection *col = &hdev->collection[i];
+ if (col->type == HID_COLLECTION_APPLICATION &&
+ (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+ (col->usage & 0xffff) < ARRAY_SIZE(types)) {
+ type = types[col->usage & 0xffff];
+ break;
+ }
+ }
+
+ switch (hdev->bus) {
+ case BUS_USB:
+ bus = "USB";
+ break;
+ case BUS_BLUETOOTH:
+ bus = "BLUETOOTH";
+ break;
+ default:
+ bus = "<UNKNOWN>";
+ }
+
+ dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+ buf, bus, hdev->version >> 8, hdev->version & 0xff,
+ type, hdev->name, hdev->phys);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_connect);
+
static bool hid_match_one_id(struct hid_device *hdev,
const struct hid_device_id *id)
{
@@ -1238,7 +1312,7 @@
} else { /* default probe */
ret = hid_parse(hdev);
if (!ret)
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
if (ret)
hdev->driver = NULL;
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index a1e13f1..5d69d27 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -110,7 +110,7 @@
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-dell.c b/drivers/hid/hid-dell.c
index 5d1d54c..788faa6b 100644
--- a/drivers/hid/hid-dell.c
+++ b/drivers/hid/hid-dell.c
@@ -34,7 +34,7 @@
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 0a68935..7f183b7 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -700,7 +700,7 @@
* Read all reports and initialize the absolute field values.
*/
-int hidinput_connect(struct hid_device *hid)
+int hidinput_connect(struct hid_device *hid, unsigned int force)
{
struct hid_report *report;
struct hid_input *hidinput = NULL;
@@ -708,19 +708,20 @@
int i, j, k;
int max_report_type = HID_OUTPUT_REPORT;
- if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
- return -1;
-
INIT_LIST_HEAD(&hid->inputs);
- for (i = 0; i < hid->maxcollection; i++)
- if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
- hid->collection[i].type == HID_COLLECTION_PHYSICAL)
- if (IS_INPUT_APPLICATION(hid->collection[i].usage))
- break;
+ if (!force) {
+ for (i = 0; i < hid->maxcollection; i++) {
+ struct hid_collection *col = &hid->collection[i];
+ if (col->type == HID_COLLECTION_APPLICATION ||
+ col->type == HID_COLLECTION_PHYSICAL)
+ if (IS_INPUT_APPLICATION(col->usage))
+ break;
+ }
- if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
- return -1;
+ if (i == hid->maxcollection)
+ return -1;
+ }
if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
max_report_type = HID_INPUT_REPORT;
diff --git a/drivers/hid/hid-logitech.c b/drivers/hid/hid-logitech.c
index b2aaebe..7322582 100644
--- a/drivers/hid/hid-logitech.c
+++ b/drivers/hid/hid-logitech.c
@@ -237,7 +237,7 @@
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 1fa8b81..d718b16 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -154,8 +154,6 @@
hid_set_drvdata(hdev, (void *)quirks);
- if (quirks & MS_HIDINPUT)
- hdev->quirks |= HID_QUIRK_HIDINPUT;
if (quirks & MS_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
@@ -165,7 +163,8 @@
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
+ HID_CONNECT_HIDINPUT_FORCE : 0));
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index 4109244..10945fe 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -80,7 +80,7 @@
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 8771bfa..15f3c04 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -52,15 +52,14 @@
{
int ret;
- hdev->quirks |= HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT;
-
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "parse failed\n");
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) |
+ HID_CONNECT_HIDDEV_FORCE);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 97668c6..3af8095 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -57,15 +57,14 @@
{
int ret;
- hdev->quirks |= HID_QUIRK_HIDDEV;
-
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "parse failed\n");
goto err_free;
}
- ret = hid_hw_start(hdev);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+ HID_CONNECT_HIDDEV_FORCE);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b41d011..0513b60 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -44,8 +44,6 @@
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
- "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
/*
* Module parameters.
*/
@@ -670,70 +668,6 @@
usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
-static int usbhid_start_finish(struct hid_device *hid)
-{
- struct usb_interface *intf = to_usb_interface(hid->dev.parent);
- char path[64], *type;
- unsigned int i;
-
- usbhid_init_reports(hid);
- hid_dump_device(hid);
- if (hid->quirks & HID_QUIRK_RESET_LEDS)
- usbhid_set_leds(hid);
-
- if (!hidinput_connect(hid))
- hid->claimed |= HID_CLAIMED_INPUT;
- if (!hiddev_connect(hid))
- hid->claimed |= HID_CLAIMED_HIDDEV;
- if (!hidraw_connect(hid))
- hid->claimed |= HID_CLAIMED_HIDRAW;
-
- if (!hid->claimed) {
- printk(KERN_ERR "HID device claimed by neither input, hiddev "
- "nor hidraw\n");
- return -ENODEV;
- }
-
- if ((hid->claimed & HID_CLAIMED_INPUT))
- hid_ff_init(hid);
-
- printk(KERN_INFO);
-
- if (hid->claimed & HID_CLAIMED_INPUT)
- printk("input");
- if ((hid->claimed & HID_CLAIMED_INPUT) &&
- ((hid->claimed & HID_CLAIMED_HIDDEV) ||
- hid->claimed & HID_CLAIMED_HIDRAW))
- printk(",");
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- printk("hiddev%d", hid->minor);
- if ((hid->claimed & HID_CLAIMED_INPUT) &&
- (hid->claimed & HID_CLAIMED_HIDDEV) &&
- (hid->claimed & HID_CLAIMED_HIDRAW))
- printk(",");
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- printk("hidraw%d", ((struct hidraw *)hid->hidraw)->minor);
-
- type = "Device";
- for (i = 0; i < hid->maxcollection; i++) {
- if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
- (hid->collection[i].usage & HID_USAGE_PAGE) ==
- HID_UP_GENDESK &&
- (hid->collection[i].usage & 0xffff) <
- ARRAY_SIZE(hid_types)) {
- type = hid_types[hid->collection[i].usage & 0xffff];
- break;
- }
- }
-
- usb_make_path(interface_to_usbdev(intf), path, 63);
-
- printk(": USB HID v%x.%02x %s [%s] on %s\n",
- hid->version >> 8, hid->version & 0xff, type, hid->name, path);
-
- return 0;
-}
-
static int usbhid_parse(struct hid_device *hid)
{
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
@@ -923,9 +857,11 @@
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
- ret = usbhid_start_finish(hid);
- if (ret)
- goto fail;
+ usbhid_init_reports(hid);
+ hid_dump_device(hid);
+
+ if (hid->quirks & HID_QUIRK_RESET_LEDS)
+ usbhid_set_leds(hid);
return 0;
@@ -1000,7 +936,9 @@
usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver;
hid->hid_output_raw_report = usbhid_output_raw_report;
+ hid->ff_init = hid_ff_init;
#ifdef CONFIG_USB_HIDDEV
+ hid->hiddev_connect = hiddev_connect;
hid->hiddev_hid_event = hiddev_hid_event;
hid->hiddev_report_event = hiddev_report_event;
#endif
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 842e9ed..babd65d 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -790,21 +790,23 @@
/*
* This is where hid.c calls us to connect a hid device to the hiddev driver
*/
-int hiddev_connect(struct hid_device *hid)
+int hiddev_connect(struct hid_device *hid, unsigned int force)
{
struct hiddev *hiddev;
struct usbhid_device *usbhid = hid->driver_data;
- int i;
int retval;
- for (i = 0; i < hid->maxcollection; i++)
- if (hid->collection[i].type ==
- HID_COLLECTION_APPLICATION &&
- !IS_INPUT_APPLICATION(hid->collection[i].usage))
- break;
+ if (!force) {
+ unsigned int i;
+ for (i = 0; i < hid->maxcollection; i++)
+ if (hid->collection[i].type ==
+ HID_COLLECTION_APPLICATION &&
+ !IS_INPUT_APPLICATION(hid->collection[i].usage))
+ break;
- if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
- return -1;
+ if (i == hid->maxcollection)
+ return -1;
+ }
if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 43aa51a..043209f 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -247,6 +247,19 @@
#define HID_FEATURE_REPORT 2
/*
+ * HID connect requests
+ */
+
+#define HID_CONNECT_HIDINPUT 0x01
+#define HID_CONNECT_HIDINPUT_FORCE 0x02
+#define HID_CONNECT_HIDRAW 0x04
+#define HID_CONNECT_HIDDEV 0x08
+#define HID_CONNECT_HIDDEV_FORCE 0x10
+#define HID_CONNECT_FF 0x20
+#define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
+ HID_CONNECT_HIDDEV|HID_CONNECT_FF)
+
+/*
* HID device quirks.
*/
@@ -258,13 +271,10 @@
#define HID_QUIRK_INVERT 0x00000001
#define HID_QUIRK_NOTOUCH 0x00000002
#define HID_QUIRK_NOGET 0x00000008
-#define HID_QUIRK_HIDDEV 0x00000010
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_RESET_LEDS 0x00100000
-#define HID_QUIRK_HIDINPUT 0x00200000
-#define HID_QUIRK_IGNORE_HIDINPUT 0x01000000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
/*
@@ -439,7 +449,11 @@
void *driver_data;
+ /* temporary hid_ff handling (until moved to the drivers) */
+ int (*ff_init)(struct hid_device *);
+
/* hiddev event handler */
+ int (*hiddev_connect)(struct hid_device *, unsigned int);
void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
@@ -610,7 +624,7 @@
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *);
+extern int hidinput_connect(struct hid_device *hid, unsigned int force);
extern void hidinput_disconnect(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
@@ -619,6 +633,7 @@
void hid_output_report(struct hid_report *report, __u8 *data);
struct hid_device *hid_allocate_device(void);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_connect(struct hid_device *hid, unsigned int connect_mask);
/**
* hid_map_usage - map usage input bits
@@ -700,14 +715,22 @@
* hid_hw_start - start underlaying HW
*
* @hdev: hid device
+ * @connect_mask: which outputs to connect, see HID_CONNECT_*
*
* Call this in probe function *after* hid_parse. This will setup HW buffers
* and start the device (if not deffered to device open). hid_hw_stop must be
* called if this was successfull.
*/
-static inline int __must_check hid_hw_start(struct hid_device *hdev)
+static inline int __must_check hid_hw_start(struct hid_device *hdev,
+ unsigned int connect_mask)
{
- return hdev->ll_driver->start(hdev);
+ int ret = hdev->ll_driver->start(hdev);
+ if (ret || !connect_mask)
+ return ret;
+ ret = hid_connect(hdev, connect_mask);
+ if (ret)
+ hdev->ll_driver->stop(hdev);
+ return ret;
}
/**
@@ -749,7 +772,7 @@
#endif
#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#define hid_ff_init NULL
#endif
#ifdef CONFIG_HID_DEBUG
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
index a416b90..6ae77b3 100644
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -217,7 +217,7 @@
struct hid_report;
#ifdef CONFIG_USB_HIDDEV
-int hiddev_connect(struct hid_device *);
+int hiddev_connect(struct hid_device *hid, unsigned int force);
void hiddev_disconnect(struct hid_device *);
void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value);
@@ -225,7 +225,9 @@
int __init hiddev_init(void);
void hiddev_exit(void);
#else
-static inline int hiddev_connect(struct hid_device *hid) { return -1; }
+static inline int hiddev_connect(struct hid_device *hid,
+ unsigned int force)
+{ return -1; }
static inline void hiddev_disconnect(struct hid_device *hid) { }
static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value) { }
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index f3d8307..acdeab3 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -724,9 +724,6 @@
report_list, list)
hidp_send_report(session, report);
- if (hidinput_connect(hid) == 0)
- hid->claimed |= HID_CLAIMED_INPUT;
-
return 0;
}