diff options
Diffstat (limited to 'arch/x86/kernel/apm_32.c')
-rw-r--r-- | arch/x86/kernel/apm_32.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index bf9290e29013..bf9b441331e9 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c | |||
@@ -204,6 +204,7 @@ | |||
204 | #include <linux/module.h> | 204 | #include <linux/module.h> |
205 | 205 | ||
206 | #include <linux/poll.h> | 206 | #include <linux/poll.h> |
207 | #include <linux/smp_lock.h> | ||
207 | #include <linux/types.h> | 208 | #include <linux/types.h> |
208 | #include <linux/stddef.h> | 209 | #include <linux/stddef.h> |
209 | #include <linux/timer.h> | 210 | #include <linux/timer.h> |
@@ -228,6 +229,7 @@ | |||
228 | #include <linux/suspend.h> | 229 | #include <linux/suspend.h> |
229 | #include <linux/kthread.h> | 230 | #include <linux/kthread.h> |
230 | #include <linux/jiffies.h> | 231 | #include <linux/jiffies.h> |
232 | #include <linux/smp_lock.h> | ||
231 | 233 | ||
232 | #include <asm/system.h> | 234 | #include <asm/system.h> |
233 | #include <asm/uaccess.h> | 235 | #include <asm/uaccess.h> |
@@ -1149,7 +1151,7 @@ static void queue_event(apm_event_t event, struct apm_user *sender) | |||
1149 | as->event_tail = 0; | 1151 | as->event_tail = 0; |
1150 | } | 1152 | } |
1151 | as->events[as->event_head] = event; | 1153 | as->events[as->event_head] = event; |
1152 | if ((!as->suser) || (!as->writer)) | 1154 | if (!as->suser || !as->writer) |
1153 | continue; | 1155 | continue; |
1154 | switch (event) { | 1156 | switch (event) { |
1155 | case APM_SYS_SUSPEND: | 1157 | case APM_SYS_SUSPEND: |
@@ -1211,9 +1213,9 @@ static int suspend(int vetoable) | |||
1211 | if (err != APM_SUCCESS) | 1213 | if (err != APM_SUCCESS) |
1212 | apm_error("suspend", err); | 1214 | apm_error("suspend", err); |
1213 | err = (err == APM_SUCCESS) ? 0 : -EIO; | 1215 | err = (err == APM_SUCCESS) ? 0 : -EIO; |
1214 | device_power_up(); | 1216 | device_power_up(PMSG_RESUME); |
1215 | local_irq_enable(); | 1217 | local_irq_enable(); |
1216 | device_resume(); | 1218 | device_resume(PMSG_RESUME); |
1217 | queue_event(APM_NORMAL_RESUME, NULL); | 1219 | queue_event(APM_NORMAL_RESUME, NULL); |
1218 | spin_lock(&user_list_lock); | 1220 | spin_lock(&user_list_lock); |
1219 | for (as = user_list; as != NULL; as = as->next) { | 1221 | for (as = user_list; as != NULL; as = as->next) { |
@@ -1238,7 +1240,7 @@ static void standby(void) | |||
1238 | apm_error("standby", err); | 1240 | apm_error("standby", err); |
1239 | 1241 | ||
1240 | local_irq_disable(); | 1242 | local_irq_disable(); |
1241 | device_power_up(); | 1243 | device_power_up(PMSG_RESUME); |
1242 | local_irq_enable(); | 1244 | local_irq_enable(); |
1243 | } | 1245 | } |
1244 | 1246 | ||
@@ -1324,7 +1326,7 @@ static void check_events(void) | |||
1324 | ignore_bounce = 1; | 1326 | ignore_bounce = 1; |
1325 | if ((event != APM_NORMAL_RESUME) | 1327 | if ((event != APM_NORMAL_RESUME) |
1326 | || (ignore_normal_resume == 0)) { | 1328 | || (ignore_normal_resume == 0)) { |
1327 | device_resume(); | 1329 | device_resume(PMSG_RESUME); |
1328 | queue_event(event, NULL); | 1330 | queue_event(event, NULL); |
1329 | } | 1331 | } |
1330 | ignore_normal_resume = 0; | 1332 | ignore_normal_resume = 0; |
@@ -1396,7 +1398,7 @@ static void apm_mainloop(void) | |||
1396 | 1398 | ||
1397 | static int check_apm_user(struct apm_user *as, const char *func) | 1399 | static int check_apm_user(struct apm_user *as, const char *func) |
1398 | { | 1400 | { |
1399 | if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { | 1401 | if (as == NULL || as->magic != APM_BIOS_MAGIC) { |
1400 | printk(KERN_ERR "apm: %s passed bad filp\n", func); | 1402 | printk(KERN_ERR "apm: %s passed bad filp\n", func); |
1401 | return 1; | 1403 | return 1; |
1402 | } | 1404 | } |
@@ -1459,18 +1461,19 @@ static unsigned int do_poll(struct file *fp, poll_table *wait) | |||
1459 | return 0; | 1461 | return 0; |
1460 | } | 1462 | } |
1461 | 1463 | ||
1462 | static int do_ioctl(struct inode *inode, struct file *filp, | 1464 | static long do_ioctl(struct file *filp, u_int cmd, u_long arg) |
1463 | u_int cmd, u_long arg) | ||
1464 | { | 1465 | { |
1465 | struct apm_user *as; | 1466 | struct apm_user *as; |
1467 | int ret; | ||
1466 | 1468 | ||
1467 | as = filp->private_data; | 1469 | as = filp->private_data; |
1468 | if (check_apm_user(as, "ioctl")) | 1470 | if (check_apm_user(as, "ioctl")) |
1469 | return -EIO; | 1471 | return -EIO; |
1470 | if ((!as->suser) || (!as->writer)) | 1472 | if (!as->suser || !as->writer) |
1471 | return -EPERM; | 1473 | return -EPERM; |
1472 | switch (cmd) { | 1474 | switch (cmd) { |
1473 | case APM_IOC_STANDBY: | 1475 | case APM_IOC_STANDBY: |
1476 | lock_kernel(); | ||
1474 | if (as->standbys_read > 0) { | 1477 | if (as->standbys_read > 0) { |
1475 | as->standbys_read--; | 1478 | as->standbys_read--; |
1476 | as->standbys_pending--; | 1479 | as->standbys_pending--; |
@@ -1479,8 +1482,10 @@ static int do_ioctl(struct inode *inode, struct file *filp, | |||
1479 | queue_event(APM_USER_STANDBY, as); | 1482 | queue_event(APM_USER_STANDBY, as); |
1480 | if (standbys_pending <= 0) | 1483 | if (standbys_pending <= 0) |
1481 | standby(); | 1484 | standby(); |
1485 | unlock_kernel(); | ||
1482 | break; | 1486 | break; |
1483 | case APM_IOC_SUSPEND: | 1487 | case APM_IOC_SUSPEND: |
1488 | lock_kernel(); | ||
1484 | if (as->suspends_read > 0) { | 1489 | if (as->suspends_read > 0) { |
1485 | as->suspends_read--; | 1490 | as->suspends_read--; |
1486 | as->suspends_pending--; | 1491 | as->suspends_pending--; |
@@ -1488,16 +1493,17 @@ static int do_ioctl(struct inode *inode, struct file *filp, | |||
1488 | } else | 1493 | } else |
1489 | queue_event(APM_USER_SUSPEND, as); | 1494 | queue_event(APM_USER_SUSPEND, as); |
1490 | if (suspends_pending <= 0) { | 1495 | if (suspends_pending <= 0) { |
1491 | return suspend(1); | 1496 | ret = suspend(1); |
1492 | } else { | 1497 | } else { |
1493 | as->suspend_wait = 1; | 1498 | as->suspend_wait = 1; |
1494 | wait_event_interruptible(apm_suspend_waitqueue, | 1499 | wait_event_interruptible(apm_suspend_waitqueue, |
1495 | as->suspend_wait == 0); | 1500 | as->suspend_wait == 0); |
1496 | return as->suspend_result; | 1501 | ret = as->suspend_result; |
1497 | } | 1502 | } |
1498 | break; | 1503 | unlock_kernel(); |
1504 | return ret; | ||
1499 | default: | 1505 | default: |
1500 | return -EINVAL; | 1506 | return -ENOTTY; |
1501 | } | 1507 | } |
1502 | return 0; | 1508 | return 0; |
1503 | } | 1509 | } |
@@ -1544,10 +1550,12 @@ static int do_open(struct inode *inode, struct file *filp) | |||
1544 | { | 1550 | { |
1545 | struct apm_user *as; | 1551 | struct apm_user *as; |
1546 | 1552 | ||
1553 | lock_kernel(); | ||
1547 | as = kmalloc(sizeof(*as), GFP_KERNEL); | 1554 | as = kmalloc(sizeof(*as), GFP_KERNEL); |
1548 | if (as == NULL) { | 1555 | if (as == NULL) { |
1549 | printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", | 1556 | printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", |
1550 | sizeof(*as)); | 1557 | sizeof(*as)); |
1558 | unlock_kernel(); | ||
1551 | return -ENOMEM; | 1559 | return -ENOMEM; |
1552 | } | 1560 | } |
1553 | as->magic = APM_BIOS_MAGIC; | 1561 | as->magic = APM_BIOS_MAGIC; |
@@ -1569,6 +1577,7 @@ static int do_open(struct inode *inode, struct file *filp) | |||
1569 | user_list = as; | 1577 | user_list = as; |
1570 | spin_unlock(&user_list_lock); | 1578 | spin_unlock(&user_list_lock); |
1571 | filp->private_data = as; | 1579 | filp->private_data = as; |
1580 | unlock_kernel(); | ||
1572 | return 0; | 1581 | return 0; |
1573 | } | 1582 | } |
1574 | 1583 | ||
@@ -1860,7 +1869,7 @@ static const struct file_operations apm_bios_fops = { | |||
1860 | .owner = THIS_MODULE, | 1869 | .owner = THIS_MODULE, |
1861 | .read = do_read, | 1870 | .read = do_read, |
1862 | .poll = do_poll, | 1871 | .poll = do_poll, |
1863 | .ioctl = do_ioctl, | 1872 | .unlocked_ioctl = do_ioctl, |
1864 | .open = do_open, | 1873 | .open = do_open, |
1865 | .release = do_release, | 1874 | .release = do_release, |
1866 | }; | 1875 | }; |