@@ -35,6 +35,7 @@ struct cbas_ec {
35
35
struct device * dev ; /* The platform device (EC) */
36
36
struct input_dev * input ;
37
37
bool base_present ;
38
+ bool base_folded ;
38
39
struct notifier_block notifier ;
39
40
};
40
41
@@ -208,7 +209,14 @@ static int __cbas_ec_probe(struct platform_device *pdev)
208
209
return error ;
209
210
}
210
211
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 );
212
220
213
221
cbas_ec_set_input (input );
214
222
@@ -322,10 +330,9 @@ static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev,
322
330
static int hammer_register_leds (struct hid_device * hdev )
323
331
{
324
332
struct hammer_kbd_leds * kbd_backlight ;
333
+ int error ;
325
334
326
- kbd_backlight = devm_kzalloc (& hdev -> dev ,
327
- sizeof (* kbd_backlight ),
328
- GFP_KERNEL );
335
+ kbd_backlight = kzalloc (sizeof (* kbd_backlight ), GFP_KERNEL );
329
336
if (!kbd_backlight )
330
337
return - ENOMEM ;
331
338
@@ -339,12 +346,31 @@ static int hammer_register_leds(struct hid_device *hdev)
339
346
/* Set backlight to 0% initially. */
340
347
hammer_kbd_brightness_set_blocking (& kbd_backlight -> cdev , 0 );
341
348
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
+ }
343
369
}
344
370
345
371
#define HID_UP_GOOGLEVENDOR 0xffd10000
346
372
#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)
348
374
349
375
/* HID usage for keyboard backlight (Alphanumeric display brightness) */
350
376
#define HID_AD_BRIGHTNESS 0x00140046
@@ -354,8 +380,7 @@ static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi,
354
380
struct hid_usage * usage ,
355
381
unsigned long * * bit , int * max )
356
382
{
357
- if (hdev -> product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
358
- usage -> hid == WHISKERS_KBD_FOLDED ) {
383
+ if (usage -> hid == HID_USAGE_KBD_FOLDED ) {
359
384
/*
360
385
* We do not want to have this usage mapped as it will get
361
386
* 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
397
{
373
398
unsigned long flags ;
374
399
375
- if (hid -> product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
376
- usage -> hid == WHISKERS_KBD_FOLDED ) {
400
+ if (usage -> hid == HID_USAGE_KBD_FOLDED ) {
377
401
spin_lock_irqsave (& cbas_ec_lock , flags );
378
402
379
- hid_dbg (hid , "%s: base: %d, folded: %d\n" , __func__ ,
380
- cbas_ec .base_present , value );
381
-
382
403
/*
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.
386
406
*/
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 ) {
388
413
input_report_switch (cbas_ec .input ,
389
414
SW_TABLET_MODE , value );
390
415
input_sync (cbas_ec .input );
@@ -397,55 +422,46 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
397
422
return 0 ;
398
423
}
399
424
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 )
401
427
{
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 ];
415
429
struct hid_report * report ;
416
430
int i , j ;
417
431
418
432
list_for_each_entry (report , & re -> report_list , list ) {
419
- if (report -> application != HID_GD_KEYBOARD )
433
+ if (report -> application != application )
420
434
continue ;
421
435
422
436
for (i = 0 ; i < report -> maxfield ; i ++ ) {
423
437
struct hid_field * field = report -> field [i ];
424
438
425
439
for (j = 0 ; j < field -> maxusage ; j ++ )
426
- if (field -> usage [j ].hid == HID_AD_BRIGHTNESS )
440
+ if (field -> usage [j ].hid == usage )
427
441
return true;
428
442
}
429
443
}
430
444
431
445
return false;
432
446
}
433
447
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
+
434
460
static int hammer_probe (struct hid_device * hdev ,
435
461
const struct hid_device_id * id )
436
462
{
437
463
int error ;
438
464
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
-
449
465
error = hid_parse (hdev );
450
466
if (error )
451
467
return error ;
@@ -454,6 +470,19 @@ static int hammer_probe(struct hid_device *hdev,
454
470
if (error )
455
471
return error ;
456
472
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
+
457
486
if (hammer_has_backlight_control (hdev )) {
458
487
error = hammer_register_leds (hdev );
459
488
if (error )
@@ -465,6 +494,36 @@ static int hammer_probe(struct hid_device *hdev,
465
494
return 0 ;
466
495
}
467
496
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
+ }
468
527
469
528
static const struct hid_device_id hammer_devices [] = {
470
529
{ HID_DEVICE (BUS_USB , HID_GROUP_GENERIC ,
@@ -487,6 +546,7 @@ static struct hid_driver hammer_driver = {
487
546
.name = "hammer" ,
488
547
.id_table = hammer_devices ,
489
548
.probe = hammer_probe ,
549
+ .remove = hammer_remove ,
490
550
.input_mapping = hammer_input_mapping ,
491
551
.event = hammer_event ,
492
552
};
0 commit comments