Skip to content

Commit 38e57f0

Browse files
dtorJiri Kosina
authored andcommitted
HID: google: whiskers: more robust tablet mode detection
The USB interface may get detected before the platform/EC one, so let's note the state of the base (if we receive event) and use it to correctly initialize the tablet mode switch state. Also let's start the HID interface immediately when probing, this will ensure that we correctly process "base folded" events that may be sent as we initialize the base. Note that this requires us to add a remove() function where we stop and close the hardware and switch the LED registration away from devm interface as we need to make sure that we destroy the LED instance before we stop the hardware. Signed-off-by: Dmitry Torokhov <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 1ad0bc7 commit 38e57f0

File tree

1 file changed

+56
-15
lines changed

1 file changed

+56
-15
lines changed

drivers/hid/hid-google-hammer.c

Lines changed: 56 additions & 15 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,7 +346,26 @@ 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
@@ -376,8 +402,9 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
376402
usage->hid == WHISKERS_KBD_FOLDED) {
377403
spin_lock_irqsave(&cbas_ec_lock, flags);
378404

405+
cbas_ec.base_folded = value;
379406
hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
380-
cbas_ec.base_present, value);
407+
cbas_ec.base_present, cbas_ec.base_folded);
381408

382409
/*
383410
* We should not get event if base is detached, but in case
@@ -436,23 +463,27 @@ static int hammer_probe(struct hid_device *hdev,
436463
{
437464
int error;
438465

466+
error = hid_parse(hdev);
467+
if (error)
468+
return error;
469+
470+
error = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
471+
if (error)
472+
return error;
473+
439474
/*
440475
* We always want to poll for, and handle tablet mode events from
441476
* Whiskers, even when nobody has opened the input device. This also
442477
* prevents the hid core from dropping early tablet mode events from
443478
* the device.
444479
*/
445480
if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
446-
hammer_is_keyboard_interface(hdev))
481+
hammer_is_keyboard_interface(hdev)) {
447482
hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
448-
449-
error = hid_parse(hdev);
450-
if (error)
451-
return error;
452-
453-
error = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
454-
if (error)
455-
return error;
483+
error = hid_hw_open(hdev);
484+
if (error)
485+
return error;
486+
}
456487

457488
if (hammer_has_backlight_control(hdev)) {
458489
error = hammer_register_leds(hdev);
@@ -465,6 +496,15 @@ static int hammer_probe(struct hid_device *hdev,
465496
return 0;
466497
}
467498

499+
static void hammer_remove(struct hid_device *hdev)
500+
{
501+
if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
502+
hammer_is_keyboard_interface(hdev))
503+
hid_hw_close(hdev);
504+
505+
hammer_unregister_leds(hdev);
506+
hid_hw_stop(hdev);
507+
}
468508

469509
static const struct hid_device_id hammer_devices[] = {
470510
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
@@ -483,6 +523,7 @@ static struct hid_driver hammer_driver = {
483523
.name = "hammer",
484524
.id_table = hammer_devices,
485525
.probe = hammer_probe,
526+
.remove = hammer_remove,
486527
.input_mapping = hammer_input_mapping,
487528
.event = hammer_event,
488529
};

0 commit comments

Comments
 (0)