@@ -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,
322330static 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+
434460static 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
469528static 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