0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/poll.h>
0016 #include <linux/slab.h>
0017 #include <linux/mutex.h>
0018 #include <linux/proc_fs.h>
0019 #include <linux/seq_file.h>
0020 #include <linux/miscdevice.h>
0021 #include <linux/apm_bios.h>
0022 #include <linux/capability.h>
0023 #include <linux/sched.h>
0024 #include <linux/suspend.h>
0025 #include <linux/apm-emulation.h>
0026 #include <linux/freezer.h>
0027 #include <linux/device.h>
0028 #include <linux/kernel.h>
0029 #include <linux/list.h>
0030 #include <linux/init.h>
0031 #include <linux/completion.h>
0032 #include <linux/kthread.h>
0033 #include <linux/delay.h>
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #define APM_MAX_EVENTS 16
0044
0045 struct apm_queue {
0046 unsigned int event_head;
0047 unsigned int event_tail;
0048 apm_event_t events[APM_MAX_EVENTS];
0049 };
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 enum apm_suspend_state {
0091 SUSPEND_NONE,
0092 SUSPEND_PENDING,
0093 SUSPEND_READ,
0094 SUSPEND_ACKED,
0095 SUSPEND_ACKTO,
0096 SUSPEND_WAIT,
0097 SUSPEND_DONE,
0098 };
0099
0100
0101
0102
0103 struct apm_user {
0104 struct list_head list;
0105
0106 unsigned int suser: 1;
0107 unsigned int writer: 1;
0108 unsigned int reader: 1;
0109
0110 int suspend_result;
0111 enum apm_suspend_state suspend_state;
0112
0113 struct apm_queue queue;
0114 };
0115
0116
0117
0118
0119 static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
0120 static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
0121 static int apm_disabled;
0122 static struct task_struct *kapmd_tsk;
0123
0124 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
0125 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
0126
0127
0128
0129
0130 static DECLARE_RWSEM(user_list_lock);
0131 static LIST_HEAD(apm_user_list);
0132
0133
0134
0135
0136
0137
0138 static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
0139 static DEFINE_SPINLOCK(kapmd_queue_lock);
0140 static struct apm_queue kapmd_queue;
0141
0142 static DEFINE_MUTEX(state_lock);
0143
0144 static const char driver_version[] = "1.13";
0145
0146
0147
0148
0149
0150
0151
0152 static void __apm_get_power_status(struct apm_power_info *info)
0153 {
0154 }
0155
0156
0157
0158
0159 void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
0160 EXPORT_SYMBOL(apm_get_power_status);
0161
0162
0163
0164
0165
0166 static inline int queue_empty(struct apm_queue *q)
0167 {
0168 return q->event_head == q->event_tail;
0169 }
0170
0171 static inline apm_event_t queue_get_event(struct apm_queue *q)
0172 {
0173 q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
0174 return q->events[q->event_tail];
0175 }
0176
0177 static void queue_add_event(struct apm_queue *q, apm_event_t event)
0178 {
0179 q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
0180 if (q->event_head == q->event_tail) {
0181 static int notified;
0182
0183 if (notified++ == 0)
0184 printk(KERN_ERR "apm: an event queue overflowed\n");
0185 q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
0186 }
0187 q->events[q->event_head] = event;
0188 }
0189
0190 static void queue_event(apm_event_t event)
0191 {
0192 struct apm_user *as;
0193
0194 down_read(&user_list_lock);
0195 list_for_each_entry(as, &apm_user_list, list) {
0196 if (as->reader)
0197 queue_add_event(&as->queue, event);
0198 }
0199 up_read(&user_list_lock);
0200 wake_up_interruptible(&apm_waitqueue);
0201 }
0202
0203 static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
0204 {
0205 struct apm_user *as = fp->private_data;
0206 apm_event_t event;
0207 int i = count, ret = 0;
0208
0209 if (count < sizeof(apm_event_t))
0210 return -EINVAL;
0211
0212 if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
0213 return -EAGAIN;
0214
0215 wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
0216
0217 while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
0218 event = queue_get_event(&as->queue);
0219
0220 ret = -EFAULT;
0221 if (copy_to_user(buf, &event, sizeof(event)))
0222 break;
0223
0224 mutex_lock(&state_lock);
0225 if (as->suspend_state == SUSPEND_PENDING &&
0226 (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND))
0227 as->suspend_state = SUSPEND_READ;
0228 mutex_unlock(&state_lock);
0229
0230 buf += sizeof(event);
0231 i -= sizeof(event);
0232 }
0233
0234 if (i < count)
0235 ret = count - i;
0236
0237 return ret;
0238 }
0239
0240 static __poll_t apm_poll(struct file *fp, poll_table * wait)
0241 {
0242 struct apm_user *as = fp->private_data;
0243
0244 poll_wait(fp, &apm_waitqueue, wait);
0245 return queue_empty(&as->queue) ? 0 : EPOLLIN | EPOLLRDNORM;
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 static long
0259 apm_ioctl(struct file *filp, u_int cmd, u_long arg)
0260 {
0261 struct apm_user *as = filp->private_data;
0262 int err = -EINVAL;
0263
0264 if (!as->suser || !as->writer)
0265 return -EPERM;
0266
0267 switch (cmd) {
0268 case APM_IOC_SUSPEND:
0269 mutex_lock(&state_lock);
0270
0271 as->suspend_result = -EINTR;
0272
0273 switch (as->suspend_state) {
0274 case SUSPEND_READ:
0275
0276
0277
0278
0279
0280 as->suspend_state = SUSPEND_ACKED;
0281 atomic_dec(&suspend_acks_pending);
0282 mutex_unlock(&state_lock);
0283
0284
0285
0286
0287
0288 wake_up(&apm_suspend_waitqueue);
0289
0290
0291
0292
0293
0294
0295
0296
0297 while (wait_event_freezable(apm_suspend_waitqueue,
0298 as->suspend_state != SUSPEND_ACKED))
0299 msleep(10);
0300 break;
0301 case SUSPEND_ACKTO:
0302 as->suspend_result = -ETIMEDOUT;
0303 mutex_unlock(&state_lock);
0304 break;
0305 default:
0306 as->suspend_state = SUSPEND_WAIT;
0307 mutex_unlock(&state_lock);
0308
0309
0310
0311
0312
0313
0314 as->suspend_result = pm_suspend(PM_SUSPEND_MEM);
0315 }
0316
0317 mutex_lock(&state_lock);
0318 err = as->suspend_result;
0319 as->suspend_state = SUSPEND_NONE;
0320 mutex_unlock(&state_lock);
0321 break;
0322 }
0323
0324 return err;
0325 }
0326
0327 static int apm_release(struct inode * inode, struct file * filp)
0328 {
0329 struct apm_user *as = filp->private_data;
0330
0331 filp->private_data = NULL;
0332
0333 down_write(&user_list_lock);
0334 list_del(&as->list);
0335 up_write(&user_list_lock);
0336
0337
0338
0339
0340
0341 mutex_lock(&state_lock);
0342 if (as->suspend_state == SUSPEND_PENDING ||
0343 as->suspend_state == SUSPEND_READ)
0344 atomic_dec(&suspend_acks_pending);
0345 mutex_unlock(&state_lock);
0346
0347 wake_up(&apm_suspend_waitqueue);
0348
0349 kfree(as);
0350 return 0;
0351 }
0352
0353 static int apm_open(struct inode * inode, struct file * filp)
0354 {
0355 struct apm_user *as;
0356
0357 as = kzalloc(sizeof(*as), GFP_KERNEL);
0358 if (as) {
0359
0360
0361
0362
0363
0364
0365
0366 as->suser = capable(CAP_SYS_ADMIN);
0367 as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
0368 as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
0369
0370 down_write(&user_list_lock);
0371 list_add(&as->list, &apm_user_list);
0372 up_write(&user_list_lock);
0373
0374 filp->private_data = as;
0375 }
0376
0377 return as ? 0 : -ENOMEM;
0378 }
0379
0380 static const struct file_operations apm_bios_fops = {
0381 .owner = THIS_MODULE,
0382 .read = apm_read,
0383 .poll = apm_poll,
0384 .unlocked_ioctl = apm_ioctl,
0385 .open = apm_open,
0386 .release = apm_release,
0387 .llseek = noop_llseek,
0388 };
0389
0390 static struct miscdevice apm_device = {
0391 .minor = APM_MINOR_DEV,
0392 .name = "apm_bios",
0393 .fops = &apm_bios_fops
0394 };
0395
0396
0397 #ifdef CONFIG_PROC_FS
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436 static int proc_apm_show(struct seq_file *m, void *v)
0437 {
0438 struct apm_power_info info;
0439 char *units;
0440
0441 info.ac_line_status = 0xff;
0442 info.battery_status = 0xff;
0443 info.battery_flag = 0xff;
0444 info.battery_life = -1;
0445 info.time = -1;
0446 info.units = -1;
0447
0448 if (apm_get_power_status)
0449 apm_get_power_status(&info);
0450
0451 switch (info.units) {
0452 default: units = "?"; break;
0453 case 0: units = "min"; break;
0454 case 1: units = "sec"; break;
0455 }
0456
0457 seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
0458 driver_version, APM_32_BIT_SUPPORT,
0459 info.ac_line_status, info.battery_status,
0460 info.battery_flag, info.battery_life,
0461 info.time, units);
0462
0463 return 0;
0464 }
0465 #endif
0466
0467 static int kapmd(void *arg)
0468 {
0469 do {
0470 apm_event_t event;
0471
0472 wait_event_interruptible(kapmd_wait,
0473 !queue_empty(&kapmd_queue) || kthread_should_stop());
0474
0475 if (kthread_should_stop())
0476 break;
0477
0478 spin_lock_irq(&kapmd_queue_lock);
0479 event = 0;
0480 if (!queue_empty(&kapmd_queue))
0481 event = queue_get_event(&kapmd_queue);
0482 spin_unlock_irq(&kapmd_queue_lock);
0483
0484 switch (event) {
0485 case 0:
0486 break;
0487
0488 case APM_LOW_BATTERY:
0489 case APM_POWER_STATUS_CHANGE:
0490 queue_event(event);
0491 break;
0492
0493 case APM_USER_SUSPEND:
0494 case APM_SYS_SUSPEND:
0495 pm_suspend(PM_SUSPEND_MEM);
0496 break;
0497
0498 case APM_CRITICAL_SUSPEND:
0499 atomic_inc(&userspace_notification_inhibit);
0500 pm_suspend(PM_SUSPEND_MEM);
0501 atomic_dec(&userspace_notification_inhibit);
0502 break;
0503 }
0504 } while (1);
0505
0506 return 0;
0507 }
0508
0509 static int apm_suspend_notifier(struct notifier_block *nb,
0510 unsigned long event,
0511 void *dummy)
0512 {
0513 struct apm_user *as;
0514 int err;
0515 unsigned long apm_event;
0516
0517
0518 if (atomic_read(&userspace_notification_inhibit))
0519 return NOTIFY_DONE;
0520
0521 switch (event) {
0522 case PM_SUSPEND_PREPARE:
0523 case PM_HIBERNATION_PREPARE:
0524 apm_event = (event == PM_SUSPEND_PREPARE) ?
0525 APM_USER_SUSPEND : APM_USER_HIBERNATION;
0526
0527
0528
0529
0530 mutex_lock(&state_lock);
0531 down_read(&user_list_lock);
0532
0533 list_for_each_entry(as, &apm_user_list, list) {
0534 if (as->suspend_state != SUSPEND_WAIT && as->reader &&
0535 as->writer && as->suser) {
0536 as->suspend_state = SUSPEND_PENDING;
0537 atomic_inc(&suspend_acks_pending);
0538 queue_add_event(&as->queue, apm_event);
0539 }
0540 }
0541
0542 up_read(&user_list_lock);
0543 mutex_unlock(&state_lock);
0544 wake_up_interruptible(&apm_waitqueue);
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554 err = wait_event_interruptible_timeout(
0555 apm_suspend_waitqueue,
0556 atomic_read(&suspend_acks_pending) == 0,
0557 5*HZ);
0558
0559
0560 if (err == 0) {
0561
0562
0563
0564
0565
0566
0567
0568 mutex_lock(&state_lock);
0569 down_read(&user_list_lock);
0570 list_for_each_entry(as, &apm_user_list, list) {
0571 if (as->suspend_state == SUSPEND_PENDING ||
0572 as->suspend_state == SUSPEND_READ) {
0573 as->suspend_state = SUSPEND_ACKTO;
0574 atomic_dec(&suspend_acks_pending);
0575 }
0576 }
0577 up_read(&user_list_lock);
0578 mutex_unlock(&state_lock);
0579 }
0580
0581
0582 if (err >= 0)
0583 return NOTIFY_OK;
0584
0585
0586 return notifier_from_errno(err);
0587
0588 case PM_POST_SUSPEND:
0589 case PM_POST_HIBERNATION:
0590 apm_event = (event == PM_POST_SUSPEND) ?
0591 APM_NORMAL_RESUME : APM_HIBERNATION_RESUME;
0592
0593
0594
0595
0596 queue_event(apm_event);
0597
0598
0599
0600
0601 mutex_lock(&state_lock);
0602 down_read(&user_list_lock);
0603 list_for_each_entry(as, &apm_user_list, list) {
0604 if (as->suspend_state == SUSPEND_ACKED) {
0605
0606
0607
0608
0609
0610
0611 as->suspend_result = 0;
0612 as->suspend_state = SUSPEND_DONE;
0613 }
0614 }
0615 up_read(&user_list_lock);
0616 mutex_unlock(&state_lock);
0617
0618 wake_up(&apm_suspend_waitqueue);
0619 return NOTIFY_OK;
0620
0621 default:
0622 return NOTIFY_DONE;
0623 }
0624 }
0625
0626 static struct notifier_block apm_notif_block = {
0627 .notifier_call = apm_suspend_notifier,
0628 };
0629
0630 static int __init apm_init(void)
0631 {
0632 int ret;
0633
0634 if (apm_disabled) {
0635 printk(KERN_NOTICE "apm: disabled on user request.\n");
0636 return -ENODEV;
0637 }
0638
0639 kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");
0640 if (IS_ERR(kapmd_tsk)) {
0641 ret = PTR_ERR(kapmd_tsk);
0642 kapmd_tsk = NULL;
0643 goto out;
0644 }
0645 wake_up_process(kapmd_tsk);
0646
0647 #ifdef CONFIG_PROC_FS
0648 proc_create_single("apm", 0, NULL, proc_apm_show);
0649 #endif
0650
0651 ret = misc_register(&apm_device);
0652 if (ret)
0653 goto out_stop;
0654
0655 ret = register_pm_notifier(&apm_notif_block);
0656 if (ret)
0657 goto out_unregister;
0658
0659 return 0;
0660
0661 out_unregister:
0662 misc_deregister(&apm_device);
0663 out_stop:
0664 remove_proc_entry("apm", NULL);
0665 kthread_stop(kapmd_tsk);
0666 out:
0667 return ret;
0668 }
0669
0670 static void __exit apm_exit(void)
0671 {
0672 unregister_pm_notifier(&apm_notif_block);
0673 misc_deregister(&apm_device);
0674 remove_proc_entry("apm", NULL);
0675
0676 kthread_stop(kapmd_tsk);
0677 }
0678
0679 module_init(apm_init);
0680 module_exit(apm_exit);
0681
0682 MODULE_AUTHOR("Stephen Rothwell");
0683 MODULE_DESCRIPTION("Advanced Power Management");
0684 MODULE_LICENSE("GPL");
0685
0686 #ifndef MODULE
0687 static int __init apm_setup(char *str)
0688 {
0689 while ((str != NULL) && (*str != '\0')) {
0690 if (strncmp(str, "off", 3) == 0)
0691 apm_disabled = 1;
0692 if (strncmp(str, "on", 2) == 0)
0693 apm_disabled = 0;
0694 str = strchr(str, ',');
0695 if (str != NULL)
0696 str += strspn(str, ", \t");
0697 }
0698 return 1;
0699 }
0700
0701 __setup("apm=", apm_setup);
0702 #endif
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716 void apm_queue_event(apm_event_t event)
0717 {
0718 unsigned long flags;
0719
0720 spin_lock_irqsave(&kapmd_queue_lock, flags);
0721 queue_add_event(&kapmd_queue, event);
0722 spin_unlock_irqrestore(&kapmd_queue_lock, flags);
0723
0724 wake_up_interruptible(&kapmd_wait);
0725 }
0726 EXPORT_SYMBOL(apm_queue_event);