@@ -98,6 +98,7 @@ struct asus_kbd_leds {
98
98
struct hid_device * hdev ;
99
99
struct work_struct work ;
100
100
unsigned int brightness ;
101
+ spinlock_t lock ;
101
102
bool removed ;
102
103
};
103
104
@@ -490,33 +491,54 @@ static int rog_nkey_led_init(struct hid_device *hdev)
490
491
return ret ;
491
492
}
492
493
494
+ static void asus_schedule_work (struct asus_kbd_leds * led )
495
+ {
496
+ unsigned long flags ;
497
+
498
+ spin_lock_irqsave (& led -> lock , flags );
499
+ if (!led -> removed )
500
+ schedule_work (& led -> work );
501
+ spin_unlock_irqrestore (& led -> lock , flags );
502
+ }
503
+
493
504
static void asus_kbd_backlight_set (struct led_classdev * led_cdev ,
494
505
enum led_brightness brightness )
495
506
{
496
507
struct asus_kbd_leds * led = container_of (led_cdev , struct asus_kbd_leds ,
497
508
cdev );
509
+ unsigned long flags ;
510
+
511
+ spin_lock_irqsave (& led -> lock , flags );
498
512
led -> brightness = brightness ;
499
- schedule_work (& led -> work );
513
+ spin_unlock_irqrestore (& led -> lock , flags );
514
+
515
+ asus_schedule_work (led );
500
516
}
501
517
502
518
static enum led_brightness asus_kbd_backlight_get (struct led_classdev * led_cdev )
503
519
{
504
520
struct asus_kbd_leds * led = container_of (led_cdev , struct asus_kbd_leds ,
505
521
cdev );
522
+ enum led_brightness brightness ;
523
+ unsigned long flags ;
524
+
525
+ spin_lock_irqsave (& led -> lock , flags );
526
+ brightness = led -> brightness ;
527
+ spin_unlock_irqrestore (& led -> lock , flags );
506
528
507
- return led -> brightness ;
529
+ return brightness ;
508
530
}
509
531
510
532
static void asus_kbd_backlight_work (struct work_struct * work )
511
533
{
512
534
struct asus_kbd_leds * led = container_of (work , struct asus_kbd_leds , work );
513
535
u8 buf [] = { FEATURE_KBD_REPORT_ID , 0xba , 0xc5 , 0xc4 , 0x00 };
514
536
int ret ;
537
+ unsigned long flags ;
515
538
516
- if (led -> removed )
517
- return ;
518
-
539
+ spin_lock_irqsave (& led -> lock , flags );
519
540
buf [4 ] = led -> brightness ;
541
+ spin_unlock_irqrestore (& led -> lock , flags );
520
542
521
543
ret = asus_kbd_set_report (led -> hdev , buf , sizeof (buf ));
522
544
if (ret < 0 )
@@ -584,6 +606,7 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
584
606
drvdata -> kbd_backlight -> cdev .brightness_set = asus_kbd_backlight_set ;
585
607
drvdata -> kbd_backlight -> cdev .brightness_get = asus_kbd_backlight_get ;
586
608
INIT_WORK (& drvdata -> kbd_backlight -> work , asus_kbd_backlight_work );
609
+ spin_lock_init (& drvdata -> kbd_backlight -> lock );
587
610
588
611
ret = devm_led_classdev_register (& hdev -> dev , & drvdata -> kbd_backlight -> cdev );
589
612
if (ret < 0 ) {
@@ -1119,9 +1142,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
1119
1142
static void asus_remove (struct hid_device * hdev )
1120
1143
{
1121
1144
struct asus_drvdata * drvdata = hid_get_drvdata (hdev );
1145
+ unsigned long flags ;
1122
1146
1123
1147
if (drvdata -> kbd_backlight ) {
1148
+ spin_lock_irqsave (& drvdata -> kbd_backlight -> lock , flags );
1124
1149
drvdata -> kbd_backlight -> removed = true;
1150
+ spin_unlock_irqrestore (& drvdata -> kbd_backlight -> lock , flags );
1151
+
1125
1152
cancel_work_sync (& drvdata -> kbd_backlight -> work );
1126
1153
}
1127
1154
0 commit comments