Skip to content

Commit d004701

Browse files
committed
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 ...
2 parents 4a08fe5 + d8d0470 commit d004701

File tree

14 files changed

+1166
-66
lines changed

14 files changed

+1166
-66
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9709,6 +9709,13 @@ S: Maintained
97099709
F: Documentation/admin-guide/ldm.rst
97109710
F: block/partitions/ldm.*
97119711

9712+
LOGITECH HID GAMING KEYBOARDS
9713+
M: Hans de Goede <[email protected]>
9714+
9715+
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
9716+
S: Maintained
9717+
F: drivers/hid/hid-lg-g15.c
9718+
97129719
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
97139720
M: Sathya Prakash <[email protected]>
97149721
M: Chaitra P B <[email protected]>

drivers/hid/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ config HID_LENOVO
525525
config HID_LOGITECH
526526
tristate "Logitech devices"
527527
depends on HID
528+
depends on LEDS_CLASS
528529
default !EXPERT
529530
---help---
530531
Support for Logitech devices that are not fully compliant with HID standard.

drivers/hid/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o
6464
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
6565
obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o
6666
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
67+
obj-$(CONFIG_HID_LOGITECH) += hid-lg-g15.o
6768
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
6869
obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o
6970
obj-$(CONFIG_HID_MACALLY) += hid-macally.o

drivers/hid/hid-core.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
211211
return 0; /* we know nothing about this usage type */
212212
}
213213

214+
/*
215+
* Concatenate usage which defines 16 bits or less with the
216+
* currently defined usage page to form a 32 bit usage
217+
*/
218+
219+
static void complete_usage(struct hid_parser *parser, unsigned int index)
220+
{
221+
parser->local.usage[index] &= 0xFFFF;
222+
parser->local.usage[index] |=
223+
(parser->global.usage_page & 0xFFFF) << 16;
224+
}
225+
214226
/*
215227
* Add a usage to the temporary parser table.
216228
*/
@@ -222,6 +234,14 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
222234
return -1;
223235
}
224236
parser->local.usage[parser->local.usage_index] = usage;
237+
238+
/*
239+
* If Usage item only includes usage id, concatenate it with
240+
* currently defined usage page
241+
*/
242+
if (size <= 2)
243+
complete_usage(parser, parser->local.usage_index);
244+
225245
parser->local.usage_size[parser->local.usage_index] = size;
226246
parser->local.collection_index[parser->local.usage_index] =
227247
parser->collection_stack_ptr ?
@@ -543,13 +563,32 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
543563
* usage value."
544564
*/
545565

546-
static void hid_concatenate_usage_page(struct hid_parser *parser)
566+
static void hid_concatenate_last_usage_page(struct hid_parser *parser)
547567
{
548568
int i;
569+
unsigned int usage_page;
570+
unsigned int current_page;
571+
572+
if (!parser->local.usage_index)
573+
return;
549574

550-
for (i = 0; i < parser->local.usage_index; i++)
551-
if (parser->local.usage_size[i] <= 2)
552-
parser->local.usage[i] += parser->global.usage_page << 16;
575+
usage_page = parser->global.usage_page;
576+
577+
/*
578+
* Concatenate usage page again only if last declared Usage Page
579+
* has not been already used in previous usages concatenation
580+
*/
581+
for (i = parser->local.usage_index - 1; i >= 0; i--) {
582+
if (parser->local.usage_size[i] > 2)
583+
/* Ignore extended usages */
584+
continue;
585+
586+
current_page = parser->local.usage[i] >> 16;
587+
if (current_page == usage_page)
588+
break;
589+
590+
complete_usage(parser, i);
591+
}
553592
}
554593

555594
/*
@@ -561,7 +600,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
561600
__u32 data;
562601
int ret;
563602

564-
hid_concatenate_usage_page(parser);
603+
hid_concatenate_last_usage_page(parser);
565604

566605
data = item_udata(item);
567606

@@ -742,6 +781,10 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
742781
if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
743782
parser->global.report_size == 8)
744783
parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
784+
785+
if (usage == 0xff0000c6 && parser->global.report_count == 1 &&
786+
parser->global.report_size == 8)
787+
parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
745788
}
746789

747790
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)
772815
__u32 data;
773816
int i;
774817

775-
hid_concatenate_usage_page(parser);
818+
hid_concatenate_last_usage_page(parser);
776819

777820
data = item_udata(item);
778821

drivers/hid/hid-google-hammer.c

Lines changed: 103 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct cbas_ec {
3535
struct device *dev; /* The platform device (EC) */
3636
struct input_dev *input;
3737
bool base_present;
38+
bool base_folded;
3839
struct notifier_block notifier;
3940
};
4041

