aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-01-08 10:02:39 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 22:26:06 -0500
commitb2c985e7eba858a1765db6d56bdd4df775f53633 (patch)
tree938b712a2ae312a1876a04ff830c1411f7eeab4a /drivers/misc/thinkpad_acpi.c
parent0f089147e620e083f58a0e641f701bd4244b455b (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.c184
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;
777static u32 hotkey_orig_mask; 777static u32 hotkey_orig_mask;
778static u32 hotkey_all_mask; 778static u32 hotkey_all_mask;
779static u32 hotkey_reserved_mask; 779static u32 hotkey_reserved_mask;
780static u32 hotkey_mask;
780 781
781static u16 *hotkey_keycode_map; 782static 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 */
796static 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 */
809static 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
839static 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
847static 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 ------------------------------------------------- */
793static ssize_t hotkey_enable_show(struct device *dev, 856static 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
844static ssize_t hotkey_mask_store(struct device *dev, 904static 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
1208static void hotkey_exit(void) 1277static 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
1350static void hotkey_resume(void) 1418static 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 */
1358static 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 */
1373static 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 -------------------------------------------------------------- */
1392static int hotkey_read(char *p) 1426static 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
1463errexit: 1497errexit:
1464 mutex_unlock(&hotkey_mutex); 1498 mutex_unlock(&hotkey_mutex);