Commit d004701d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

 - Support for Logitech G15 (Hans de Goede)

 - HID parser improvements, improving support for some devices; e.g.
   Windows Precision Touchpad, products from Primax, etc. (Blaž
   Hrastnik, Candle Sun)

 - robustification of tablet mode support in google-whiskers driver
   (Dmitry Torokhov)

 - assorted small fixes, device-specific quirks and device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (23 commits)
  HID: rmi: Check that the RMI_STARTED bit is set before unregistering the RMI transport device
  HID: quirks: remove hid-led devices from hid_have_special_driver
  HID: Improve Windows Precision Touchpad detection.
  HID: i2c-hid: Reset ALPS touchpads on resume
  HID: i2c-hid: fix no irq after reset on raydium 3118
  HID: logitech-hidpp: Silence intermittent get_battery_capacity errors
  HID: i2c-hid: remove orphaned member sleep_delay
  HID: quirks: Add quirk for HP MSU1465 PIXART OEM mouse
  HID: core: check whether Usage Page item is after Usage ID items
  HID: intel-ish-hid: Spelling s/diconnect/disconnect/
  HID: google: Detect base folded usage instead of hard-coding whiskers
  HID: logitech: Add depends on LEDS_CLASS to Logitech Kconfig entry
  HID: lg-g15: Add support for the G510's M1-M3 and MR LEDs
  HID: lg-g15: Add support for controlling the G510's RGB backlight
  HID: lg-g15: Add support for the G510 keyboards' gaming keys
  HID: lg-g15: Add support for the M1-M3 and MR LEDs
  HID: lg-g15: Add keyboard and LCD backlight control
  HID: Add driver for Logitech gaming keyboards (G15, G15 v2)
  Input: Add event-codes for macro keys found on various keyboards
  HID: hidraw: replace printk() with corresponding pr_xx() variant
  ...
