diff options
35 files changed, 665 insertions, 337 deletions
diff --git a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml index 1c191bc5a178..ce18d7dadae2 100644 --- a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml +++ b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml @@ -36,6 +36,13 @@ properties: vdd-supply: description: The 3.3V supply to the touchscreen. + mainboard-vddio-supply: + description: + The supply on the main board needed to power up IO signals going + to the touchscreen. This supply need not go to the touchscreen + itself as long as it allows the main board to make signals compatible + with what the touchscreen is expecting for its IO rails. + required: - compatible - reg diff --git a/MAINTAINERS b/MAINTAINERS index fb1471cb5ed3..327679567645 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9217,6 +9217,13 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/hid/hid-logitech-* +HID++ LOGITECH DRIVERS +R: Filipe Laíns <lains@riseup.net> +R: Bastien Nocera <hadess@hadess.net> +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-logitech-hidpp.c + HID PLAYSTATION DRIVER M: Roderick Colenbrander <roderick.colenbrander@sony.com> L: linux-input@vger.kernel.org diff --git a/drivers/hid/.kunitconfig b/drivers/hid/.kunitconfig index 04daeff5c970..675a8209c7ae 100644 --- a/drivers/hid/.kunitconfig +++ b/drivers/hid/.kunitconfig @@ -1,5 +1,6 @@ CONFIG_KUNIT=y CONFIG_USB=y CONFIG_USB_HID=y +CONFIG_HID_BATTERY_STRENGTH=y CONFIG_HID_UCLOGIC=y CONFIG_HID_KUNIT_TEST=y diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e2a5d30c8895..757a6fe8594a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -329,6 +329,13 @@ config HID_ELO Support for the ELO USB 4000/4500 touchscreens. Note that this is for different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO. +config HID_EVISION + tristate "EVision Keyboards Support" + depends on HID + help + Support for some EVision keyboards. Note that this is needed only when + applying customization using userspace programs. + config HID_EZKEY tristate "Ezkey BTC 8193 keyboard" default !EXPERT @@ -1264,6 +1271,7 @@ config HID_MCP2221 config HID_KUNIT_TEST tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS depends on KUNIT=y + depends on HID_BATTERY_STRENGTH depends on HID_UCLOGIC default KUNIT_ALL_TESTS help diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index e8014c1a2f8b..bd01571ddfe7 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELAN) += hid-elan.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o +obj-$(CONFIG_HID_EVISION) += hid-evision.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_FT260) += hid-ft260.o obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c index 1b18291fc5af..705b52337068 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c @@ -112,7 +112,7 @@ void amdtp_hid_wakeup(struct hid_device *hid) } } -static struct hid_ll_driver amdtp_hid_ll_driver = { +static const struct hid_ll_driver amdtp_hid_ll_driver = { .parse = amdtp_hid_parse, .start = amdtp_hid_start, .stop = amdtp_hid_stop, diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index f99752b998f3..d1094bb1aa42 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -98,6 +98,7 @@ struct asus_kbd_leds { struct hid_device *hdev; struct work_struct work; unsigned int brightness; + spinlock_t lock; bool removed; }; @@ -490,21 +491,42 @@ static int rog_nkey_led_init(struct hid_device *hdev) return ret; } +static void asus_schedule_work(struct asus_kbd_leds *led) +{ + unsigned long flags; + + spin_lock_irqsave(&led->lock, flags); + if (!led->removed) + schedule_work(&led->work); + spin_unlock_irqrestore(&led->lock, flags); +} + static void asus_kbd_backlight_set(struct led_classdev *led_cdev, enum led_brightness brightness) { struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds, cdev); + unsigned long flags; + + spin_lock_irqsave(&led->lock, flags); led->brightness = brightness; - schedule_work(&led->work); + spin_unlock_irqrestore(&led->lock, flags); + + asus_schedule_work(led); } static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev) { struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds, cdev); + enum led_brightness brightness; + unsigned long flags; + + spin_lock_irqsave(&led->lock, flags); + brightness = led->brightness; + spin_unlock_irqrestore(&led->lock, flags); - return led->brightness; + return brightness; } static void asus_kbd_backlight_work(struct work_struct *work) @@ -512,11 +534,11 @@ static void asus_kbd_backlight_work(struct work_struct *work) struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work); u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 }; int ret; + unsigned long flags; - if (led->removed) - return; - + spin_lock_irqsave(&led->lock, flags); buf[4] = led->brightness; + spin_unlock_irqrestore(&led->lock, flags); ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf)); if (ret < 0) @@ -584,6 +606,7 @@ static int asus_kbd_register_leds(struct hid_device *hdev) drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set; drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get; INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work); + spin_lock_init(&drvdata->kbd_backlight->lock); ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev); if (ret < 0) { @@ -1119,9 +1142,13 @@ err_stop_hw: static void asus_remove(struct hid_device *hdev) { struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + unsigned long flags; if (drvdata->kbd_backlight) { + spin_lock_irqsave(&drvdata->kbd_backlight->lock, flags); drvdata->kbd_backlight->removed = true; + spin_unlock_irqrestore(&drvdata->kbd_backlight->lock, flags); + cancel_work_sync(&drvdata->kbd_backlight->work); } diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c index e8b16665860d..a02cb517b4c4 100644 --- a/drivers/hid/hid-bigbenff.c +++ b/drivers/hid/hid-bigbenff.c @@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = { struct bigben_device { struct hid_device *hid; struct hid_report *report; + spinlock_t lock; bool removed; u8 led_state; /* LED1 = 1 .. LED4 = 8 */ u8 right_motor_on; /* right motor off/on 0/1 */ @@ -184,18 +185,39 @@ struct bigben_device { struct work_struct worker; }; +static inline void bigben_schedule_work(struct bigben_device *bigben) +{ + unsigned long flags; + + spin_lock_irqsave(&bigben->lock, flags); + if (!bigben->removed) + schedule_work(&bigben->worker); + spin_unlock_irqrestore(&bigben->lock, flags); +} static void bigben_worker(struct work_struct *work) { struct bigben_device *bigben = container_of(work, struct bigben_device, worker); struct hid_field *report_field = bigben->report->field[0]; - - if (bigben->removed || !report_field) + bool do_work_led = false; + bool do_work_ff = false; + u8 *buf; + u32 len; + unsigned long flags; + + buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL); + if (!buf) return; + len = hid_report_len(bigben->report); + + /* LED work */ + spin_lock_irqsave(&bigben->lock, flags); + if (bigben->work_led) { bigben->work_led = false; + do_work_led = true; report_field->value[0] = 0x01; /* 1 = led message */ report_field->value[1] = 0x08; /* reserved value, always 8 */ report_field->value[2] = bigben->led_state; @@ -204,11 +226,22 @@ static void bigben_worker(struct work_struct *work) report_field->value[5] = 0x00; /* padding */ report_field->value[6] = 0x00; /* padding */ report_field->value[7] = 0x00; /* padding */ - hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT); + hid_output_report(bigben->report, buf); + } + + spin_unlock_irqrestore(&bigben->lock, flags); + + if (do_work_led) { + hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len, + bigben->report->type, HID_REQ_SET_REPORT); } + /* FF work */ + spin_lock_irqsave(&bigben->lock, flags); + if (bigben->work_ff) { bigben->work_ff = false; + do_work_ff = true; report_field->value[0] = 0x02; /* 2 = rumble effect message */ report_field->value[1] = 0x08; /* reserved value, always 8 */ report_field->value[2] = bigben->right_motor_on; @@ -217,8 +250,17 @@ static void bigben_worker(struct work_struct *work) report_field->value[5] = 0x00; /* padding */ report_field->value[6] = 0x00; /* padding */ report_field->value[7] = 0x00; /* padding */ - hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT); + hid_output_report(bigben->report, buf); + } + + spin_unlock_irqrestore(&bigben->lock, flags); + + if (do_work_ff) { + hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len, + bigben->report->type, HID_REQ_SET_REPORT); } + + kfree(buf); } static int hid_bigben_play_effect(struct input_dev *dev, void *data, @@ -228,6 +270,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data, struct bigben_device *bigben = hid_get_drvdata(hid); u8 right_motor_on; u8 left_motor_force; + unsigned long flags; if (!bigben) { hid_err(hid, "no device data\n"); @@ -242,10 +285,13 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data, if (right_motor_on != bigben->right_motor_on || left_motor_force != bigben->left_motor_force) { + spin_lock_irqsave(&bigben->lock, flags); bigben->right_motor_on = right_motor_on; bigben->left_motor_force = left_motor_force; bigben->work_ff = true; - schedule_work(&bigben->worker); + spin_unlock_irqrestore(&bigben->lock, flags); + + bigben_schedule_work(bigben); } return 0; @@ -259,6 +305,7 @@ static void bigben_set_led(struct led_classdev *led, struct bigben_device *bigben = hid_get_drvdata(hid); int n; bool work; + unsigned long flags; if (!bigben) { hid_err(hid, "no device data\n"); @@ -267,6 +314,7 @@ static void bigben_set_led(struct led_classdev *led, for (n = 0; n < NUM_LEDS; n++) { if (led == bigben->leds[n]) { + spin_lock_irqsave(&bigben->lock, flags); if (value == LED_OFF) { work = (bigben->led_state & BIT(n)); bigben->led_state &= ~BIT(n); @@ -274,10 +322,11 @@ static void bigben_set_led(struct led_classdev *led, work = !(bigben->led_state & BIT(n)); bigben->led_state |= BIT(n); } + spin_unlock_irqrestore(&bigben->lock, flags); if (work) { bigben->work_led = true; - schedule_work(&bigben->worker); + bigben_schedule_work(bigben); } return; } @@ -307,8 +356,12 @@ static enum led_brightness bigben_get_led(struct led_classdev *led) static void bigben_remove(struct hid_device *hid) { struct bigben_device *bigben = hid_get_drvdata(hid); + unsigned long flags; + spin_lock_irqsave(&bigben->lock, flags); bigben->removed = true; + spin_unlock_irqrestore(&bigben->lock, flags); + cancel_work_sync(&bigben->worker); hid_hw_stop(hid); } @@ -318,7 +371,6 @@ static int bigben_probe(struct hid_device *hid, { struct bigben_device *bigben; struct hid_input *hidinput; - struct list_head *report_list; struct led_classdev *led; char *name; size_t name_sz; @@ -343,14 +395,12 @@ static int bigben_probe(struct hid_device *hid, return error; } - report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - if (list_empty(report_list)) { + bigben->report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 8); + if (!bigben->report) { hid_err(hid, "no output report found\n"); error = -ENODEV; goto error_hw_stop; } - bigben->report = list_entry(report_list->next, - struct hid_report, list); if (list_empty(&hid->inputs)) { hid_err(hid, "no inputs found\n"); @@ -362,6 +412,7 @@ static int bigben_probe(struct hid_device *hid, set_bit(FF_RUMBLE, hidinput->input->ffbit); INIT_WORK(&bigben->worker, bigben_worker); + spin_lock_init(&bigben->lock); error = input_ff_create_memless(hidinput->input, NULL, hid_bigben_play_effect); @@ -402,7 +453,7 @@ static int bigben_probe(struct hid_device *hid, bigben->left_motor_force = 0; bigben->work_led = true; bigben->work_ff = true; - schedule_work(&bigben->worker); + bigben_schedule_work(bigben); hid_info(hid, "LED and force feedback support for BigBen gamepad\n"); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5c72aef3d3dd..53e4d5831caf 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -41,11 +41,6 @@ #define DRIVER_DESC "HID core driver" -int hid_debug = 0; -module_param_named(debug, hid_debug, int, 0600); -MODULE_PARM_DESC(debug, "toggle HID debugging messages"); -EXPORT_SYMBOL_GPL(hid_debug); - static int hid_ignore_special_drivers = 0; module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600); MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver"); @@ -804,7 +799,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) int i; if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && - type == HID_COLLECTION_PHYSICAL) + (type == HID_COLLECTION_PHYSICAL || + type == HID_COLLECTION_APPLICATION)) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && @@ -2912,10 +2908,6 @@ static int __init hid_init(void) { int ret; - if (hid_debug) - pr_warn("hid_debug is now used solely for parser and driver debugging.\n" - "debugfs is now used for inspecting the device (report descriptor, reports)\n"); - ret = bus_register(&hid_bus_type); if (ret) { pr_err("can't register hid bus\n"); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index e213bdde543a..e7ef1ea107c9 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -975,6 +975,7 @@ static const char *keys[KEY_MAX + 1] = { [KEY_CAMERA_ACCESS_DISABLE] = "CameraAccessDisable", [KEY_CAMERA_ACCESS_TOGGLE] = "CameraAccessToggle", [KEY_DICTATE] = "Dictate", + [KEY_MICMUTE] = "MicrophoneMute", [KEY_BRIGHTNESS_MIN] = "BrightnessMin", [KEY_BRIGHTNESS_MAX] = "BrightnessMax", [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", diff --git a/drivers/hid/hid-evision.c b/drivers/hid/hid-evision.c new file mode 100644 index 000000000000..ef6b4b435215 --- /dev/null +++ b/drivers/hid/hid-evision.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for EVision devices + * For now, only ignore bogus consumer reports + * sent after the keyboard has been configured + * + * Copyright (c) 2022 Philippe Valembois + */ + +#include <linux/device.h> +#include <linux/input.h> +#include <linux/hid.h> +#include <linux/module.h> + +#include "hid-ids.h" + +static int evision_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + /* Ignore key down event */ + if ((usage->hid & HID_USAGE) >> 8 == 0x05) + return -1; + /* Ignore key up event */ + if ((usage->hid & HID_USAGE) >> 8 == 0x06) + return -1; + + switch (usage->hid & HID_USAGE) { + /* Ignore configuration saved event */ + case 0x0401: return -1; + /* Ignore reset event */ + case 0x0402: return -1; + } + return 0; +} + +static const struct hid_device_id evision_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EVISION_ICL01) }, + { } +}; +MODULE_DEVICE_TABLE(hid, evision_devices); + +static struct hid_driver evision_driver = { + .name = "evision", + .id_table = evision_devices, + .input_mapping = evision_input_mapping, +}; +module_hid_driver(evision_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index cf12f17e6533..819eb38eb5df 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -424,7 +424,7 @@ static int mousevsc_hid_raw_request(struct hid_device *hid, return 0; } -static struct hid_ll_driver mousevsc_ll_driver = { +static const struct hid_ll_driver mousevsc_ll_driver = { .parse = mousevsc_hid_parse, .open = mousevsc_hid_open, .close = mousevsc_hid_close, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9e36b4cd905e..a98c6145e975 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -448,6 +448,9 @@ #define USB_VENDOR_ID_EMS 0x2006 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 +#define USB_VENDOR_ID_EVISION 0x320f +#define USB_DEVICE_ID_EVISION_ICL01 0x5041 + #define USB_VENDOR_ID_FLATFROG 0x25b5 #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 @@ -822,6 +825,7 @@ #define USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO 0xc22e #define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f #define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262 +#define USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL 0xc26e #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c new file mode 100644 index 000000000000..77c2d45ac62a --- /dev/null +++ b/drivers/hid/hid-input-test.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID to Linux Input mapping + * + * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> + */ + +#include <kunit/test.h> + +static void hid_test_input_set_battery_charge_status(struct kunit *test) +{ + struct hid_device *dev; + bool handled; + + dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0); + KUNIT_EXPECT_FALSE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN); + + handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0); + KUNIT_EXPECT_TRUE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING); + + handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1); + KUNIT_EXPECT_TRUE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING); +} + +static void hid_test_input_get_battery_property(struct kunit *test) +{ + struct power_supply *psy; + struct hid_device *dev; + union power_supply_propval val; + int ret; + + dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + dev->battery_avoid_query = true; + + psy = kunit_kzalloc(test, sizeof(*psy), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, psy); + psy->drv_data = dev; + + dev->battery_status = HID_BATTERY_UNKNOWN; + dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING; + ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_UNKNOWN); + + dev->battery_status = HID_BATTERY_REPORTED; + dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING; + ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_CHARGING); + + dev->battery_status = HID_BATTERY_REPORTED; + dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING; + ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_DISCHARGING); +} + +static struct kunit_case hid_input_tests[] = { + KUNIT_CASE(hid_test_input_set_battery_charge_status), + KUNIT_CASE(hid_test_input_get_battery_property), + { } +}; + +static struct kunit_suite hid_input_test_suite = { + .name = "hid_input", + .test_cases = hid_input_tests, +}; + +kunit_test_suite(hid_input_test_suite); + +MODULE_DESCRIPTION("HID input KUnit tests"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>"); diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 77c8c49852b5..743e518b9836 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -486,7 +486,7 @@ static int hidinput_get_battery_property(struct power_supply *psy, if (dev->battery_status == HID_BATTERY_UNKNOWN) val->intval = POWER_SUPPLY_STATUS_UNKNOWN; else - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = dev->battery_charge_status; break; case POWER_SUPPLY_PROP_SCOPE: @@ -554,6 +554,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, dev->battery_max = max; dev->battery_report_type = report_type; dev->battery_report_id = field->report->id; + dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING; /* * Stylus is normally not connected to the device and thus we @@ -620,6 +621,20 @@ static void hidinput_update_battery(struct hid_device *dev, int value) power_supply_changed(dev->battery); } } + +static bool hidinput_set_battery_charge_status(struct hid_device *dev, + unsigned int usage, int value) +{ + switch (usage) { + case HID_BAT_CHARGING: + dev->battery_charge_status = value ? + POWER_SUPPLY_STATUS_CHARGING : + POWER_SUPPLY_STATUS_DISCHARGING; + return true; + } + + return false; +} #else /* !CONFIG_HID_BATTERY_STRENGTH */ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field, bool is_percentage) @@ -634,6 +649,12 @@ static void hidinput_cleanup_battery(struct hid_device *dev) static void hidinput_update_battery(struct hid_device *dev, int value) { } + +static bool hidinput_set_battery_charge_status(struct hid_device *dev, + unsigned int usage, int value) +{ + return false; +} #endif /* CONFIG_HID_BATTERY_STRENGTH */ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field, @@ -793,6 +814,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; } + if ((usage->hid & 0xf0) == 0xa0) { /* SystemControl */ + switch (usage->hid & 0xf) { + case 0x9: map_key_clear(KEY_MICMUTE); break; + default: goto ignore; + } + break; + } + if ((usage->hid & 0xf0) == 0xb0) { /* SC - Display */ switch (usage->hid & 0xf) { case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break; @@ -1223,6 +1252,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel hidinput_setup_battery(device, HID_INPUT_REPORT, field, true); usage->type = EV_PWR; return; + case HID_BAT_CHARGING: + usage->type = EV_PWR; + return; } goto unknown; @@ -1465,7 +1497,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; if (usage->type == EV_PWR) { - hidinput_update_battery(hid, value); + bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value); + + if (!handled) + hidinput_update_battery(hid, value); + return; } @@ -2321,3 +2357,7 @@ void hidinput_disconnect(struct hid_device *hid) cancel_work_sync(&hid->led_work); } EXPORT_SYMBOL_GPL(hidinput_disconnect); + +#ifdef CONFIG_HID_KUNIT_TEST +#include "hid-input-test.c" +#endif diff --git a/drivers/hid/hid-letsketch.c b/drivers/hid/hid-letsketch.c index 74d17cf518ba..97f047f18136 100644 --- a/drivers/hid/hid-letsketch.c +++ b/drivers/hid/hid-letsketch.c @@ -238,7 +238,7 @@ static int letsketch_probe(struct hid_device *hdev, const struct hid_device_id * char buf[256]; int i, ret; - if (!hid_is_using_ll_driver(hdev, &usb_hid_driver)) + if (!hid_is_usb(hdev)) return -ENODEV; intf = to_usb_interface(hdev->dev.parent); diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index c358778e070b..62180414efcc 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -554,7 +554,7 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = { #define LOGITECH_DJ_INTERFACE_NUMBER 0x02 -static struct hid_ll_driver logi_dj_ll_driver; +static const struct hid_ll_driver logi_dj_ll_driver; static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); static void delayedwork_callback(struct work_struct *work); @@ -1506,7 +1506,7 @@ static bool logi_dj_ll_may_wakeup(struct hid_device *hid) return hid_hw_may_wakeup(djrcv_dev->hidpp); } -static struct hid_ll_driver logi_dj_ll_driver = { +static const struct hid_ll_driver logi_dj_ll_driver = { .parse = logi_dj_ll_parse, .start = logi_dj_ll_start, .stop = logi_dj_ll_stop, diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 9c1ee8e91e0c..25dcda76d6c7 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -30,11 +30,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>"); - -static bool disable_raw_mode; -module_param(disable_raw_mode, bool, 0644); -MODULE_PARM_DESC(disable_raw_mode, - "Disable Raw mode reporting for touchpads and keep firmware gestures."); +MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); static bool disable_tap_to_click; module_param(disable_tap_to_click, bool, 0644); @@ -71,12 +67,13 @@ MODULE_PARM_DESC(disable_tap_to_click, /* bits 2..20 are reserved for classes */ /* #define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) disabled */ #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22) -#define HIDPP_QUIRK_NO_HIDINPUT BIT(23) +#define HIDPP_QUIRK_DELAYED_INIT BIT(23) #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) #define HIDPP_QUIRK_UNIFYING BIT(25) #define HIDPP_QUIRK_HIDPP_WHEELS BIT(26) #define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27) #define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28) +#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(29) /* These are just aliases for now */ #define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS @@ -87,8 +84,6 @@ MODULE_PARM_DESC(disable_tap_to_click, HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL | \ HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) -#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT - #define HIDPP_CAPABILITY_HIDPP10_BATTERY BIT(0) #define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1) #define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2) @@ -225,6 +220,16 @@ struct hidpp_device { #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c /* HID++ 2.0 error codes */ +#define HIDPP20_ERROR_NO_ERROR 0x00 +#define HIDPP20_ERROR_UNKNOWN 0x01 +#define HIDPP20_ERROR_INVALID_ARGS 0x02 +#define HIDPP20_ERROR_OUT_OF_RANGE 0x03 +#define HIDPP20_ERROR_HW_ERROR 0x04 +#define HIDPP20_ERROR_LOGITECH_INTERNAL 0x05 +#define HIDPP20_ERROR_INVALID_FEATURE_INDEX 0x06 +#define HIDPP20_ERROR_INVALID_FUNCTION_ID 0x07 +#define HIDPP20_ERROR_BUSY 0x08 +#define HIDPP20_ERROR_UNSUPPORTED 0x09 #define HIDPP20_ERROR 0xff static void hidpp_connect_event(struct hidpp_device *hidpp_dev); @@ -279,6 +284,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, struct hidpp_report *response) { int ret; + int max_retries = 3; mutex_lock(&hidpp->send_mutex); @@ -291,34 +297,39 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, */ *response = *message; - ret = __hidpp_send_report(hidpp->hid_dev, message); + for (; max_retries != 0; max_retries--) { + ret = __hidpp_send_report(hidpp->hid_dev, message); - if (ret) { - dbg_hid("__hidpp_send_report returned err: %d\n", ret); - memset(response, 0, sizeof(struct hidpp_report)); - goto exit; - } + if (ret) { + dbg_hid("__hidpp_send_report returned err: %d\n", ret); + memset(response, 0, sizeof(struct hidpp_report)); + goto exit; + } - if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, - 5*HZ)) { - dbg_hid("%s:timeout waiting for response\n", __func__); - memset(response, 0, sizeof(struct hidpp_report)); - ret = -ETIMEDOUT; - } + if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, + 5*HZ)) { + dbg_hid("%s:timeout waiting for response\n", __func__); + memset(response, 0, sizeof(struct hidpp_report)); + ret = -ETIMEDOUT; + } - if (response->report_id == REPORT_ID_HIDPP_SHORT && - response->rap.sub_id == HIDPP_ERROR) { - ret = response->rap.params[1]; - dbg_hid("%s:got hidpp error %02X\n", __func__, ret); - goto exit; - } + if (response->report_id == REPORT_ID_HIDPP_SHORT && + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); + goto exit; + } - if ((response->report_id == REPORT_ID_HIDPP_LONG || - response->report_id == REPORT_ID_HIDPP_VERY_LONG) && - response->fap.feature_index == HIDPP20_ERROR) { - ret = response->fap.params[1]; - dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); - goto exit; + if ((response->report_id == REPORT_ID_HIDPP_LONG || + response->report_id == REPORT_ID_HIDPP_VERY_LONG) && + response->fap.feature_index == HIDPP20_ERROR) { + ret = response->fap.params[1]; + if (ret != HIDPP20_ERROR_BUSY) { + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); + goto exit; + } + dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret); + } } exit: @@ -334,8 +345,13 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, struct hidpp_report *message; int ret; - if (param_count > sizeof(message->fap.params)) + if (param_count > sizeof(message->fap.params)) { + hid_dbg(hidpp->hid_dev, + "Invalid number of parameters passed to command (%d != %llu)\n", + param_count, + (unsigned long long) sizeof(message->fap.params)); return -EINVAL; + } message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); if (!message) @@ -3436,11 +3452,17 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp) ret = hidpp10_enable_scrolling_acceleration(hidpp); multiplier = 8; } - if (ret) + if (ret) { + hid_dbg(hidpp->hid_dev, + "Could not enable hi-res scrolling: %d\n", ret); return ret; + } - if (multiplier == 0) + if (multiplier == 0) { + hid_dbg(hidpp->hid_dev, + "Invalid multiplier 0 from device, setting it to 1\n"); multiplier = 1; + } hidpp->vertical_wheel_counter.wheel_multiplier = multiplier; hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier); @@ -3472,14 +3494,8 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp) hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n"); } } else { - struct hidpp_report response; - - ret = hidpp_send_rap_command_sync(hidpp, - REPORT_ID_HIDPP_SHORT, - HIDPP_GET_REGISTER, - HIDPP_ENABLE_FAST_SCROLL, - NULL, 0, &response); - if (!ret) { + /* We cannot detect fast scrolling support on HID++ 1.0 devices */ + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) { hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL; hid_dbg(hidpp->hid_dev, "Detected HID++ 1.0 fast scroll\n"); } @@ -4002,7 +4018,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) if (hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL) hi_res_scroll_enable(hidpp); - if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) + if (!(hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) || hidpp->delayed_input) /* if the input nodes are already created, we can stop now */ return; @@ -4107,6 +4123,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) bool connected; unsigned int connect_mask = HID_CONNECT_DEFAULT; struct hidpp_ff_private_data data; + bool will_restart = false; /* report_fixup needs drvdata to be set before we call hid_parse */ hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL); @@ -4147,11 +4164,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) hidpp_application_equals(hdev, HID_GD_KEYBOARD)) hidpp->quirks |= HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS; - if (disable_raw_mode) { - hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP; - hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT; - } - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { ret = wtp_allocate(hdev, id); if (ret) @@ -4162,6 +4174,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } + if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT || + hidpp->quirks & HIDPP_QUIRK_UNIFYING) + will_restart = true; + INIT_WORK(&hidpp->work, delayed_work_cb); mutex_init(&hidpp->send_mutex); init_waitqueue_head(&hidpp->wait); @@ -4176,7 +4192,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) * Plain USB connections need to actually call start and open * on the transport driver to allow incoming data. */ - ret = hid_hw_start(hdev, 0); + ret = hid_hw_start(hdev, will_restart ? 0 : connect_mask); if (ret) { hid_err(hdev, "hw start failed\n"); goto hid_hw_start_fail; @@ -4213,6 +4229,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) hidpp->wireless_feature_index = 0; else if (ret) goto hid_hw_init_fail; + ret = 0; } if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) { @@ -4227,19 +4244,21 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) hidpp_connect_event(hidpp); - /* Reset the HID node state */ - hid_device_io_stop(hdev); - hid_hw_close(hdev); - hid_hw_stop(hdev); + if (will_restart) { + /* Reset the HID node state */ + hid_device_io_stop(hdev); + hid_hw_close(hdev); + hid_hw_stop(hdev); - if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) - connect_mask &= ~HID_CONNECT_HIDINPUT; + if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) + connect_mask &= ~HID_CONNECT_HIDINPUT; - /* Now export the actual inputs and hidraw nodes to the world */ - ret = hid_hw_start(hdev, connect_mask); - if (ret) { - hid_err(hdev, "%s:hid_hw_start returned error\n", __func__); - goto hid_hw_start_fail; + /* Now export the actual inputs and hidraw nodes to the world */ + ret = hid_hw_start(hdev, connect_mask); + if (ret) { + hid_err(hdev, "%s:hid_hw_start returned error\n", __func__); + goto hid_hw_start_fail; + } } if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { @@ -4297,9 +4316,15 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651), .driver_data = HIDPP_QUIRK_CLASS_WTP }, + { /* Mouse Logitech Anywhere MX */ + LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, { /* Mouse logitech M560 */ LDJ_DEVICE(0x402d), .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, + { /* Mouse Logitech M705 (firmware RQM17) */ + LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, + { /* Mouse Logitech Performance MX */ + LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, { /* Keyboard logitech K400 */ LDJ_DEVICE(0x4024), .driver_data = HIDPP_QUIRK_CLASS_K400 }, @@ -4348,6 +4373,9 @@ static const struct hid_device_id hidpp_devices[] = { { /* Logitech G920 Wheel over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, + { /* Logitech G923 Wheel (Xbox version) over USB */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL), + .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS }, { /* Logitech G Pro Gaming Mouse over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) }, @@ -4367,6 +4395,8 @@ static const struct hid_device_id hidpp_devices[] = { { /* MX Ergo trackball over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) }, + { /* Signature M650 over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) }, { /* MX Master 3 mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) }, {} diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index f444e63e9f36..3e3f89e01d81 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -5,6 +5,7 @@ */ #include <linux/ctype.h> +#include <linux/dmi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -750,114 +751,209 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom } -/* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */ -static const char *const known_sensor_luid[] = { "020B000000000000" }; +/* + * Match a known custom sensor. + * tag and luid is mandatory. + */ +struct hid_sensor_custom_match { + const char *tag; + const char *luid; + const char *model; + const char *manufacturer; + bool check_dmi; + struct dmi_system_id dmi; +}; -static int get_luid_table_index(unsigned char *usage_str) -{ - int i; +/* + * Custom sensor properties used for matching. + */ +struct hid_sensor_custom_properties { + u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES]; + u16 model[HID_CUSTOM_MAX_FEATURE_BYTES]; + u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES]; +}; + +static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = { + /* + * Intel Integrated Sensor Hub (ISH) + */ + { /* Intel ISH hinge */ + .tag = "INT", + .luid = "020B000000000000", + .manufacturer = "INTEL", + }, + /* + * Lenovo Intelligent Sensing Solution (LISS) + */ + { /* ambient light */ + .tag = "LISS", + .luid = "0041010200000082", + .model = "STK3X3X Sensor", + .manufacturer = "Vendor 258", + .check_dmi = true, + .dmi.matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + } + }, + { /* human presence */ + .tag = "LISS", + .luid = "0226000171AC0081", + .model = "VL53L1_HOD Sensor", + .manufacturer = "ST_MICRO", + .check_dmi = true, + .dmi.matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + } + }, + {} +}; - for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) { - if (!strncmp(usage_str, known_sensor_luid[i], - strlen(known_sensor_luid[i]))) - return i; +static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match, + size_t count) +{ + while (count-- && *prop && *match) { + if (*prop != (u16) *match) + return false; + prop++; + match++; } - return -ENODEV; + return (count == -1) || *prop == (u16)*match; } -static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev) +static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev, + u32 prop_usage_id, size_t prop_size, + u16 *prop) { - struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 }; - struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 }; - int report_size; + struct hid_sensor_hub_attribute_info prop_attr = { 0 }; int ret; - static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES]; - static char buf[HID_CUSTOM_MAX_FEATURE_BYTES]; - int i; - memset(w_buf, 0, sizeof(w_buf)); - memset(buf, 0, sizeof(buf)); + memset(prop, 0, prop_size); - /* get manufacturer info */ - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, hsdev->usage, - HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer); + ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, + hsdev->usage, prop_usage_id, + &prop_attr); if (ret < 0) return ret; - report_size = - sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id, - sensor_manufacturer.index, sizeof(w_buf), - w_buf); - if (report_size <= 0) { - hid_err(hsdev->hdev, - "Failed to get sensor manufacturer info %d\n", - report_size); - return -ENODEV; + ret = sensor_hub_get_feature(hsdev, prop_attr.report_id, + prop_attr.index, prop_size, prop); + if (ret < 0) { + hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n", + prop_usage_id, ret); + return ret; } - /* convert from wide char to char */ - for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) - buf[i] = (char)w_buf[i]; + return 0; +} - /* ensure it's ISH sensor */ - if (strncmp(buf, "INTEL", strlen("INTEL"))) - return -ENODEV; +static bool +hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev, + const struct hid_sensor_custom_match *match, + const struct hid_sensor_custom_properties *prop) +{ + struct dmi_system_id dmi[] = { match->dmi, { 0 } }; - memset(w_buf, 0, sizeof(w_buf)); - memset(buf, 0, sizeof(buf)); + if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) || + !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid, + HID_CUSTOM_MAX_FEATURE_BYTES - 5)) + return false; - /* get real usage id */ - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, hsdev->usage, - HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info); + if (match->model && + !hid_sensor_custom_prop_match_str(prop->model, match->model, + HID_CUSTOM_MAX_FEATURE_BYTES)) + return false; + + if (match->manufacturer && + !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer, + HID_CUSTOM_MAX_FEATURE_BYTES)) + return false; + + if (match->check_dmi && !dmi_check_system(dmi)) + return false; + + return true; +} + +static int +hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev, + struct hid_sensor_custom_properties *prop) +{ + int ret; + + ret = hid_sensor_custom_get_prop(hsdev, + HID_USAGE_SENSOR_PROP_SERIAL_NUM, + HID_CUSTOM_MAX_FEATURE_BYTES, + prop->serial_num); if (ret < 0) return ret; - report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id, - sensor_luid_info.index, sizeof(w_buf), - w_buf); - if (report_size <= 0) { - hid_err(hsdev->hdev, "Failed to get real usage info %d\n", - report_size); - return -ENODEV; - } + /* + * Ignore errors on the following model and manufacturer properties. + * Because these are optional, it is not an error if they are missing. + */ - /* convert from wide char to char */ - for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) - buf[i] = (char)w_buf[i]; + hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL, + HID_CUSTOM_MAX_FEATURE_BYTES, + prop->model); - if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) { - hid_err(hsdev->hdev, - "%s luid length not match %zu != (%zu + 5)\n", __func__, - strlen(buf), strlen(known_sensor_luid[0])); - return -ENODEV; - } + hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER, + HID_CUSTOM_MAX_FEATURE_BYTES, + prop->manufacturer); - /* get table index with luid (not matching 'LUID: ' in luid) */ - return get_luid_table_index(&buf[5]); + return 0; +} + +static int +hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev, + const struct hid_sensor_custom_match **known) +{ + int ret; + const struct hid_sensor_custom_match *match = + hid_sensor_custom_known_table; + struct hid_sensor_custom_properties *prop; + + prop = kmalloc(sizeof(struct hid_sensor_custom_properties), GFP_KERNEL); + if (!prop) + return -ENOMEM; + + ret = hid_sensor_custom_properties_get(hsdev, prop); + if (ret < 0) + goto out; + + while (match->tag) { + if (hid_sensor_custom_do_match(hsdev, match, prop)) { + *known = match; + ret = 0; + goto out; + } + match++; + } + ret = -ENODATA; +out: + kfree(prop); + return ret; } static struct platform_device * hid_sensor_register_platform_device(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - int index) + const struct hid_sensor_custom_match *match) { - char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; + char real_usage[HID_SENSOR_USAGE_LENGTH]; struct platform_device *custom_pdev; const char *dev_name; char *c; - /* copy real usage id */ - memcpy(real_usage, known_sensor_luid[index], 4); + memcpy(real_usage, match->luid, 4); /* usage id are all lowcase */ for (c = real_usage; *c != '\0'; c++) *c = tolower(*c); - /* HID-SENSOR-INT-REAL_USAGE_ID */ - dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage); + /* HID-SENSOR-TAG-REAL_USAGE_ID */ + dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s", + match->tag, real_usage); if (!dev_name) return ERR_PTR(-ENOMEM); @@ -873,7 +969,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) struct hid_sensor_custom *sensor_inst; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; int ret; - int index; + const struct hid_sensor_custom_match *match; sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), GFP_KERNEL); @@ -888,10 +984,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) mutex_init(&sensor_inst->mutex); platform_set_drvdata(pdev, sensor_inst); - index = get_known_custom_sensor_index(hsdev); - if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) { + ret = hid_sensor_custom_get_known(hsdev, &match); + if (!ret) { sensor_inst->custom_pdev = - hid_sensor_register_platform_device(pdev, hsdev, index); + hid_sensor_register_platform_device(pdev, hsdev, match); ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev); if (ret) { diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 6abd3e2a9094..83237b86c8ff 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -397,7 +397,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, for (i = 0; i < report->maxfield; ++i) { field = report->field[i]; if (field->maxusage) { - if (field->physical == usage_id && + if ((field->physical == usage_id || + field->application == usage_id) && (field->logical == attr_usage_id || field->usage[0].hid == attr_usage_id) && @@ -506,7 +507,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev, collection->usage); callback = sensor_hub_get_callback(hdev, - report->field[i]->physical, + report->field[i]->physical ? report->field[i]->physical : + report->field[i]->application, report->field[i]->usage[0].collection_index, &hsdev, &priv); if (!callback) { diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index 8ee43cb225fc..29ec8b34741a 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -674,7 +674,7 @@ static int steam_client_ll_raw_request(struct hid_device *hdev, report_type, reqtype); } -static struct hid_ll_driver steam_client_ll_driver = { +static const struct hid_ll_driver steam_client_ll_driver = { .parse = steam_client_ll_parse, .start = steam_client_ll_start, .stop = steam_client_ll_stop, diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c index 375c77c3db74..3a7e2bcb5412 100644 --- a/drivers/hid/i2c-hid/i2c-hid-acpi.c +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -39,8 +39,8 @@ static const struct acpi_device_id i2c_hid_acpi_blacklist[] = { * The CHPN0001 ACPI device, which is used to describe the Chipone * ICN8505 controller, has a _CID of PNP0C50 but is not HID compatible. */ - {"CHPN0001", 0 }, - { }, + { "CHPN0001" }, + { } }; /* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */ @@ -48,8 +48,9 @@ static guid_t i2c_hid_guid = GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555, 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE); -static int i2c_hid_acpi_get_descriptor(struct acpi_device *adev) +static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi) { + struct acpi_device *adev = ihid_acpi->adev; acpi_handle handle = acpi_device_handle(adev); union acpi_object *obj; u16 hid_descriptor_address; @@ -81,38 +82,31 @@ static int i2c_hid_acpi_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct i2c_hid_acpi *ihid_acpi; - struct acpi_device *adev; u16 hid_descriptor_address; int ret; - adev = ACPI_COMPANION(dev); - if (!adev) { - dev_err(&client->dev, "Error could not get ACPI device\n"); - return -ENODEV; - } - ihid_acpi = devm_kzalloc(&client->dev, sizeof(*ihid_acpi), GFP_KERNEL); if (!ihid_acpi) return -ENOMEM; - ihid_acpi->adev = adev; + ihid_acpi->adev = ACPI_COMPANION(dev); ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail; - ret = i2c_hid_acpi_get_descriptor(adev); + ret = i2c_hid_acpi_get_descriptor(ihid_acpi); if (ret < 0) return ret; hid_descriptor_address = ret; - acpi_device_fix_up_power(adev); + acpi_device_fix_up_power(ihid_acpi->adev); return i2c_hid_core_probe(client, &ihid_acpi->ops, hid_descriptor_address, 0); } static const struct acpi_device_id i2c_hid_acpi_match[] = { - {"ACPI0C50", 0 }, - {"PNP0C50", 0 }, - { }, + { "ACPI0C50" }, + { "PNP0C50" }, + { } }; MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index b86b62f97108..0ab8f47a84e9 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -67,16 +67,7 @@ #define I2C_HID_PWR_ON 0x00 #define I2C_HID_PWR_SLEEP 0x01 -/* debug option */ -static bool debug; -module_param(debug, bool, 0444); -MODULE_PARM_DESC(debug, "print a lot of debug information"); - -#define i2c_hid_dbg(ihid, fmt, arg...) \ -do { \ - if (debug) \ - dev_printk(KERN_DEBUG, &(ihid)->client->dev, fmt, ##arg); \ -} while (0) +#define i2c_hid_dbg(ihid, ...) dev_dbg(&(ihid)->client->dev, __VA_ARGS__) struct i2c_hid_desc { __le16 wHIDDescLength; @@ -842,7 +833,7 @@ static void i2c_hid_close(struct hid_device *hid) clear_bit(I2C_HID_STARTED, &ihid->flags); } -struct hid_ll_driver i2c_hid_ll_driver = { +static const struct hid_ll_driver i2c_hid_ll_driver = { .parse = i2c_hid_parse, .start = i2c_hid_start, .stop = i2c_hid_stop, @@ -851,7 +842,6 @@ struct hid_ll_driver i2c_hid_ll_driver = { .output_report = i2c_hid_output_report, .raw_request = i2c_hid_raw_request, }; -EXPORT_SYMBOL_GPL(i2c_hid_ll_driver); static int i2c_hid_init_irq(struct i2c_client *client) { @@ -859,7 +849,7 @@ static int i2c_hid_init_irq(struct i2c_client *client) unsigned long irqflags = 0; int ret; - dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq); + i2c_hid_dbg(ihid, "Requesting IRQ: %d\n", client->irq); if (!irq_get_trigger_type(client->irq)) irqflags = IRQF_TRIGGER_LOW; @@ -1003,7 +993,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, /* Make sure there is something at this address */ ret = i2c_smbus_read_byte(client); if (ret < 0) { - dev_dbg(&client->dev, "nothing at this address: %d\n", ret); + i2c_hid_dbg(ihid, "nothing at this address: %d\n", ret); ret = -ENXIO; goto err_powered; } diff --git a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c index 29c6cb174032..0060e3dcd775 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c +++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c @@ -26,28 +26,33 @@ struct i2c_hid_of_goodix { struct i2chid_ops ops; struct regulator *vdd; - struct notifier_block nb; + struct regulator *vddio; struct gpio_desc *reset_gpio; const struct goodix_i2c_hid_timing_data *timings; }; -static void goodix_i2c_hid_deassert_reset(struct i2c_hid_of_goodix *ihid_goodix, - bool regulator_just_turned_on) +static int goodix_i2c_hid_power_up(struct i2chid_ops *ops) { - if (regulator_just_turned_on && ihid_goodix->timings->post_power_delay_ms) + struct i2c_hid_of_goodix *ihid_goodix = + container_of(ops, struct i2c_hid_of_goodix, ops); + int ret; + + ret = regulator_enable(ihid_goodix->vdd); + if (ret) + return ret; + + ret = regulator_enable(ihid_goodix->vddio); + if (ret) + return ret; + + if (ihid_goodix->timings->post_power_delay_ms) msleep(ihid_goodix->timings->post_power_delay_ms); gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0); if (ihid_goodix->timings->post_gpio_reset_delay_ms) msleep(ihid_goodix->timings->post_gpio_reset_delay_ms); -} - -static int goodix_i2c_hid_power_up(struct i2chid_ops *ops) -{ - struct i2c_hid_of_goodix *ihid_goodix = - container_of(ops, struct i2c_hid_of_goodix, ops); - return regulator_enable(ihid_goodix->vdd); + return 0; } static void goodix_i2c_hid_power_down(struct i2chid_ops *ops) @@ -55,42 +60,15 @@ static void goodix_i2c_hid_power_down(struct i2chid_ops *ops) struct i2c_hid_of_goodix *ihid_goodix = container_of(ops, struct i2c_hid_of_goodix, ops); + gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1); + regulator_disable(ihid_goodix->vddio); regulator_disable(ihid_goodix->vdd); } -static int ihid_goodix_vdd_notify(struct notifier_block *nb, - unsigned long event, - void *ignored) -{ - struct i2c_hid_of_goodix *ihid_goodix = - container_of(nb, struct i2c_hid_of_goodix, nb); - int ret = NOTIFY_OK; - - switch (event) { - case REGULATOR_EVENT_PRE_DISABLE: - gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1); - break; - - case REGULATOR_EVENT_ENABLE: - goodix_i2c_hid_deassert_reset(ihid_goodix, true); - break; - - case REGULATOR_EVENT_ABORT_DISABLE: - goodix_i2c_hid_deassert_reset(ihid_goodix, false); - break; - - default: - ret = NOTIFY_DONE; - break; - } - - return ret; -} - static int i2c_hid_of_goodix_probe(struct i2c_client *client) { struct i2c_hid_of_goodix *ihid_goodix; - int ret; + ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix), GFP_KERNEL); if (!ihid_goodix) @@ -109,41 +87,11 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client) if (IS_ERR(ihid_goodix->vdd)) return PTR_ERR(ihid_goodix->vdd); - ihid_goodix->timings = device_get_match_data(&client->dev); + ihid_goodix->vddio = devm_regulator_get(&client->dev, "mainboard-vddio"); + if (IS_ERR(ihid_goodix->vddio)) + return PTR_ERR(ihid_goodix->vddio); - /* - * We need to control the "reset" line in lockstep with the regulator - * actually turning on an off instead of just when we make the request. - * This matters if the regulator is shared with another consumer. - * - If the regulator is off then we must assert reset. The reset - * line is active low and on some boards it could cause a current - * leak if left high. - * - If the regulator is on then we don't want reset asserted for very - * long. Holding the controller in reset apparently draws extra - * power. - */ - ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify; - ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb); - if (ret) - return dev_err_probe(&client->dev, ret, - "regulator notifier request failed\n"); - - /* - * If someone else is holding the regulator on (or the regulator is - * an always-on one) we might never be told to deassert reset. Do it - * now... and temporarily bump the regulator reference count just to - * make sure it is impossible for this to race with our own notifier! - * We also assume that someone else might have _just barely_ turned - * the regulator on so we'll do the full "post_power_delay" just in - * case. - */ - if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) { - ret = regulator_enable(ihid_goodix->vdd); - if (ret) - return ret; - goodix_i2c_hid_deassert_reset(ihid_goodix, true); - regulator_disable(ihid_goodix->vdd); - } + ihid_goodix->timings = device_get_match_data(&client->dev); return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0); } diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c index 14c271d7d8a9..00c6f0ebf356 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid.c @@ -183,7 +183,7 @@ void ishtp_hid_wakeup(struct hid_device *hid) wake_up_interruptible(&hid_data->hid_wait); } -static struct hid_ll_driver ishtp_hid_ll_driver = { +static const struct hid_ll_driver ishtp_hid_ll_driver = { .parse = ishtp_hid_parse, .start = ishtp_hid_start, .stop = ishtp_hid_stop, diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c index 87637f813de2..a3e9cceddfac 100644 --- a/drivers/hid/surface-hid/surface_hid_core.c +++ b/drivers/hid/surface-hid/surface_hid_core.c @@ -174,7 +174,7 @@ static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportn return -EIO; } -static struct hid_ll_driver surface_hid_ll_driver = { +static const struct hid_ll_driver surface_hid_ll_driver = { .start = surface_hid_start, .stop = surface_hid_stop, .open = surface_hid_open, diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 2a918aeb0af1..f161c95a1ad2 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -387,7 +387,7 @@ static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf, return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT); } -struct hid_ll_driver uhid_hid_driver = { +static const struct hid_ll_driver uhid_hid_driver = { .start = uhid_hid_start, .stop = uhid_hid_stop, .open = uhid_hid_open, @@ -396,7 +396,6 @@ struct hid_ll_driver uhid_hid_driver = { .raw_request = uhid_hid_raw_request, .output_report = uhid_hid_output_report, }; -EXPORT_SYMBOL_GPL(uhid_hid_driver); #ifdef CONFIG_COMPAT diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index be4c731aaa65..257dd73e37bf 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1318,7 +1318,7 @@ static bool usbhid_may_wakeup(struct hid_device *hid) return device_may_wakeup(&dev->dev); } -struct hid_ll_driver usb_hid_driver = { +static const struct hid_ll_driver usb_hid_driver = { .parse = usbhid_parse, .start = usbhid_start, .stop = usbhid_stop, @@ -1332,7 +1332,12 @@ struct hid_ll_driver usb_hid_driver = { .idle = usbhid_idle, .may_wakeup = usbhid_may_wakeup, }; -EXPORT_SYMBOL_GPL(usb_hid_driver); + +bool hid_is_usb(const struct hid_device *hdev) +{ + return hdev->ll_driver == &usb_hid_driver; +} +EXPORT_SYMBOL_GPL(hid_is_usb); static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id) { diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 5a1a625d8d16..eb1aedad7edc 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -86,6 +86,7 @@ static int als_read_raw(struct iio_dev *indio_dev, long mask) { struct als_state *als_state = iio_priv(indio_dev); + struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev; int report_id = -1; u32 address; int ret_type; @@ -110,11 +111,8 @@ static int als_read_raw(struct iio_dev *indio_dev, hid_sensor_power_state(&als_state->common_attributes, true); *val = sensor_hub_input_attr_get_raw_value( - als_state->common_attributes.hsdev, - HID_USAGE_SENSOR_ALS, address, - report_id, - SENSOR_HUB_SYNC, - min < 0); + hsdev, hsdev->usage, address, report_id, + SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&als_state->common_attributes, false); } else { @@ -259,9 +257,7 @@ static int als_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, st->als_illum.report_id); - st->scale_precision = hid_sensor_format_scale( - HID_USAGE_SENSOR_ALS, - &st->als_illum, + st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum, &st->scale_pre_decml, &st->scale_post_decml); return ret; @@ -285,7 +281,8 @@ static int hid_als_probe(struct platform_device *pdev) als_state->common_attributes.hsdev = hsdev; als_state->common_attributes.pdev = pdev; - ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS, + ret = hid_sensor_parse_common_attributes(hsdev, + hsdev->usage, &als_state->common_attributes, als_sensitivity_addresses, ARRAY_SIZE(als_sensitivity_addresses)); @@ -303,7 +300,8 @@ static int hid_als_probe(struct platform_device *pdev) ret = als_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, - HID_USAGE_SENSOR_ALS, als_state); + hsdev->usage, + als_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; @@ -333,8 +331,7 @@ static int hid_als_probe(struct platform_device *pdev) als_state->callbacks.send_event = als_proc_event; als_state->callbacks.capture_sample = als_capture_sample; als_state->callbacks.pdev = pdev; - ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS, - &als_state->callbacks); + ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); goto error_iio_unreg; @@ -356,7 +353,7 @@ static int hid_als_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct als_state *als_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS); + sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); @@ -368,6 +365,10 @@ static const struct platform_device_id hid_als_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200041", }, + { + /* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-LISS-0041", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_als_ids); diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index f10fa2abfe72..a47591e1bad9 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -61,6 +61,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); + struct hid_sensor_hub_device *hsdev; int report_id = -1; u32 address; int ret_type; @@ -75,6 +76,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, report_id = prox_state->prox_attr.report_id; min = prox_state->prox_attr.logical_minimum; address = HID_USAGE_SENSOR_HUMAN_PRESENCE; + hsdev = prox_state->common_attributes.hsdev; break; default: report_id = -1; @@ -84,11 +86,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, hid_sensor_power_state(&prox_state->common_attributes, true); *val = sensor_hub_input_attr_get_raw_value( - prox_state->common_attributes.hsdev, - HID_USAGE_SENSOR_PROX, address, - report_id, - SENSOR_HUB_SYNC, - min < 0); + hsdev, hsdev->usage, address, report_id, + SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&prox_state->common_attributes, false); } else { @@ -191,10 +190,16 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_HUMAN_PRESENCE: - prox_state->human_presence = *(u32 *)raw_data; - ret = 0; - break; - default: + switch (raw_len) { + case 1: + prox_state->human_presence = *(u8 *)raw_data; + return 0; + case 4: + prox_state->human_presence = *(u32 *)raw_data; + return 0; + default: + break; + } break; } @@ -244,7 +249,7 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->common_attributes.hsdev = hsdev; prox_state->common_attributes.pdev = pdev; - ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX, + ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, &prox_state->common_attributes, prox_sensitivity_addresses, ARRAY_SIZE(prox_sensitivity_addresses)); @@ -262,7 +267,7 @@ static int hid_prox_probe(struct platform_device *pdev) ret = prox_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, - HID_USAGE_SENSOR_PROX, prox_state); + hsdev->usage, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; @@ -291,8 +296,8 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->callbacks.send_event = prox_proc_event; prox_state->callbacks.capture_sample = prox_capture_sample; prox_state->callbacks.pdev = pdev; - ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX, - &prox_state->callbacks); + ret = sensor_hub_register_callback(hsdev, hsdev->usage, + &prox_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); goto error_iio_unreg; @@ -314,7 +319,7 @@ static int hid_prox_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct prox_state *prox_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX); + sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); @@ -326,6 +331,10 @@ static const struct platform_device_id hid_prox_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200011", }, + { + /* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-LISS-0226", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_prox_ids); diff --git a/drivers/platform/x86/asus-tf103c-dock.c b/drivers/platform/x86/asus-tf103c-dock.c index 62310e06282b..aeb1138464df 100644 --- a/drivers/platform/x86/asus-tf103c-dock.c +++ b/drivers/platform/x86/asus-tf103c-dock.c @@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum, return 0; } -static struct hid_ll_driver tf103c_dock_hid_ll_driver = { +static const struct hid_ll_driver tf103c_dock_hid_ll_driver = { .parse = tf103c_dock_hid_parse, .start = tf103c_dock_hid_start, .stop = tf103c_dock_hid_stop, @@ -259,7 +259,7 @@ static struct hid_ll_driver tf103c_dock_hid_ll_driver = { .raw_request = tf103c_dock_hid_raw_request, }; -static int tf103c_dock_toprow_codes[13][2] = { +static const int tf103c_dock_toprow_codes[13][2] = { /* Normal, AltGr pressed */ { KEY_POWER, KEY_F1 }, { KEY_RFKILL, KEY_F2 }, diff --git a/drivers/staging/greybus/hid.c b/drivers/staging/greybus/hid.c index adb91286803a..15335c38cb26 100644 --- a/drivers/staging/greybus/hid.c +++ b/drivers/staging/greybus/hid.c @@ -381,7 +381,7 @@ static int gb_hid_power(struct hid_device *hid, int lvl) } /* HID structure to pass callbacks */ -static struct hid_ll_driver gb_hid_ll_driver = { +static const struct hid_ll_driver gb_hid_ll_driver = { .parse = gb_hid_parse, .start = gb_hid_start, .stop = gb_hid_stop, diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index ac631159403a..13b1e65fbdcc 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -132,6 +132,7 @@ #define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301 #define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307 #define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305 +#define HID_USAGE_SENSOR_PROP_MODEL 0x200306 #define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E #define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F #define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310 diff --git a/include/linux/hid.h b/include/linux/hid.h index 8677ae38599e..6074d2a828fd 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -312,6 +312,7 @@ struct hid_item { #define HID_DG_LATENCYMODE 0x000d0060 #define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065 +#define HID_BAT_CHARGING 0x00850044 #define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076 @@ -595,7 +596,7 @@ struct hid_device { /* device report descriptor */ struct device dev; /* device */ struct hid_driver *driver; - struct hid_ll_driver *ll_driver; + const struct hid_ll_driver *ll_driver; struct mutex ll_open_lock; unsigned int ll_open_count; @@ -611,6 +612,7 @@ struct hid_device { /* device report descriptor */ __s32 battery_max; __s32 battery_report_type; __s32 battery_report_id; + __s32 battery_charge_status; enum hid_battery_status battery_status; bool battery_avoid_query; ktime_t battery_ratelimit_time; @@ -853,21 +855,7 @@ struct hid_ll_driver { bool (*may_wakeup)(struct hid_device *hdev); }; -extern struct hid_ll_driver i2c_hid_ll_driver; -extern struct hid_ll_driver hidp_hid_driver; -extern struct hid_ll_driver uhid_hid_driver; -extern struct hid_ll_driver usb_hid_driver; - -static inline bool hid_is_using_ll_driver(struct hid_device *hdev, - struct hid_ll_driver *driver) -{ - return hdev->ll_driver == driver; -} - -static inline bool hid_is_usb(struct hid_device *hdev) -{ - return hid_is_using_ll_driver(hdev, &usb_hid_driver); -} +extern bool hid_is_usb(const struct hid_device *hdev); #define PM_HINT_FULLON 1<<5 #define PM_HINT_NORMAL 1<<1 @@ -882,8 +870,6 @@ static inline bool hid_is_usb(struct hid_device *hdev) /* HID core API */ -extern int hid_debug; - extern bool hid_ignore(struct hid_device *); extern int hid_add_device(struct hid_device *); extern void hid_destroy_device(struct hid_device *); @@ -1191,11 +1177,7 @@ int hid_pidff_init(struct hid_device *hid); #define hid_pidff_init NULL #endif -#define dbg_hid(fmt, ...) \ -do { \ - if (hid_debug) \ - printk(KERN_DEBUG "%s: " fmt, __FILE__, ##__VA_ARGS__); \ -} while (0) +#define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__) #define hid_err(hid, fmt, ...) \ dev_err(&(hid)->dev, fmt, ##__VA_ARGS__) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index cc20e706c639..bed1a7b9205c 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -739,7 +739,7 @@ static void hidp_stop(struct hid_device *hid) hid->claimed = 0; } -struct hid_ll_driver hidp_hid_driver = { +static const struct hid_ll_driver hidp_hid_driver = { .parse = hidp_parse, .start = hidp_start, .stop = hidp_stop, @@ -748,7 +748,6 @@ struct hid_ll_driver hidp_hid_driver = { .raw_request = hidp_raw_request, .output_report = hidp_output_report, }; -EXPORT_SYMBOL_GPL(hidp_hid_driver); /* This function sets up the hid device. It does not add it to the HID system. That is done in hidp_add_connection(). */ |