@@ -208,7 +209,14 @@ static int __cbas_ec_probe(struct platform_device *pdev)
208209
return error;
209210
}
210211

211-
input_report_switch(input, SW_TABLET_MODE, !cbas_ec.base_present);
212+
if (!cbas_ec.base_present)
213+
cbas_ec.base_folded = false;
214+
215+
dev_dbg(&pdev->dev, "%s: base: %d, folded: %d\n", __func__,
216+
cbas_ec.base_present, cbas_ec.base_folded);
217+
218+
input_report_switch(input, SW_TABLET_MODE,
219+
!cbas_ec.base_present || cbas_ec.base_folded);
212220

213221
cbas_ec_set_input(input);
214222

@@ -322,10 +330,9 @@ static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev,
322330
static int hammer_register_leds(struct hid_device *hdev)
323331
{
324332
struct hammer_kbd_leds *kbd_backlight;
333+
int error;
325334

326-
kbd_backlight = devm_kzalloc(&hdev->dev,
327-
sizeof(*kbd_backlight),
328-
GFP_KERNEL);
335+
kbd_backlight = kzalloc(sizeof(*kbd_backlight), GFP_KERNEL);
329336
if (!kbd_backlight)
330337
return -ENOMEM;
331338

@@ -339,12 +346,31 @@ static int hammer_register_leds(struct hid_device *hdev)
339346
/* Set backlight to 0% initially. */
340347
hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0);
341348

342-
return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev);
349+
error = led_classdev_register(&hdev->dev, &kbd_backlight->cdev);
350+
if (error)
351+
goto err_free_mem;
352+
353+
hid_set_drvdata(hdev, kbd_backlight);
354+
return 0;
355+
356+
err_free_mem:
357+
kfree(kbd_backlight);
358+
return error;
359+
}
360+
361+
static void hammer_unregister_leds(struct hid_device *hdev)
362+
{
363+
struct hammer_kbd_leds *kbd_backlight = hid_get_drvdata(hdev);
364+
365+
if (kbd_backlight) {
366+
led_classdev_unregister(&kbd_backlight->cdev);
367+
kfree(kbd_backlight);
368+
}
343369
}
344370

345371
#define HID_UP_GOOGLEVENDOR 0xffd10000
346372
#define HID_VD_KBD_FOLDED 0x00000019
347-
#define WHISKERS_KBD_FOLDED (HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED)
373+
#define HID_USAGE_KBD_FOLDED (HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED)
348374