parents 4a08fe57 d8d04708
...@@ -9709,6 +9709,13 @@ S: Maintained ...@@ -9709,6 +9709,13 @@ S: Maintained
F: Documentation/admin-guide/ldm.rst F: Documentation/admin-guide/ldm.rst
F: block/partitions/ldm.* F: block/partitions/ldm.*
LOGITECH HID GAMING KEYBOARDS
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
S: Maintained
F: drivers/hid/hid-lg-g15.c
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI) LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
M: Sathya Prakash <sathya.prakash@broadcom.com> M: Sathya Prakash <sathya.prakash@broadcom.com>
M: Chaitra P B <chaitra.basappa@broadcom.com> M: Chaitra P B <chaitra.basappa@broadcom.com>
......
...@@ -525,6 +525,7 @@ config HID_LENOVO ...@@ -525,6 +525,7 @@ config HID_LENOVO
config HID_LOGITECH config HID_LOGITECH
tristate "Logitech devices" tristate "Logitech devices"
depends on HID depends on HID
depends on LEDS_CLASS
default !EXPERT default !EXPERT
---help--- ---help---
Support for Logitech devices that are not fully compliant with HID standard. Support for Logitech devices that are not fully compliant with HID standard.
......
...@@ -64,6 +64,7 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o ...@@ -64,6 +64,7 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH) += hid-lg-g15.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o
obj-$(CONFIG_HID_MACALLY) += hid-macally.o obj-$(CONFIG_HID_MACALLY) += hid-macally.o
......
...@@ -211,6 +211,18 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) ...@@ -211,6 +211,18 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
return 0; /* we know nothing about this usage type */ return 0; /* we know nothing about this usage type */
} }
/*
* Concatenate usage which defines 16 bits or less with the
* currently defined usage page to form a 32 bit usage
*/
static void complete_usage(struct hid_parser *parser, unsigned int index)
{
parser->local.usage[index] &= 0xFFFF;
parser->local.usage[index] |=
(parser->global.usage_page & 0xFFFF) << 16;
}
/* /*
* Add a usage to the temporary parser table. * Add a usage to the temporary parser table.
*/ */
...@@ -222,6 +234,14 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size) ...@@ -222,6 +234,14 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
return -1; return -1;
} }
parser->local.usage[parser->local.usage_index] = usage; parser->local.usage[parser->local.usage_index] = usage;
/*
* If Usage item only includes usage id, concatenate it with
* currently defined usage page
*/
if (size <= 2)
complete_usage(parser, parser->local.usage_index);
parser->local.usage_size[parser->local.usage_index] = size; parser->local.usage_size[parser->local.usage_index] = size;
parser->local.collection_index[parser->local.usage_index] = parser->local.collection_index[parser->local.usage_index] =
parser->collection_stack_ptr ? parser->collection_stack_ptr ?
...@@ -543,13 +563,32 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) ...@@ -543,13 +563,32 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
* usage value." * usage value."
*/ */
static void hid_concatenate_usage_page(struct hid_parser *parser) static void hid_concatenate_last_usage_page(struct hid_parser *parser)
{ {
int i; int i;
unsigned int usage_page;
unsigned int current_page;
if (!parser->local.usage_index)
return;
for (i = 0; i < parser->local.usage_index; i++) usage_page = parser->global.usage_page;
if (parser->local.usage_size[i] <= 2)
parser->local.usage[i] += parser->global.usage_page << 16; /*
* Concatenate usage page again only if last declared Usage Page
* has not been already used in previous usages concatenation
*/
for (i = parser->local.usage_index - 1; i >= 0; i--) {
if (parser->local.usage_size[i] > 2)
/* Ignore extended usages */
continue;
current_page = parser->local.usage[i] >> 16;
if (current_page == usage_page)
break;
complete_usage(parser, i);
}
} }
/* /*
...@@ -561,7 +600,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) ...@@ -561,7 +600,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
__u32 data; __u32 data;
int ret; int ret;
hid_concatenate_usage_page(parser); hid_concatenate_last_usage_page(parser);
data = item_udata(item); data = item_udata(item);
...@@ -742,6 +781,10 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) ...@@ -742,6 +781,10 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
if (usage == 0xff0000c5 && parser->global.report_count == 256 && if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
parser->global.report_size == 8) parser->global.report_size == 8)
parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8; parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
if (usage == 0xff0000c6 && parser->global.report_count == 1 &&
parser->global.report_size == 8)
parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
} }
static void hid_scan_collection(struct hid_parser *parser, unsigned type) static void hid_scan_collection(struct hid_parser *parser, unsigned type)
...@@ -772,7 +815,7 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) ...@@ -772,7 +815,7 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
__u32 data; __u32 data;
int i; int i;
hid_concatenate_usage_page(parser); hid_concatenate_last_usage_page(parser);
data = item_udata(item); data = item_udata(item);
......
...@@ -35,6 +35,7 @@ struct cbas_ec { ...@@ -35,6 +35,7 @@ struct cbas_ec {
struct device *dev; /* The platform device (EC) */ struct device *dev; /* The platform device (EC) */
struct input_dev *input; struct input_dev *input;
bool base_present; bool base_present;
bool base_folded;
struct notifier_block notifier; struct notifier_block notifier;
}; };
...@@ -208,7 +209,14 @@ static int __cbas_ec_probe(struct platform_device *pdev) ...@@ -208,7 +209,14 @@ static int __cbas_ec_probe(struct platform_device *pdev)
return error; return error;
} }
input_report_switch(input, SW_TABLET_MODE, !cbas_ec.base_present); if (!cbas_ec.base_present)
cbas_ec.base_folded = false;
dev_dbg(&pdev->dev, "%s: base: %d, folded: %d\n", __func__,
cbas_ec.base_present, cbas_ec.base_folded);
input_report_switch(input, SW_TABLET_MODE,
!cbas_ec.base_present || cbas_ec.base_folded);
cbas_ec_set_input(input); cbas_ec_set_input(input);
...@@ -322,10 +330,9 @@ static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev, ...@@ -322,10 +330,9 @@ static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev,
static int hammer_register_leds(struct hid_device *hdev) static int hammer_register_leds(struct hid_device *hdev)
{ {
struct hammer_kbd_leds *kbd_backlight; struct hammer_kbd_leds *kbd_backlight;
int error;
kbd_backlight = devm_kzalloc(&hdev->dev, kbd_backlight = kzalloc(sizeof(*kbd_backlight), GFP_KERNEL);
sizeof(*kbd_backlight),
GFP_KERNEL);
if (!kbd_backlight) if (!kbd_backlight)
return -ENOMEM; return -ENOMEM;
...@@ -339,12 +346,31 @@ static int hammer_register_leds(struct hid_device *hdev) ...@@ -339,12 +346,31 @@ static int hammer_register_leds(struct hid_device *hdev)
/* Set backlight to 0% initially. */ /* Set backlight to 0% initially. */
hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0); hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0);
return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev); error = led_classdev_register(&hdev->dev, &kbd_backlight->cdev);
if (error)
goto err_free_mem;
hid_set_drvdata(hdev, kbd_backlight);
return 0;
err_free_mem:
kfree(kbd_backlight);
return error;
}
static void hammer_unregister_leds(struct hid_device *hdev)
{
struct hammer_kbd_leds *kbd_backlight = hid_get_drvdata(hdev);
if (kbd_backlight) {
led_classdev_unregister(&kbd_backlight->cdev);
kfree(kbd_backlight);
}
} }
#define HID_UP_GOOGLEVENDOR 0xffd10000 #define HID_UP_GOOGLEVENDOR 0xffd10000
#define HID_VD_KBD_FOLDED 0x00000019 #define HID_VD_KBD_FOLDED 0x00000019
#define WHISKERS_KBD_FOLDED (HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED) #define HID_USAGE_KBD_FOLDED (HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED)
/* HID usage for keyboard backlight (Alphanumeric display brightness) */ /* HID usage for keyboard backlight (Alphanumeric display brightness) */
#define HID_AD_BRIGHTNESS 0x00140046 #define HID_AD_BRIGHTNESS 0x00140046
...@@ -354,8 +380,7 @@ static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -354,8 +380,7 @@ static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_usage *usage, struct hid_usage *usage,
unsigned long **bit, int *max) unsigned long **bit, int *max)
{ {
if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS && if (usage->hid == HID_USAGE_KBD_FOLDED) {
usage->hid == WHISKERS_KBD_FOLDED) {
/* /*
* We do not want to have this usage mapped as it will get * We do not want to have this usage mapped as it will get
* mixed in with "base attached" signal and delivered over * mixed in with "base attached" signal and delivered over
...@@ -372,19 +397,19 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field, ...@@ -372,19 +397,19 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
{ {
unsigned long flags; unsigned long flags;
if (hid->product == USB_DEVICE_ID_GOOGLE_WHISKERS && if (usage->hid == HID_USAGE_KBD_FOLDED) {
usage->hid == WHISKERS_KBD_FOLDED) {
spin_lock_irqsave(&cbas_ec_lock, flags); spin_lock_irqsave(&cbas_ec_lock, flags);
hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
cbas_ec.base_present, value);
/* /*
* We should not get event if base is detached, but in case * If we are getting events from Whiskers that means that it
* we happen to service HID and EC notifications out of order * is attached to the lid.
* let's still check the "base present" flag.
*/ */
if (cbas_ec.input && cbas_ec.base_present) { cbas_ec.base_present = true;
cbas_ec.base_folded = value;
hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
cbas_ec.base_present, cbas_ec.base_folded);
if (cbas_ec.input) {
input_report_switch(cbas_ec.input, input_report_switch(cbas_ec.input,
SW_TABLET_MODE, value); SW_TABLET_MODE, value);
input_sync(cbas_ec.input); input_sync(cbas_ec.input);
...@@ -397,33 +422,22 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field, ...@@ -397,33 +422,22 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
return 0; return 0;
} }
static bool hammer_is_keyboard_interface(struct hid_device *hdev) static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
unsigned application, unsigned usage)
{ {
struct hid_report_enum *re = &hdev->report_enum[HID_INPUT_REPORT]; struct hid_report_enum *re = &hdev->report_enum[report_type];
struct hid_report *report;
list_for_each_entry(report, &re->report_list, list)
if (report->application == HID_GD_KEYBOARD)
return true;
return false;
}
static bool hammer_has_backlight_control(struct hid_device *hdev)
{
struct hid_report_enum *re = &hdev->report_enum[HID_OUTPUT_REPORT];
struct hid_report *report; struct hid_report *report;
int i, j; int i, j;
list_for_each_entry(report, &re->report_list, list) { list_for_each_entry(report, &re->report_list, list) {
if (report->application != HID_GD_KEYBOARD) if (report->application != application)
continue; continue;
for (i = 0; i < report->maxfield; i++) { for (i = 0; i < report->maxfield; i++) {
struct hid_field *field = report->field[i]; struct hid_field *field = report->field[i];
for (j = 0; j < field->maxusage; j++) for (j = 0; j < field->maxusage; j++)
if (field->usage[j].hid == HID_AD_BRIGHTNESS) if (field->usage[j].hid == usage)
return true; return true;
} }
} }
...@@ -431,21 +445,23 @@ static bool hammer_has_backlight_control(struct hid_device *hdev) ...@@ -431,21 +445,23 @@ static bool hammer_has_backlight_control(struct hid_device *hdev)
return false; return false;
} }
static bool hammer_has_folded_event(struct hid_device *hdev)
{
return hammer_has_usage(hdev, HID_INPUT_REPORT,
HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
}
static bool hammer_has_backlight_control(struct hid_device *hdev)
{
return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
}
static int hammer_probe(struct hid_device *hdev, static int hammer_probe(struct hid_device *hdev,
const struct hid_device_id *id) const struct hid_device_id *id)
{ {
int error; int error;
/*
* We always want to poll for, and handle tablet mode events from
* Whiskers, even when nobody has opened the input device. This also
* prevents the hid core from dropping early tablet mode events from
* the device.
*/
if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
hammer_is_keyboard_interface(hdev))
hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
error = hid_parse(hdev); error = hid_parse(hdev);
if (error) if (error)
return error; return error;
...@@ -454,6 +470,19 @@ static int hammer_probe(struct hid_device *hdev, ...@@ -454,6 +470,19 @@ static int hammer_probe(struct hid_device *hdev,
if (error) if (error)
return error; return error;
/*
* We always want to poll for, and handle tablet mode events from
* devices that have folded usage, even when nobody has opened the input
* device. This also prevents the hid core from dropping early tablet
* mode events from the device.
*/
if (hammer_has_folded_event(hdev)) {
hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
error = hid_hw_open(hdev);
if (error)
return error;
}
if (hammer_has_backlight_control(hdev)) { if (hammer_has_backlight_control(hdev)) {
error = hammer_register_leds(hdev); error = hammer_register_leds(hdev);
if (error) if (error)
...@@ -465,6 +494,36 @@ static int hammer_probe(struct hid_device *hdev, ...@@ -465,6 +494,36 @@ static int hammer_probe(struct hid_device *hdev,
return 0; return 0;
} }
static void hammer_remove(struct hid_device *hdev)
{
unsigned long flags;
if (hammer_has_folded_event(hdev)) {
hid_hw_close(hdev);
/*
* If we are disconnecting then most likely Whiskers is
* being removed. Even if it is not removed, without proper
* keyboard we should not stay in clamshell mode.
*
* The reason for doing it here and not waiting for signal
* from EC, is that on some devices there are high leakage
* on Whiskers pins and we do not detect disconnect reliably,
* resulting in devices being stuck in clamshell mode.
*/
spin_lock_irqsave(&cbas_ec_lock, flags);
if (cbas_ec.input && cbas_ec.base_present) {
input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
input_sync(cbas_ec.input);
}
cbas_ec.base_present = false;
spin_unlock_irqrestore(&cbas_ec_lock, flags);
}
hammer_unregister_leds(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id hammer_devices[] = { static const struct hid_device_id hammer_devices[] = {
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
...@@ -487,6 +546,7 @@ static struct hid_driver hammer_driver = { ...@@ -487,6 +546,7 @@ static struct hid_driver hammer_driver = {
.name = "hammer", .name = "hammer",
.id_table = hammer_devices, .id_table = hammer_devices,
.probe = hammer_probe, .probe = hammer_probe,
.remove = hammer_remove,
.input_mapping = hammer_input_mapping, .input_mapping = hammer_input_mapping,
.event = hammer_event, .event = hammer_event,
}; };
......
...@@ -573,6 +573,7 @@ ...@@ -573,6 +573,7 @@
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941 0x0941 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941 0x0941
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a 0x1f4a
#define USB_VENDOR_ID_HUION 0x256c #define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e #define USB_DEVICE_ID_HUION_TABLET 0x006e
...@@ -749,6 +750,10 @@ ...@@ -749,6 +750,10 @@
#define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216 #define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
#define USB_DEVICE_ID_LOGITECH_G15_LCD 0xc222
#define USB_DEVICE_ID_LOGITECH_G15_V2_LCD 0xc227
#define USB_DEVICE_ID_LOGITECH_G510 0xc22d
#define USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO 0xc22e
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f #define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f
#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262 #define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
...@@ -959,6 +964,7 @@ ...@@ -959,6 +964,7 @@
#define I2C_VENDOR_ID_RAYDIUM 0x2386 #define I2C_VENDOR_ID_RAYDIUM 0x2386
#define I2C_PRODUCT_ID_RAYDIUM_4B33 0x4b33 #define I2C_PRODUCT_ID_RAYDIUM_4B33 0x4b33
#define I2C_PRODUCT_ID_RAYDIUM_3118 0x3118
#define USB_VENDOR_ID_RAZER 0x1532 #define USB_VENDOR_ID_RAZER 0x1532
#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D #define USB_DEVICE_ID_RAZER_BLADE_14 0x011D
......
This diff is collapsed.
...@@ -1102,6 +1102,9 @@ static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp, ...@@ -1102,6 +1102,9 @@ static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp,
ret = hidpp_send_fap_command_sync(hidpp, feature_index, ret = hidpp_send_fap_command_sync(hidpp, feature_index,
CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS, CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS,
NULL, 0, &response); NULL, 0, &response);
/* Ignore these intermittent errors */
if (ret == HIDPP_ERROR_RESOURCE_ERROR)
return -EIO;
if (ret > 0) { if (ret > 0) {
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
__func__, ret); __func__, ret);
......
...@@ -94,6 +94,7 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -94,6 +94,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
...@@ -419,13 +420,6 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -419,13 +420,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_LCPOWER) #if IS_ENABLED(CONFIG_HID_LCPOWER)
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_LED)
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_LUXAFOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
#endif
#if IS_ENABLED(CONFIG_HID_LENOVO) #if IS_ENABLED(CONFIG_HID_LENOVO)
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
......
...@@ -744,7 +744,8 @@ static void rmi_remove(struct hid_device *hdev) ...@@ -744,7 +744,8 @@ static void rmi_remove(struct hid_device *hdev)
{ {
struct rmi_data *hdata = hid_get_drvdata(hdev); struct rmi_data *hdata = hid_get_drvdata(hdev);
if (hdata->device_flags & RMI_DEVICE) { if ((hdata->device_flags & RMI_DEVICE)
&& test_bit(RMI_STARTED, &hdata->flags)) {
clear_bit(RMI_STARTED, &hdata->flags); clear_bit(RMI_STARTED, &hdata->flags);
cancel_work_sync(&hdata->reset_work); cancel_work_sync(&hdata->reset_work);
rmi_unregister_transport_device(&hdata->xport); rmi_unregister_transport_device(&hdata->xport);
......
...@@ -197,15 +197,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t ...@@ -197,15 +197,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
} }
if (count > HID_MAX_BUFFER_SIZE) { if (count > HID_MAX_BUFFER_SIZE) {
printk(KERN_WARNING "hidraw: pid %d passed too large report\n", hid_warn(dev, "pid %d passed too large report\n",
task_pid_nr(current)); task_pid_nr(current));
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (count < 2) { if (count < 2) {
printk(KERN_WARNING "hidraw: pid %d passed too short report\n", hid_warn(dev, "pid %d passed too short report\n",
task_pid_nr(current)); task_pid_nr(current));
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
...@@ -595,7 +595,7 @@ int __init hidraw_init(void) ...@@ -595,7 +595,7 @@ int __init hidraw_init(void)
if (result < 0) if (result < 0)
goto error_class; goto error_class;
printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina\n"); pr_info("raw HID events driver (C) Jiri Kosina\n");
out: out:
return result; return result;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1) #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
#define I2C_HID_QUIRK_BOGUS_IRQ BIT(4) #define I2C_HID_QUIRK_BOGUS_IRQ BIT(4)
#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5)
/* flags */ /* flags */
#define I2C_HID_STARTED 0 #define I2C_HID_STARTED 0
...@@ -157,8 +158,6 @@ struct i2c_hid { ...@@ -157,8 +158,6 @@ struct i2c_hid {
bool irq_wake_enabled; bool irq_wake_enabled;
struct mutex reset_lock; struct mutex reset_lock;
unsigned long sleep_delay;
}; };
static const struct i2c_hid_quirks { static const struct i2c_hid_quirks {
...@@ -170,8 +169,12 @@ static const struct i2c_hid_quirks { ...@@ -170,8 +169,12 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288, { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
{ I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_3118,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
{ USB_VENDOR_ID_ELAN, HID_ANY_ID, { USB_VENDOR_ID_ELAN, HID_ANY_ID,
I2C_HID_QUIRK_BOGUS_IRQ }, I2C_HID_QUIRK_BOGUS_IRQ },
{ USB_VENDOR_ID_ALPS_JP, HID_ANY_ID,
I2C_HID_QUIRK_RESET_ON_RESUME },
{ 0, 0 } { 0, 0 }
}; };
...@@ -1212,8 +1215,15 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1212,8 +1215,15 @@ static int i2c_hid_resume(struct device *dev)
* solves "incomplete reports" on Raydium devices 2386:3118 and * solves "incomplete reports" on Raydium devices 2386:3118 and
* 2386:4B33 and fixes various SIS touchscreens no longer sending * 2386:4B33 and fixes various SIS touchscreens no longer sending
* data after a suspend/resume. * data after a suspend/resume.
*
* However some ALPS touchpads generate IRQ storm without reset, so
* let's still reset them here.
*/ */
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
ret = i2c_hid_hwreset(client);
else
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret) if (ret)
return ret; return ret;
......
...@@ -402,7 +402,7 @@ static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev, ...@@ -402,7 +402,7 @@ static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
* @dev: ISHTP device instance * @dev: ISHTP device instance
* @disconnect_req: disconnect request structure * @disconnect_req: disconnect request structure
* *
* Disconnect request bus message from the fw. Send diconnect response. * Disconnect request bus message from the fw. Send disconnect response.
*/ */
static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev, static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
struct hbm_client_connect_request *disconnect_req) struct hbm_client_connect_request *disconnect_req)
......
...@@ -650,6 +650,81 @@ ...@@ -650,6 +650,81 @@
#define KEY_DATA 0x277 #define KEY_DATA 0x277
#define KEY_ONSCREEN_KEYBOARD 0x278 #define KEY_ONSCREEN_KEYBOARD 0x278
/*
* Some keyboards have keys which do not have a defined meaning, these keys
* are intended to be programmed / bound to macros by the user. For most
* keyboards with these macro-keys the key-sequence to inject, or action to
* take, is all handled by software on the host side. So from the kernel's
* point of view these are just normal keys.
*
* The KEY_MACRO# codes below are intended for such keys, which may be labeled
* e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys
* where the marking on the key does indicate a defined meaning / purpose.
*
* The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing
* KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO
* define MUST be added.
*/
#define KEY_MACRO1 0x290
#define KEY_MACRO2 0x291
#define KEY_MACRO3 0x292
#define KEY_MACRO4 0x293
#define KEY_MACRO5 0x294
#define KEY_MACRO6 0x295
#define KEY_MACRO7 0x296
#define KEY_MACRO8 0x297
#define KEY_MACRO9 0x298
#define KEY_MACRO10 0x299
#define KEY_MACRO11 0x29a
#define KEY_MACRO12 0x29b
#define KEY_MACRO13 0x29c
#define KEY_MACRO14 0x29d
#define KEY_MACRO15 0x29e
#define KEY_MACRO16 0x29f
#define KEY_MACRO17 0x2a0
#define KEY_MACRO18 0x2a1
#define KEY_MACRO19 0x2a2
#define KEY_MACRO20 0x2a3
#define KEY_MACRO21 0x2a4
#define KEY_MACRO22 0x2a5
#define KEY_MACRO23 0x2a6
#define KEY_MACRO24 0x2a7
#define KEY_MACRO25 0x2a8
#define KEY_MACRO26 0x2a9
#define KEY_MACRO27 0x2aa
#define KEY_MACRO28 0x2ab
#define KEY_MACRO29 0x2ac
#define KEY_MACRO30 0x2ad
/*
* Some keyboards with the macro-keys described above have some extra keys
* for controlling the host-side software responsible for the macro handling:
* -A macro recording start/stop key. Note that not all keyboards which emit
* KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if
* KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START
* should be interpreted as a recording start/stop toggle;
* -Keys for switching between different macro (pre)sets, either a key for
* cycling through the configured presets or keys to directly select a preset.
*/
#define KEY_MACRO_RECORD_START 0x2b0
#define KEY_MACRO_RECORD_STOP 0x2b1
#define KEY_MACRO_PRESET_CYCLE 0x2b2
#define KEY_MACRO_PRESET1 0x2b3
#define KEY_MACRO_PRESET2 0x2b4
#define KEY_MACRO_PRESET3 0x2b5
/*
* Some keyboards have a buildin LCD panel where the contents are controlled
* by the host. Often these have a number of keys directly below the LCD
* intended for controlling a menu shown on the LCD. These keys often don't
* have any labeling so we just name them KEY_KBD_LCD_MENU#
*/
#define KEY_KBD_LCD_MENU1 0x2b8
#define KEY_KBD_LCD_MENU2 0x2b9
#define KEY_KBD_LCD_MENU3 0x2ba
#define KEY_KBD_LCD_MENU4 0x2bb
#define KEY_KBD_LCD_MENU5 0x2bc
#define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1 #define BTN_TRIGGER_HAPPY2 0x2c1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment