diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2008-01-08 10:02:39 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-02-01 22:26:06 -0500 |
commit | b2c985e7eba858a1765db6d56bdd4df775f53633 (patch) | |
tree | 938b712a2ae312a1876a04ff830c1411f7eeab4a /drivers/misc/thinkpad_acpi.c | |
parent | 0f089147e620e083f58a0e641f701bd4244b455b (diff) |
ACPI: thinkpad-acpi: refactor hotkey_get and hotkey_set (v2)
Refactor and organize the code a bit for the NVRAM polling support:
1. Split hotkey_get/set into hotkey_status_get/set and hotkey_mask_get/set;
2. Cache the status of hot key mask for later driver use;
3. Make sure the cache of hot key mask is refreshed when needed;
4. log a printk notice when the firmware doesn't set the hot key
mask to exactly what we asked it to;
5. Add proper locking to the data structures.
Only (4) should be user-noticeable, but there is a chance (5) fixes
some unknown/unreported race conditions.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 184 |
1 files changed, 109 insertions, 75 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 7b1080f5843c..49d4f4af759e 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -777,6 +777,7 @@ static int hotkey_orig_status; | |||
777 | static u32 hotkey_orig_mask; | 777 | static u32 hotkey_orig_mask; |
778 | static u32 hotkey_all_mask; | 778 | static u32 hotkey_all_mask; |
779 | static u32 hotkey_reserved_mask; | 779 | static u32 hotkey_reserved_mask; |
780 | static u32 hotkey_mask; | ||
780 | 781 | ||
781 | static u16 *hotkey_keycode_map; | 782 | static u16 *hotkey_keycode_map; |
782 | 783 | ||
@@ -789,15 +790,76 @@ static int hotkey_get_wlsw(int *status) | |||
789 | return 0; | 790 | return 0; |
790 | } | 791 | } |
791 | 792 | ||
793 | /* | ||
794 | * Call with hotkey_mutex held | ||
795 | */ | ||
796 | static int hotkey_mask_get(void) | ||
797 | { | ||
798 | if (tp_features.hotkey_mask) { | ||
799 | if (!acpi_evalf(hkey_handle, &hotkey_mask, "DHKN", "d")) | ||
800 | return -EIO; | ||
801 | } | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * Call with hotkey_mutex held | ||
808 | */ | ||
809 | static int hotkey_mask_set(u32 mask) | ||
810 | { | ||
811 | int i; | ||
812 | int rc = 0; | ||
813 | |||
814 | if (tp_features.hotkey_mask) { | ||
815 | for (i = 0; i < 32; i++) { | ||
816 | u32 m = 1 << i; | ||
817 | if (!acpi_evalf(hkey_handle, | ||
818 | NULL, "MHKM", "vdd", i + 1, | ||
819 | !!(mask & m))) { | ||
820 | rc = -EIO; | ||
821 | break; | ||
822 | } else { | ||
823 | hotkey_mask = (hotkey_mask & ~m) | (mask & m); | ||
824 | } | ||
825 | } | ||
826 | |||
827 | /* hotkey_mask_get must be called unconditionally below */ | ||
828 | if (!hotkey_mask_get() && !rc && hotkey_mask != mask) { | ||
829 | printk(IBM_NOTICE | ||
830 | "requested hot key mask 0x%08x, but " | ||
831 | "firmware forced it to 0x%08x\n", | ||
832 | mask, hotkey_mask); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | return rc; | ||
837 | } | ||
838 | |||
839 | static int hotkey_status_get(int *status) | ||
840 | { | ||
841 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) | ||
842 | return -EIO; | ||
843 | |||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int hotkey_status_set(int status) | ||
848 | { | ||
849 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) | ||
850 | return -EIO; | ||
851 | |||
852 | return 0; | ||
853 | } | ||
854 | |||
792 | /* sysfs hotkey enable ------------------------------------------------- */ | 855 | /* sysfs hotkey enable ------------------------------------------------- */ |
793 | static ssize_t hotkey_enable_show(struct device *dev, | 856 | static ssize_t hotkey_enable_show(struct device *dev, |
794 | struct device_attribute *attr, | 857 | struct device_attribute *attr, |
795 | char *buf) | 858 | char *buf) |
796 | { | 859 | { |
797 | int res, status; | 860 | int res, status; |
798 | u32 mask; | ||
799 | 861 | ||
800 | res = hotkey_get(&status, &mask); | 862 | res = hotkey_status_get(&status); |
801 | if (res) | 863 | if (res) |
802 | return res; | 864 | return res; |
803 | 865 | ||
@@ -809,15 +871,12 @@ static ssize_t hotkey_enable_store(struct device *dev, | |||
809 | const char *buf, size_t count) | 871 | const char *buf, size_t count) |
810 | { | 872 | { |
811 | unsigned long t; | 873 | unsigned long t; |
812 | int res, status; | 874 | int res; |
813 | u32 mask; | ||
814 | 875 | ||
815 | if (parse_strtoul(buf, 1, &t)) | 876 | if (parse_strtoul(buf, 1, &t)) |
816 | return -EINVAL; | 877 | return -EINVAL; |
817 | 878 | ||
818 | res = hotkey_get(&status, &mask); | 879 | res = hotkey_status_set(t); |
819 | if (!res) | ||
820 | res = hotkey_set(t, mask); | ||
821 | 880 | ||
822 | return (res) ? res : count; | 881 | return (res) ? res : count; |
823 | } | 882 | } |
@@ -831,14 +890,15 @@ static ssize_t hotkey_mask_show(struct device *dev, | |||
831 | struct device_attribute *attr, | 890 | struct device_attribute *attr, |
832 | char *buf) | 891 | char *buf) |
833 | { | 892 | { |
834 | int res, status; | 893 | int res; |
835 | u32 mask; | ||
836 | 894 | ||
837 | res = hotkey_get(&status, &mask); | 895 | if (mutex_lock_interruptible(&hotkey_mutex)) |
838 | if (res) | 896 | return -ERESTARTSYS; |
839 | return res; | 897 | res = hotkey_mask_get(); |
898 | mutex_unlock(&hotkey_mutex); | ||
840 | 899 | ||
841 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); | 900 | return (res)? |
901 | res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); | ||
842 | } | 902 | } |
843 | 903 | ||
844 | static ssize_t hotkey_mask_store(struct device *dev, | 904 | static ssize_t hotkey_mask_store(struct device *dev, |
@@ -846,15 +906,16 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
846 | const char *buf, size_t count) | 906 | const char *buf, size_t count) |
847 | { | 907 | { |
848 | unsigned long t; | 908 | unsigned long t; |
849 | int res, status; | 909 | int res; |
850 | u32 mask; | ||
851 | 910 | ||
852 | if (parse_strtoul(buf, 0xffffffffUL, &t)) | 911 | if (parse_strtoul(buf, 0xffffffffUL, &t)) |
853 | return -EINVAL; | 912 | return -EINVAL; |
854 | 913 | ||
855 | res = hotkey_get(&status, &mask); | 914 | if (mutex_lock_interruptible(&hotkey_mutex)) |
856 | if (!res) | 915 | return -ERESTARTSYS; |
857 | hotkey_set(status, t); | 916 | |
917 | res = hotkey_mask_set(t); | ||
918 | mutex_unlock(&hotkey_mutex); | ||
858 | 919 | ||
859 | return (res) ? res : count; | 920 | return (res) ? res : count; |
860 | } | 921 | } |
@@ -1123,11 +1184,16 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1123 | } | 1184 | } |
1124 | } | 1185 | } |
1125 | 1186 | ||
1126 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); | 1187 | res = hotkey_status_get(&hotkey_orig_status); |
1127 | if (!res && tp_features.hotkey_mask) { | 1188 | if (!res && tp_features.hotkey_mask) { |
1128 | res = add_many_to_attr_set(hotkey_dev_attributes, | 1189 | res = hotkey_mask_get(); |
1129 | hotkey_mask_attributes, | 1190 | hotkey_orig_mask = hotkey_mask; |
1130 | ARRAY_SIZE(hotkey_mask_attributes)); | 1191 | if (!res) { |
1192 | res = add_many_to_attr_set( | ||
1193 | hotkey_dev_attributes, | ||
1194 | hotkey_mask_attributes, | ||
1195 | ARRAY_SIZE(hotkey_mask_attributes)); | ||
1196 | } | ||
1131 | } | 1197 | } |
1132 | 1198 | ||
1133 | /* Not all thinkpads have a hardware radio switch */ | 1199 | /* Not all thinkpads have a hardware radio switch */ |
@@ -1191,7 +1257,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1191 | 1257 | ||
1192 | dbg_printk(TPACPI_DBG_INIT, | 1258 | dbg_printk(TPACPI_DBG_INIT, |
1193 | "enabling hot key handling\n"); | 1259 | "enabling hot key handling\n"); |
1194 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | 1260 | res = hotkey_status_set(1); |
1261 | if (res) | ||
1262 | return res; | ||
1263 | res = hotkey_mask_set((hotkey_all_mask & ~hotkey_reserved_mask) | ||
1195 | | hotkey_orig_mask); | 1264 | | hotkey_orig_mask); |
1196 | if (res) | 1265 | if (res) |
1197 | return res; | 1266 | return res; |
@@ -1207,13 +1276,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1207 | 1276 | ||
1208 | static void hotkey_exit(void) | 1277 | static void hotkey_exit(void) |
1209 | { | 1278 | { |
1210 | int res; | ||
1211 | |||
1212 | if (tp_features.hotkey) { | 1279 | if (tp_features.hotkey) { |
1213 | dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); | 1280 | dbg_printk(TPACPI_DBG_EXIT, "restoring original hot key mask\n"); |
1214 | res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); | 1281 | /* no short-circuit boolean operator below! */ |
1215 | if (res) | 1282 | if ((hotkey_mask_set(hotkey_orig_mask) | |
1216 | printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); | 1283 | hotkey_status_set(hotkey_orig_status)) != 0) |
1284 | printk(IBM_ERR "failed to restore hot key mask to BIOS defaults\n"); | ||
1217 | } | 1285 | } |
1218 | 1286 | ||
1219 | if (hotkey_dev_attributes) { | 1287 | if (hotkey_dev_attributes) { |
@@ -1349,50 +1417,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
1349 | 1417 | ||
1350 | static void hotkey_resume(void) | 1418 | static void hotkey_resume(void) |
1351 | { | 1419 | { |
1420 | if (hotkey_mask_get()) | ||
1421 | printk(IBM_ERR "error while trying to read hot key mask from firmware\n"); | ||
1352 | tpacpi_input_send_radiosw(); | 1422 | tpacpi_input_send_radiosw(); |
1353 | } | 1423 | } |
1354 | 1424 | ||
1355 | /* | ||
1356 | * Call with hotkey_mutex held | ||
1357 | */ | ||
1358 | static int hotkey_get(int *status, u32 *mask) | ||
1359 | { | ||
1360 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) | ||
1361 | return -EIO; | ||
1362 | |||
1363 | if (tp_features.hotkey_mask) | ||
1364 | if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) | ||
1365 | return -EIO; | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | /* | ||
1371 | * Call with hotkey_mutex held | ||
1372 | */ | ||
1373 | static int hotkey_set(int status, u32 mask) | ||
1374 | { | ||
1375 | int i; | ||
1376 | |||
1377 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) | ||
1378 | return -EIO; | ||
1379 | |||
1380 | if (tp_features.hotkey_mask) | ||
1381 | for (i = 0; i < 32; i++) { | ||
1382 | int bit = ((1 << i) & mask) != 0; | ||
1383 | if (!acpi_evalf(hkey_handle, | ||
1384 | NULL, "MHKM", "vdd", i + 1, bit)) | ||
1385 | return -EIO; | ||
1386 | } | ||
1387 | |||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | /* procfs -------------------------------------------------------------- */ | 1425 | /* procfs -------------------------------------------------------------- */ |
1392 | static int hotkey_read(char *p) | 1426 | static int hotkey_read(char *p) |
1393 | { | 1427 | { |
1394 | int res, status; | 1428 | int res, status; |
1395 | u32 mask; | ||
1396 | int len = 0; | 1429 | int len = 0; |
1397 | 1430 | ||
1398 | if (!tp_features.hotkey) { | 1431 | if (!tp_features.hotkey) { |
@@ -1402,14 +1435,16 @@ static int hotkey_read(char *p) | |||
1402 | 1435 | ||
1403 | if (mutex_lock_interruptible(&hotkey_mutex)) | 1436 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1404 | return -ERESTARTSYS; | 1437 | return -ERESTARTSYS; |
1405 | res = hotkey_get(&status, &mask); | 1438 | res = hotkey_status_get(&status); |
1439 | if (!res) | ||
1440 | res = hotkey_mask_get(); | ||
1406 | mutex_unlock(&hotkey_mutex); | 1441 | mutex_unlock(&hotkey_mutex); |
1407 | if (res) | 1442 | if (res) |
1408 | return res; | 1443 | return res; |
1409 | 1444 | ||
1410 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 1445 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); |
1411 | if (tp_features.hotkey_mask) { | 1446 | if (tp_features.hotkey_mask) { |
1412 | len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); | 1447 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); |
1413 | len += sprintf(p + len, | 1448 | len += sprintf(p + len, |
1414 | "commands:\tenable, disable, reset, <mask>\n"); | 1449 | "commands:\tenable, disable, reset, <mask>\n"); |
1415 | } else { | 1450 | } else { |
@@ -1425,7 +1460,6 @@ static int hotkey_write(char *buf) | |||
1425 | int res, status; | 1460 | int res, status; |
1426 | u32 mask; | 1461 | u32 mask; |
1427 | char *cmd; | 1462 | char *cmd; |
1428 | int do_cmd = 0; | ||
1429 | 1463 | ||
1430 | if (!tp_features.hotkey) | 1464 | if (!tp_features.hotkey) |
1431 | return -ENODEV; | 1465 | return -ENODEV; |
@@ -1433,9 +1467,8 @@ static int hotkey_write(char *buf) | |||
1433 | if (mutex_lock_interruptible(&hotkey_mutex)) | 1467 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1434 | return -ERESTARTSYS; | 1468 | return -ERESTARTSYS; |
1435 | 1469 | ||
1436 | res = hotkey_get(&status, &mask); | 1470 | status = -1; |
1437 | if (res) | 1471 | mask = hotkey_mask; |
1438 | goto errexit; | ||
1439 | 1472 | ||
1440 | res = 0; | 1473 | res = 0; |
1441 | while ((cmd = next_cmd(&buf))) { | 1474 | while ((cmd = next_cmd(&buf))) { |
@@ -1454,11 +1487,12 @@ static int hotkey_write(char *buf) | |||
1454 | res = -EINVAL; | 1487 | res = -EINVAL; |
1455 | goto errexit; | 1488 | goto errexit; |
1456 | } | 1489 | } |
1457 | do_cmd = 1; | ||
1458 | } | 1490 | } |
1491 | if (status != -1) | ||
1492 | res = hotkey_status_set(status); | ||
1459 | 1493 | ||
1460 | if (do_cmd) | 1494 | if (!res && mask != hotkey_mask) |
1461 | res = hotkey_set(status, mask); | 1495 | res = hotkey_mask_set(mask); |
1462 | 1496 | ||
1463 | errexit: | 1497 | errexit: |
1464 | mutex_unlock(&hotkey_mutex); | 1498 | mutex_unlock(&hotkey_mutex); |