349375
/* HID usage for keyboard backlight (Alphanumeric display brightness) */
350376
#define HID_AD_BRIGHTNESS 0x00140046
@@ -354,8 +380,7 @@ static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi,
354380
struct hid_usage *usage,
355381
unsigned long **bit, int *max)
356382
{
357-
if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
358-
usage->hid == WHISKERS_KBD_FOLDED) {
383+
if (usage->hid == HID_USAGE_KBD_FOLDED) {
359384
/*
360385
* We do not want to have this usage mapped as it will get
361386
* 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,
372397
{
373398
unsigned long flags;
374399

375-
if (hid->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
376-
usage->hid == WHISKERS_KBD_FOLDED) {
400+
if (usage->hid == HID_USAGE_KBD_FOLDED) {
377401
spin_lock_irqsave(&cbas_ec_lock, flags);
378402

379-
hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
380-
cbas_ec.base_present, value);
381-
382403
/*
383-
* We should not get event if base is detached, but in case
384-
* we happen to service HID and EC notifications out of order
385-
* let's still check the "base present" flag.
404+
* If we are getting events from Whiskers that means that it
405+
* is attached to the lid.
386406
*/
387-
if (cbas_ec.input && cbas_ec.base_present) {
407+
cbas_ec.base_present = true;
408+
cbas_ec.base_folded = value;
409+
hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
410+
cbas_ec.base_present, cbas_ec.base_folded);
411+
412+
if (cbas_ec.input) {
388413
input_report_switch(cbas_ec.input,
389414
SW_TABLET_MODE, value);
390415
input_sync(cbas_ec.input);
@@ -397,55 +422,46 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
397422
return 0;
398423
}
399424

400-
static bool hammer_is_keyboard_interface(struct hid_device *hdev)
425+
static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
426+
unsigned application, unsigned usage)
401427
{
402-
struct hid_report_enum *re = &hdev->report_enum[HID_INPUT_REPORT];
403-
struct hid_report *report;
404-
405-
list_for_each_entry(report, &re->report_list, list)
406-
if (report->application == HID_GD_KEYBOARD)
407-
return true;
408-
409-
return false;
410-
}
411-
412-
static bool hammer_has_backlight_control(struct hid_device *hdev)
413-
{
414-
struct hid_report_enum *re = &hdev->report_enum[HID_OUTPUT_REPORT];
428+
struct hid_report_enum *re = &hdev->report_enum[report_type];
415429
struct hid_report *report;
416430
int i, j;
417431

418432
list_for_each_entry(report, &re->report_list, list) {
419-
if (report->application != HID_GD_KEYBOARD)
433+
if (report->application != application)
420434
continue;
421435

422436
for (i = 0; i < report->maxfield; i++) {
423437
struct hid_field *field = report->field[i];
424438

425439
for (j = 0; j < field->maxusage; j++)
426-
if (field->usage[j].hid == HID_AD_BRIGHTNESS)
440+
if (field->usage[j].hid == usage)
427441
return true;
428442
}
429443
}
430444

431445
return false;
432446
}
433447

448+
static bool hammer_has_folded_event(struct hid_device *hdev)
449+
{
450+
return hammer_has_usage(hdev, HID_INPUT_REPORT,
451+
HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
452+
}
453+
454+
static bool hammer_has_backlight_control(struct hid_device *hdev)
455+
{
456+
return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
457+
HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
458+
}
459+
434460
static int hammer_probe(struct hid_device *hdev,
435461
const struct hid_device_id *id)
436462
{
437463
int error;
438464

439-
/*
440-
* We always want to poll for, and handle tablet mode events from
441-
* Whiskers, even when nobody has opened the input device. This also
442-
* prevents the hid core from dropping early tablet mode events from
443-
* the device.
444-
*/
445-
if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
446-
hammer_is_keyboard_interface(hdev))
447-
hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
448-
449465
error = hid_parse(hdev);
450466
if (error)
451467
return error;
@@ -454,6 +470,19 @@ static int hammer_probe(struct hid_device *hdev,
454470
if (error)
455471
return error;
456472

473+
/*
474+
* We always want to poll for, and handle tablet mode events from
475+
* devices that have folded usage, even when nobody has opened the input
476+
* device. This also prevents the hid core from dropping early tablet
477+
* mode events from the device.
478+
*/
479+
if (hammer_has_folded_event(hdev)) {
480+
hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
481+
error = hid_hw_open(hdev);
482+
if (error)
483+
return error;
484+
}
485+
457486
if (hammer_has_backlight_control(hdev)) {
458487
error = hammer_register_leds(hdev);
459488
if (error)
@@ -465,6 +494,36 @@ static int hammer_probe(struct hid_device *hdev,
465494
return 0;
466495
}
467496

497+
static void hammer_remove(struct hid_device *hdev)
498+
{
499+
unsigned long flags;
500+
501+
if (hammer_has_folded_event(hdev)) {
502+
hid_hw_close(hdev);
503+
504+
/*
505+
* If we are disconnecting then most likely Whiskers is
506+
* being removed. Even if it is not removed, without proper
507+
* keyboard we should not stay in clamshell mode.
508+
*
509+
* The reason for doing it here and not waiting for signal
510+
* from EC, is that on some devices there are high leakage
511+
* on Whiskers pins and we do not detect disconnect reliably,
512+
* resulting in devices being stuck in clamshell mode.
513+
*/
514+
spin_lock_irqsave(&cbas_ec_lock, flags);
515+
if (cbas_ec.input && cbas_ec.base_present) {
516+
input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
517+
input_sync(cbas_ec.input);
518+
}
519+
cbas_ec.base_present = false;
520+
spin_unlock_irqrestore(&cbas_ec_lock, flags);
521+
}
522+
523+
hammer_unregister_leds(hdev);
524+
525+
hid_hw_stop(hdev);
526+
}
468527

469528
static const struct hid_device_id hammer_devices[] = {
470529
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
@@ -487,6 +546,7 @@ static struct hid_driver hammer_driver = {
487546
.name = "hammer",
488547
.id_table = hammer_devices,
489548
.probe = hammer_probe,
549+
.remove = hammer_remove,
490550
.input_mapping = hammer_input_mapping,
491551
.event = hammer_event,
492552
};

0 commit comments

Comments
 (0)