@@ -126,6 +126,7 @@ struct ideapad_rfk_priv {
126
126
127
127
struct ideapad_private {
128
128
struct acpi_device * adev ;
129
+ struct mutex vpc_mutex ; /* protects the VPC calls */
129
130
struct rfkill * rfk [IDEAPAD_RFKILL_DEV_NUM ];
130
131
struct ideapad_rfk_priv rfk_priv [IDEAPAD_RFKILL_DEV_NUM ];
131
132
struct platform_device * platform_device ;
@@ -146,6 +147,7 @@ struct ideapad_private {
146
147
bool touchpad_ctrl_via_ec : 1 ;
147
148
bool ctrl_ps2_aux_port : 1 ;
148
149
bool usb_charging : 1 ;
150
+ bool ymc_ec_trigger : 1 ;
149
151
} features ;
150
152
struct {
151
153
bool initialized ;
@@ -194,6 +196,12 @@ MODULE_PARM_DESC(touchpad_ctrl_via_ec,
194
196
"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
195
197
"tell the EC to enable/disable the touchpad. This may not work on all models." );
196
198
199
+ static bool ymc_ec_trigger __read_mostly ;
200
+ module_param (ymc_ec_trigger , bool , 0444 );
201
+ MODULE_PARM_DESC (ymc_ec_trigger ,
202
+ "Enable EC triggering work-around to force emitting tablet mode events. "
203
+ "If you need this please report this to: [email protected] " );
204
+
197
205
/*
198
206
* shared data
199
207
*/
@@ -294,6 +302,8 @@ static int debugfs_status_show(struct seq_file *s, void *data)
294
302
struct ideapad_private * priv = s -> private ;
295
303
unsigned long value ;
296
304
305
+ guard (mutex )(& priv -> vpc_mutex );
306
+
297
307
if (!read_ec_data (priv -> adev -> handle , VPCCMD_R_BL_MAX , & value ))
298
308
seq_printf (s , "Backlight max: %lu\n" , value );
299
309
if (!read_ec_data (priv -> adev -> handle , VPCCMD_R_BL , & value ))
@@ -412,7 +422,8 @@ static ssize_t camera_power_show(struct device *dev,
412
422
unsigned long result ;
413
423
int err ;
414
424
415
- err = read_ec_data (priv -> adev -> handle , VPCCMD_R_CAMERA , & result );
425
+ scoped_guard (mutex , & priv -> vpc_mutex )
426
+ err = read_ec_data (priv -> adev -> handle , VPCCMD_R_CAMERA , & result );
416
427
if (err )
417
428
return err ;
418
429
@@ -431,7 +442,8 @@ static ssize_t camera_power_store(struct device *dev,
431
442
if (err )
432
443
return err ;
433
444
434
- err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_CAMERA , state );
445
+ scoped_guard (mutex , & priv -> vpc_mutex )
446
+ err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_CAMERA , state );
435
447
if (err )
436
448
return err ;
437
449
@@ -484,7 +496,8 @@ static ssize_t fan_mode_show(struct device *dev,
484
496
unsigned long result ;
485
497
int err ;
486
498
487
- err = read_ec_data (priv -> adev -> handle , VPCCMD_R_FAN , & result );
499
+ scoped_guard (mutex , & priv -> vpc_mutex )
500
+ err = read_ec_data (priv -> adev -> handle , VPCCMD_R_FAN , & result );
488
501
if (err )
489
502
return err ;
490
503
@@ -506,7 +519,8 @@ static ssize_t fan_mode_store(struct device *dev,
506
519
if (state > 4 || state == 3 )
507
520
return - EINVAL ;
508
521
509
- err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_FAN , state );
522
+ scoped_guard (mutex , & priv -> vpc_mutex )
523
+ err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_FAN , state );
510
524
if (err )
511
525
return err ;
512
526
@@ -591,7 +605,8 @@ static ssize_t touchpad_show(struct device *dev,
591
605
unsigned long result ;
592
606
int err ;
593
607
594
- err = read_ec_data (priv -> adev -> handle , VPCCMD_R_TOUCHPAD , & result );
608
+ scoped_guard (mutex , & priv -> vpc_mutex )
609
+ err = read_ec_data (priv -> adev -> handle , VPCCMD_R_TOUCHPAD , & result );
595
610
if (err )
596
611
return err ;
597
612
@@ -612,7 +627,8 @@ static ssize_t touchpad_store(struct device *dev,
612
627
if (err )
613
628
return err ;
614
629
615
- err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_TOUCHPAD , state );
630
+ scoped_guard (mutex , & priv -> vpc_mutex )
631
+ err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_TOUCHPAD , state );
616
632
if (err )
617
633
return err ;
618
634
@@ -1005,6 +1021,8 @@ static int ideapad_rfk_set(void *data, bool blocked)
1005
1021
struct ideapad_rfk_priv * priv = data ;
1006
1022
int opcode = ideapad_rfk_data [priv -> dev ].opcode ;
1007
1023
1024
+ guard (mutex )(& priv -> priv -> vpc_mutex );
1025
+
1008
1026
return write_ec_cmd (priv -> priv -> adev -> handle , opcode , !blocked );
1009
1027
}
1010
1028
@@ -1018,6 +1036,8 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv)
1018
1036
int i ;
1019
1037
1020
1038
if (priv -> features .hw_rfkill_switch ) {
1039
+ guard (mutex )(& priv -> vpc_mutex );
1040
+
1021
1041
if (read_ec_data (priv -> adev -> handle , VPCCMD_R_RF , & hw_blocked ))
1022
1042
return ;
1023
1043
hw_blocked = !hw_blocked ;
@@ -1191,8 +1211,9 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
1191
1211
{
1192
1212
unsigned long long_pressed ;
1193
1213
1194
- if (read_ec_data (priv -> adev -> handle , VPCCMD_R_NOVO , & long_pressed ))
1195
- return ;
1214
+ scoped_guard (mutex , & priv -> vpc_mutex )
1215
+ if (read_ec_data (priv -> adev -> handle , VPCCMD_R_NOVO , & long_pressed ))
1216
+ return ;
1196
1217
1197
1218
if (long_pressed )
1198
1219
ideapad_input_report (priv , 17 );
@@ -1204,8 +1225,9 @@ static void ideapad_check_special_buttons(struct ideapad_private *priv)
1204
1225
{
1205
1226
unsigned long bit , value ;
1206
1227
1207
- if (read_ec_data (priv -> adev -> handle , VPCCMD_R_SPECIAL_BUTTONS , & value ))
1208
- return ;
1228
+ scoped_guard (mutex , & priv -> vpc_mutex )
1229
+ if (read_ec_data (priv -> adev -> handle , VPCCMD_R_SPECIAL_BUTTONS , & value ))
1230
+ return ;
1209
1231
1210
1232
for_each_set_bit (bit , & value , 16 ) {
1211
1233
switch (bit ) {
@@ -1238,6 +1260,8 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
1238
1260
unsigned long now ;
1239
1261
int err ;
1240
1262
1263
+ guard (mutex )(& priv -> vpc_mutex );
1264
+
1241
1265
err = read_ec_data (priv -> adev -> handle , VPCCMD_R_BL , & now );
1242
1266
if (err )
1243
1267
return err ;
@@ -1250,6 +1274,8 @@ static int ideapad_backlight_update_status(struct backlight_device *blightdev)
1250
1274
struct ideapad_private * priv = bl_get_data (blightdev );
1251
1275
int err ;
1252
1276
1277
+ guard (mutex )(& priv -> vpc_mutex );
1278
+
1253
1279
err = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_BL ,
1254
1280
blightdev -> props .brightness );
1255
1281
if (err )
@@ -1327,6 +1353,8 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
1327
1353
if (!blightdev )
1328
1354
return ;
1329
1355
1356
+ guard (mutex )(& priv -> vpc_mutex );
1357
+
1330
1358
if (read_ec_data (priv -> adev -> handle , VPCCMD_R_BL_POWER , & power ))
1331
1359
return ;
1332
1360
@@ -1339,7 +1367,8 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
1339
1367
1340
1368
/* if we control brightness via acpi video driver */
1341
1369
if (!priv -> blightdev )
1342
- read_ec_data (priv -> adev -> handle , VPCCMD_R_BL , & now );
1370
+ scoped_guard (mutex , & priv -> vpc_mutex )
1371
+ read_ec_data (priv -> adev -> handle , VPCCMD_R_BL , & now );
1343
1372
else
1344
1373
backlight_force_update (priv -> blightdev , BACKLIGHT_UPDATE_HOTKEY );
1345
1374
}
@@ -1564,7 +1593,8 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
1564
1593
int ret ;
1565
1594
1566
1595
/* Without reading from EC touchpad LED doesn't switch state */
1567
- ret = read_ec_data (priv -> adev -> handle , VPCCMD_R_TOUCHPAD , & value );
1596
+ scoped_guard (mutex , & priv -> vpc_mutex )
1597
+ ret = read_ec_data (priv -> adev -> handle , VPCCMD_R_TOUCHPAD , & value );
1568
1598
if (ret )
1569
1599
return ;
1570
1600
@@ -1592,16 +1622,92 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
1592
1622
priv -> r_touchpad_val = value ;
1593
1623
}
1594
1624
1625
+ static const struct dmi_system_id ymc_ec_trigger_quirk_dmi_table [] = {
1626
+ {
1627
+ /* Lenovo Yoga 7 14ARB7 */
1628
+ .matches = {
1629
+ DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
1630
+ DMI_MATCH (DMI_PRODUCT_NAME , "82QF" ),
1631
+ },
1632
+ },
1633
+ {
1634
+ /* Lenovo Yoga 7 14ACN6 */
1635
+ .matches = {
1636
+ DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
1637
+ DMI_MATCH (DMI_PRODUCT_NAME , "82N7" ),
1638
+ },
1639
+ },
1640
+ { }
1641
+ };
1642
+
1643
+ static void ideapad_laptop_trigger_ec (void )
1644
+ {
1645
+ struct ideapad_private * priv ;
1646
+ int ret ;
1647
+
1648
+ guard (mutex )(& ideapad_shared_mutex );
1649
+
1650
+ priv = ideapad_shared ;
1651
+ if (!priv )
1652
+ return ;
1653
+
1654
+ if (!priv -> features .ymc_ec_trigger )
1655
+ return ;
1656
+
1657
+ scoped_guard (mutex , & priv -> vpc_mutex )
1658
+ ret = write_ec_cmd (priv -> adev -> handle , VPCCMD_W_YMC , 1 );
1659
+ if (ret )
1660
+ dev_warn (& priv -> platform_device -> dev , "Could not write YMC: %d\n" , ret );
1661
+ }
1662
+
1663
+ static int ideapad_laptop_nb_notify (struct notifier_block * nb ,
1664
+ unsigned long action , void * data )
1665
+ {
1666
+ switch (action ) {
1667
+ case IDEAPAD_LAPTOP_YMC_EVENT :
1668
+ ideapad_laptop_trigger_ec ();
1669
+ break ;
1670
+ }
1671
+
1672
+ return 0 ;
1673
+ }
1674
+
1675
+ static struct notifier_block ideapad_laptop_notifier = {
1676
+ .notifier_call = ideapad_laptop_nb_notify ,
1677
+ };
1678
+
1679
+ static BLOCKING_NOTIFIER_HEAD (ideapad_laptop_chain_head );
1680
+
1681
+ int ideapad_laptop_register_notifier (struct notifier_block * nb )
1682
+ {
1683
+ return blocking_notifier_chain_register (& ideapad_laptop_chain_head , nb );
1684
+ }
1685
+ EXPORT_SYMBOL_NS_GPL (ideapad_laptop_register_notifier , IDEAPAD_LAPTOP );
1686
+
1687
+ int ideapad_laptop_unregister_notifier (struct notifier_block * nb )
1688
+ {
1689
+ return blocking_notifier_chain_unregister (& ideapad_laptop_chain_head , nb );
1690
+ }
1691
+ EXPORT_SYMBOL_NS_GPL (ideapad_laptop_unregister_notifier , IDEAPAD_LAPTOP );
1692
+
1693
+ void ideapad_laptop_call_notifier (unsigned long action , void * data )
1694
+ {
1695
+ blocking_notifier_call_chain (& ideapad_laptop_chain_head , action , data );
1696
+ }
1697
+ EXPORT_SYMBOL_NS_GPL (ideapad_laptop_call_notifier , IDEAPAD_LAPTOP );
1698
+
1595
1699
static void ideapad_acpi_notify (acpi_handle handle , u32 event , void * data )
1596
1700
{
1597
1701
struct ideapad_private * priv = data ;
1598
1702
unsigned long vpc1 , vpc2 , bit ;
1599
1703
1600
- if (read_ec_data (handle , VPCCMD_R_VPC1 , & vpc1 ))
1601
- return ;
1704
+ scoped_guard (mutex , & priv -> vpc_mutex ) {
1705
+ if (read_ec_data (handle , VPCCMD_R_VPC1 , & vpc1 ))
1706
+ return ;
1602
1707
1603
- if (read_ec_data (handle , VPCCMD_R_VPC2 , & vpc2 ))
1604
- return ;
1708
+ if (read_ec_data (handle , VPCCMD_R_VPC2 , & vpc2 ))
1709
+ return ;
1710
+ }
1605
1711
1606
1712
vpc1 = (vpc2 << 8 ) | vpc1 ;
1607
1713
@@ -1728,6 +1834,8 @@ static void ideapad_check_features(struct ideapad_private *priv)
1728
1834
priv -> features .ctrl_ps2_aux_port =
1729
1835
ctrl_ps2_aux_port || dmi_check_system (ctrl_ps2_aux_port_list );
1730
1836
priv -> features .touchpad_ctrl_via_ec = touchpad_ctrl_via_ec ;
1837
+ priv -> features .ymc_ec_trigger =
1838
+ ymc_ec_trigger || dmi_check_system (ymc_ec_trigger_quirk_dmi_table );
1731
1839
1732
1840
if (!read_ec_data (handle , VPCCMD_R_FAN , & val ))
1733
1841
priv -> features .fan_mode = true;
@@ -1906,6 +2014,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
1906
2014
priv -> adev = adev ;
1907
2015
priv -> platform_device = pdev ;
1908
2016
2017
+ err = devm_mutex_init (& pdev -> dev , & priv -> vpc_mutex );
2018
+ if (err )
2019
+ return err ;
2020
+
1909
2021
ideapad_check_features (priv );
1910
2022
1911
2023
err = ideapad_sysfs_init (priv );
@@ -1974,6 +2086,8 @@ static int ideapad_acpi_add(struct platform_device *pdev)
1974
2086
if (err )
1975
2087
goto shared_init_failed ;
1976
2088
2089
+ ideapad_laptop_register_notifier (& ideapad_laptop_notifier );
2090
+
1977
2091
return 0 ;
1978
2092
1979
2093
shared_init_failed :
@@ -2006,6 +2120,8 @@ static void ideapad_acpi_remove(struct platform_device *pdev)
2006
2120
struct ideapad_private * priv = dev_get_drvdata (& pdev -> dev );
2007
2121
int i ;
2008
2122
2123
+ ideapad_laptop_unregister_notifier (& ideapad_laptop_notifier );
2124
+
2009
2125
ideapad_shared_exit (priv );
2010
2126
2011
2127
acpi_remove_notify_handler (priv -> adev -> handle ,
0 commit comments