~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/char/apm-emulation.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * bios-less APM driver for ARM Linux
 
3
 *  Jamey Hicks <jamey@crl.dec.com>
 
4
 *  adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
 
5
 *
 
6
 * APM 1.2 Reference:
 
7
 *   Intel Corporation, Microsoft Corporation. Advanced Power Management
 
8
 *   (APM) BIOS Interface Specification, Revision 1.2, February 1996.
 
9
 *
 
10
 * This document is available from Microsoft at:
 
11
 *    http://www.microsoft.com/whdc/archive/amp_12.mspx
 
12
 */
 
13
#include <linux/module.h>
 
14
#include <linux/poll.h>
 
15
#include <linux/slab.h>
 
16
#include <linux/mutex.h>
 
17
#include <linux/proc_fs.h>
 
18
#include <linux/seq_file.h>
 
19
#include <linux/miscdevice.h>
 
20
#include <linux/apm_bios.h>
 
21
#include <linux/capability.h>
 
22
#include <linux/sched.h>
 
23
#include <linux/suspend.h>
 
24
#include <linux/apm-emulation.h>
 
25
#include <linux/freezer.h>
 
26
#include <linux/device.h>
 
27
#include <linux/kernel.h>
 
28
#include <linux/list.h>
 
29
#include <linux/init.h>
 
30
#include <linux/completion.h>
 
31
#include <linux/kthread.h>
 
32
#include <linux/delay.h>
 
33
 
 
34
#include <asm/system.h>
 
35
 
 
36
/*
 
37
 * The apm_bios device is one of the misc char devices.
 
38
 * This is its minor number.
 
39
 */
 
40
#define APM_MINOR_DEV   134
 
41
 
 
42
/*
 
43
 * One option can be changed at boot time as follows:
 
44
 *      apm=on/off                      enable/disable APM
 
45
 */
 
46
 
 
47
/*
 
48
 * Maximum number of events stored
 
49
 */
 
50
#define APM_MAX_EVENTS          16
 
51
 
 
52
struct apm_queue {
 
53
        unsigned int            event_head;
 
54
        unsigned int            event_tail;
 
55
        apm_event_t             events[APM_MAX_EVENTS];
 
56
};
 
57
 
 
58
/*
 
59
 * thread states (for threads using a writable /dev/apm_bios fd):
 
60
 *
 
61
 * SUSPEND_NONE:        nothing happening
 
62
 * SUSPEND_PENDING:     suspend event queued for thread and pending to be read
 
63
 * SUSPEND_READ:        suspend event read, pending acknowledgement
 
64
 * SUSPEND_ACKED:       acknowledgement received from thread (via ioctl),
 
65
 *                      waiting for resume
 
66
 * SUSPEND_ACKTO:       acknowledgement timeout
 
67
 * SUSPEND_DONE:        thread had acked suspend and is now notified of
 
68
 *                      resume
 
69
 *
 
70
 * SUSPEND_WAIT:        this thread invoked suspend and is waiting for resume
 
71
 *
 
72
 * A thread migrates in one of three paths:
 
73
 *      NONE -1-> PENDING -2-> READ -3-> ACKED -4-> DONE -5-> NONE
 
74
 *                                  -6-> ACKTO -7-> NONE
 
75
 *      NONE -8-> WAIT -9-> NONE
 
76
 *
 
77
 * While in PENDING or READ, the thread is accounted for in the
 
78
 * suspend_acks_pending counter.
 
79
 *
 
80
 * The transitions are invoked as follows:
 
81
 *      1: suspend event is signalled from the core PM code
 
82
 *      2: the suspend event is read from the fd by the userspace thread
 
83
 *      3: userspace thread issues the APM_IOC_SUSPEND ioctl (as ack)
 
84
 *      4: core PM code signals that we have resumed
 
85
 *      5: APM_IOC_SUSPEND ioctl returns
 
86
 *
 
87
 *      6: the notifier invoked from the core PM code timed out waiting
 
88
 *         for all relevant threds to enter ACKED state and puts those
 
89
 *         that haven't into ACKTO
 
90
 *      7: those threads issue APM_IOC_SUSPEND ioctl too late,
 
91
 *         get an error
 
92
 *
 
93
 *      8: userspace thread issues the APM_IOC_SUSPEND ioctl (to suspend),
 
94
 *         ioctl code invokes pm_suspend()
 
95
 *      9: pm_suspend() returns indicating resume
 
96
 */
 
97
enum apm_suspend_state {
 
98
        SUSPEND_NONE,
 
99
        SUSPEND_PENDING,
 
100
        SUSPEND_READ,
 
101
        SUSPEND_ACKED,
 
102
        SUSPEND_ACKTO,
 
103
        SUSPEND_WAIT,
 
104
        SUSPEND_DONE,
 
105
};
 
106
 
 
107
/*
 
108
 * The per-file APM data
 
109
 */
 
110
struct apm_user {
 
111
        struct list_head        list;
 
112
 
 
113
        unsigned int            suser: 1;
 
114
        unsigned int            writer: 1;
 
115
        unsigned int            reader: 1;
 
116
 
 
117
        int                     suspend_result;
 
118
        enum apm_suspend_state  suspend_state;
 
119
 
 
120
        struct apm_queue        queue;
 
121
};
 
122
 
 
123
/*
 
124
 * Local variables
 
125
 */
 
126
static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
 
127
static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
 
128
static int apm_disabled;
 
129
static struct task_struct *kapmd_tsk;
 
130
 
 
131
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 
132
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 
133
 
 
134
/*
 
135
 * This is a list of everyone who has opened /dev/apm_bios
 
136
 */
 
137
static DECLARE_RWSEM(user_list_lock);
 
138
static LIST_HEAD(apm_user_list);
 
139
 
 
140
/*
 
141
 * kapmd info.  kapmd provides us a process context to handle
 
142
 * "APM" events within - specifically necessary if we're going
 
143
 * to be suspending the system.
 
144
 */
 
145
static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
 
146
static DEFINE_SPINLOCK(kapmd_queue_lock);
 
147
static struct apm_queue kapmd_queue;
 
148
 
 
149
static DEFINE_MUTEX(state_lock);
 
150
 
 
151
static const char driver_version[] = "1.13";    /* no spaces */
 
152
 
 
153
 
 
154
 
 
155
/*
 
156
 * Compatibility cruft until the IPAQ people move over to the new
 
157
 * interface.
 
158
 */
 
159
static void __apm_get_power_status(struct apm_power_info *info)
 
160
{
 
161
}
 
162
 
 
163
/*
 
164
 * This allows machines to provide their own "apm get power status" function.
 
165
 */
 
166
void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
 
167
EXPORT_SYMBOL(apm_get_power_status);
 
168
 
 
169
 
 
170
/*
 
171
 * APM event queue management.
 
172
 */
 
173
static inline int queue_empty(struct apm_queue *q)
 
174
{
 
175
        return q->event_head == q->event_tail;
 
176
}
 
177
 
 
178
static inline apm_event_t queue_get_event(struct apm_queue *q)
 
179
{
 
180
        q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
 
181
        return q->events[q->event_tail];
 
182
}
 
183
 
 
184
static void queue_add_event(struct apm_queue *q, apm_event_t event)
 
185
{
 
186
        q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
 
187
        if (q->event_head == q->event_tail) {
 
188
                static int notified;
 
189
 
 
190
                if (notified++ == 0)
 
191
                    printk(KERN_ERR "apm: an event queue overflowed\n");
 
192
                q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
 
193
        }
 
194
        q->events[q->event_head] = event;
 
195
}
 
196
 
 
197
static void queue_event(apm_event_t event)
 
198
{
 
199
        struct apm_user *as;
 
200
 
 
201
        down_read(&user_list_lock);
 
202
        list_for_each_entry(as, &apm_user_list, list) {
 
203
                if (as->reader)
 
204
                        queue_add_event(&as->queue, event);
 
205
        }
 
206
        up_read(&user_list_lock);
 
207
        wake_up_interruptible(&apm_waitqueue);
 
208
}
 
209
 
 
210
static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
 
211
{
 
212
        struct apm_user *as = fp->private_data;
 
213
        apm_event_t event;
 
214
        int i = count, ret = 0;
 
215
 
 
216
        if (count < sizeof(apm_event_t))
 
217
                return -EINVAL;
 
218
 
 
219
        if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
 
220
                return -EAGAIN;
 
221
 
 
222
        wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
 
223
 
 
224
        while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
 
225
                event = queue_get_event(&as->queue);
 
226
 
 
227
                ret = -EFAULT;
 
228
                if (copy_to_user(buf, &event, sizeof(event)))
 
229
                        break;
 
230
 
 
231
                mutex_lock(&state_lock);
 
232
                if (as->suspend_state == SUSPEND_PENDING &&
 
233
                    (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND))
 
234
                        as->suspend_state = SUSPEND_READ;
 
235
                mutex_unlock(&state_lock);
 
236
 
 
237
                buf += sizeof(event);
 
238
                i -= sizeof(event);
 
239
        }
 
240
 
 
241
        if (i < count)
 
242
                ret = count - i;
 
243
 
 
244
        return ret;
 
245
}
 
246
 
 
247
static unsigned int apm_poll(struct file *fp, poll_table * wait)
 
248
{
 
249
        struct apm_user *as = fp->private_data;
 
250
 
 
251
        poll_wait(fp, &apm_waitqueue, wait);
 
252
        return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
 
253
}
 
254
 
 
255
/*
 
256
 * apm_ioctl - handle APM ioctl
 
257
 *
 
258
 * APM_IOC_SUSPEND
 
259
 *   This IOCTL is overloaded, and performs two functions.  It is used to:
 
260
 *     - initiate a suspend
 
261
 *     - acknowledge a suspend read from /dev/apm_bios.
 
262
 *   Only when everyone who has opened /dev/apm_bios with write permission
 
263
 *   has acknowledge does the actual suspend happen.
 
264
 */
 
265
static long
 
266
apm_ioctl(struct file *filp, u_int cmd, u_long arg)
 
267
{
 
268
        struct apm_user *as = filp->private_data;
 
269
        int err = -EINVAL;
 
270
 
 
271
        if (!as->suser || !as->writer)
 
272
                return -EPERM;
 
273
 
 
274
        switch (cmd) {
 
275
        case APM_IOC_SUSPEND:
 
276
                mutex_lock(&state_lock);
 
277
 
 
278
                as->suspend_result = -EINTR;
 
279
 
 
280
                switch (as->suspend_state) {
 
281
                case SUSPEND_READ:
 
282
                        /*
 
283
                         * If we read a suspend command from /dev/apm_bios,
 
284
                         * then the corresponding APM_IOC_SUSPEND ioctl is
 
285
                         * interpreted as an acknowledge.
 
286
                         */
 
287
                        as->suspend_state = SUSPEND_ACKED;
 
288
                        atomic_dec(&suspend_acks_pending);
 
289
                        mutex_unlock(&state_lock);
 
290
 
 
291
                        /*
 
292
                         * suspend_acks_pending changed, the notifier needs to
 
293
                         * be woken up for this
 
294
                         */
 
295
                        wake_up(&apm_suspend_waitqueue);
 
296
 
 
297
                        /*
 
298
                         * Wait for the suspend/resume to complete.  If there
 
299
                         * are pending acknowledges, we wait here for them.
 
300
                         * wait_event_freezable() is interruptible and pending
 
301
                         * signal can cause busy looping.  We aren't doing
 
302
                         * anything critical, chill a bit on each iteration.
 
303
                         */
 
304
                        while (wait_event_freezable(apm_suspend_waitqueue,
 
305
                                        as->suspend_state == SUSPEND_DONE))
 
306
                                msleep(10);
 
307
                        break;
 
308
                case SUSPEND_ACKTO:
 
309
                        as->suspend_result = -ETIMEDOUT;
 
310
                        mutex_unlock(&state_lock);
 
311
                        break;
 
312
                default:
 
313
                        as->suspend_state = SUSPEND_WAIT;
 
314
                        mutex_unlock(&state_lock);
 
315
 
 
316
                        /*
 
317
                         * Otherwise it is a request to suspend the system.
 
318
                         * Just invoke pm_suspend(), we'll handle it from
 
319
                         * there via the notifier.
 
320
                         */
 
321
                        as->suspend_result = pm_suspend(PM_SUSPEND_MEM);
 
322
                }
 
323
 
 
324
                mutex_lock(&state_lock);
 
325
                err = as->suspend_result;
 
326
                as->suspend_state = SUSPEND_NONE;
 
327
                mutex_unlock(&state_lock);
 
328
                break;
 
329
        }
 
330
 
 
331
        return err;
 
332
}
 
333
 
 
334
static int apm_release(struct inode * inode, struct file * filp)
 
335
{
 
336
        struct apm_user *as = filp->private_data;
 
337
 
 
338
        filp->private_data = NULL;
 
339
 
 
340
        down_write(&user_list_lock);
 
341
        list_del(&as->list);
 
342
        up_write(&user_list_lock);
 
343
 
 
344
        /*
 
345
         * We are now unhooked from the chain.  As far as new
 
346
         * events are concerned, we no longer exist.
 
347
         */
 
348
        mutex_lock(&state_lock);
 
349
        if (as->suspend_state == SUSPEND_PENDING ||
 
350
            as->suspend_state == SUSPEND_READ)
 
351
                atomic_dec(&suspend_acks_pending);
 
352
        mutex_unlock(&state_lock);
 
353
 
 
354
        wake_up(&apm_suspend_waitqueue);
 
355
 
 
356
        kfree(as);
 
357
        return 0;
 
358
}
 
359
 
 
360
static int apm_open(struct inode * inode, struct file * filp)
 
361
{
 
362
        struct apm_user *as;
 
363
 
 
364
        as = kzalloc(sizeof(*as), GFP_KERNEL);
 
365
        if (as) {
 
366
                /*
 
367
                 * XXX - this is a tiny bit broken, when we consider BSD
 
368
                 * process accounting. If the device is opened by root, we
 
369
                 * instantly flag that we used superuser privs. Who knows,
 
370
                 * we might close the device immediately without doing a
 
371
                 * privileged operation -- cevans
 
372
                 */
 
373
                as->suser = capable(CAP_SYS_ADMIN);
 
374
                as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
 
375
                as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
 
376
 
 
377
                down_write(&user_list_lock);
 
378
                list_add(&as->list, &apm_user_list);
 
379
                up_write(&user_list_lock);
 
380
 
 
381
                filp->private_data = as;
 
382
        }
 
383
 
 
384
        return as ? 0 : -ENOMEM;
 
385
}
 
386
 
 
387
static const struct file_operations apm_bios_fops = {
 
388
        .owner          = THIS_MODULE,
 
389
        .read           = apm_read,
 
390
        .poll           = apm_poll,
 
391
        .unlocked_ioctl = apm_ioctl,
 
392
        .open           = apm_open,
 
393
        .release        = apm_release,
 
394
        .llseek         = noop_llseek,
 
395
};
 
396
 
 
397
static struct miscdevice apm_device = {
 
398
        .minor          = APM_MINOR_DEV,
 
399
        .name           = "apm_bios",
 
400
        .fops           = &apm_bios_fops
 
401
};
 
402
 
 
403
 
 
404
#ifdef CONFIG_PROC_FS
 
405
/*
 
406
 * Arguments, with symbols from linux/apm_bios.h.
 
407
 *
 
408
 *   0) Linux driver version (this will change if format changes)
 
409
 *   1) APM BIOS Version.  Usually 1.0, 1.1 or 1.2.
 
410
 *   2) APM flags from APM Installation Check (0x00):
 
411
 *      bit 0: APM_16_BIT_SUPPORT
 
412
 *      bit 1: APM_32_BIT_SUPPORT
 
413
 *      bit 2: APM_IDLE_SLOWS_CLOCK
 
414
 *      bit 3: APM_BIOS_DISABLED
 
415
 *      bit 4: APM_BIOS_DISENGAGED
 
416
 *   3) AC line status
 
417
 *      0x00: Off-line
 
418
 *      0x01: On-line
 
419
 *      0x02: On backup power (BIOS >= 1.1 only)
 
420
 *      0xff: Unknown
 
421
 *   4) Battery status
 
422
 *      0x00: High
 
423
 *      0x01: Low
 
424
 *      0x02: Critical
 
425
 *      0x03: Charging
 
426
 *      0x04: Selected battery not present (BIOS >= 1.2 only)
 
427
 *      0xff: Unknown
 
428
 *   5) Battery flag
 
429
 *      bit 0: High
 
430
 *      bit 1: Low
 
431
 *      bit 2: Critical
 
432
 *      bit 3: Charging
 
433
 *      bit 7: No system battery
 
434
 *      0xff: Unknown
 
435
 *   6) Remaining battery life (percentage of charge):
 
436
 *      0-100: valid
 
437
 *      -1: Unknown
 
438
 *   7) Remaining battery life (time units):
 
439
 *      Number of remaining minutes or seconds
 
440
 *      -1: Unknown
 
441
 *   8) min = minutes; sec = seconds
 
442
 */
 
443
static int proc_apm_show(struct seq_file *m, void *v)
 
444
{
 
445
        struct apm_power_info info;
 
446
        char *units;
 
447
 
 
448
        info.ac_line_status = 0xff;
 
449
        info.battery_status = 0xff;
 
450
        info.battery_flag   = 0xff;
 
451
        info.battery_life   = -1;
 
452
        info.time           = -1;
 
453
        info.units          = -1;
 
454
 
 
455
        if (apm_get_power_status)
 
456
                apm_get_power_status(&info);
 
457
 
 
458
        switch (info.units) {
 
459
        default:        units = "?";    break;
 
460
        case 0:         units = "min";  break;
 
461
        case 1:         units = "sec";  break;
 
462
        }
 
463
 
 
464
        seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
 
465
                     driver_version, APM_32_BIT_SUPPORT,
 
466
                     info.ac_line_status, info.battery_status,
 
467
                     info.battery_flag, info.battery_life,
 
468
                     info.time, units);
 
469
 
 
470
        return 0;
 
471
}
 
472
 
 
473
static int proc_apm_open(struct inode *inode, struct file *file)
 
474
{
 
475
        return single_open(file, proc_apm_show, NULL);
 
476
}
 
477
 
 
478
static const struct file_operations apm_proc_fops = {
 
479
        .owner          = THIS_MODULE,
 
480
        .open           = proc_apm_open,
 
481
        .read           = seq_read,
 
482
        .llseek         = seq_lseek,
 
483
        .release        = single_release,
 
484
};
 
485
#endif
 
486
 
 
487
static int kapmd(void *arg)
 
488
{
 
489
        do {
 
490
                apm_event_t event;
 
491
 
 
492
                wait_event_interruptible(kapmd_wait,
 
493
                                !queue_empty(&kapmd_queue) || kthread_should_stop());
 
494
 
 
495
                if (kthread_should_stop())
 
496
                        break;
 
497
 
 
498
                spin_lock_irq(&kapmd_queue_lock);
 
499
                event = 0;
 
500
                if (!queue_empty(&kapmd_queue))
 
501
                        event = queue_get_event(&kapmd_queue);
 
502
                spin_unlock_irq(&kapmd_queue_lock);
 
503
 
 
504
                switch (event) {
 
505
                case 0:
 
506
                        break;
 
507
 
 
508
                case APM_LOW_BATTERY:
 
509
                case APM_POWER_STATUS_CHANGE:
 
510
                        queue_event(event);
 
511
                        break;
 
512
 
 
513
                case APM_USER_SUSPEND:
 
514
                case APM_SYS_SUSPEND:
 
515
                        pm_suspend(PM_SUSPEND_MEM);
 
516
                        break;
 
517
 
 
518
                case APM_CRITICAL_SUSPEND:
 
519
                        atomic_inc(&userspace_notification_inhibit);
 
520
                        pm_suspend(PM_SUSPEND_MEM);
 
521
                        atomic_dec(&userspace_notification_inhibit);
 
522
                        break;
 
523
                }
 
524
        } while (1);
 
525
 
 
526
        return 0;
 
527
}
 
528
 
 
529
static int apm_suspend_notifier(struct notifier_block *nb,
 
530
                                unsigned long event,
 
531
                                void *dummy)
 
532
{
 
533
        struct apm_user *as;
 
534
        int err;
 
535
 
 
536
        /* short-cut emergency suspends */
 
537
        if (atomic_read(&userspace_notification_inhibit))
 
538
                return NOTIFY_DONE;
 
539
 
 
540
        switch (event) {
 
541
        case PM_SUSPEND_PREPARE:
 
542
                /*
 
543
                 * Queue an event to all "writer" users that we want
 
544
                 * to suspend and need their ack.
 
545
                 */
 
546
                mutex_lock(&state_lock);
 
547
                down_read(&user_list_lock);
 
548
 
 
549
                list_for_each_entry(as, &apm_user_list, list) {
 
550
                        if (as->suspend_state != SUSPEND_WAIT && as->reader &&
 
551
                            as->writer && as->suser) {
 
552
                                as->suspend_state = SUSPEND_PENDING;
 
553
                                atomic_inc(&suspend_acks_pending);
 
554
                                queue_add_event(&as->queue, APM_USER_SUSPEND);
 
555
                        }
 
556
                }
 
557
 
 
558
                up_read(&user_list_lock);
 
559
                mutex_unlock(&state_lock);
 
560
                wake_up_interruptible(&apm_waitqueue);
 
561
 
 
562
                /*
 
563
                 * Wait for the the suspend_acks_pending variable to drop to
 
564
                 * zero, meaning everybody acked the suspend event (or the
 
565
                 * process was killed.)
 
566
                 *
 
567
                 * If the app won't answer within a short while we assume it
 
568
                 * locked up and ignore it.
 
569
                 */
 
570
                err = wait_event_interruptible_timeout(
 
571
                        apm_suspend_waitqueue,
 
572
                        atomic_read(&suspend_acks_pending) == 0,
 
573
                        5*HZ);
 
574
 
 
575
                /* timed out */
 
576
                if (err == 0) {
 
577
                        /*
 
578
                         * Move anybody who timed out to "ack timeout" state.
 
579
                         *
 
580
                         * We could time out and the userspace does the ACK
 
581
                         * right after we time out but before we enter the
 
582
                         * locked section here, but that's fine.
 
583
                         */
 
584
                        mutex_lock(&state_lock);
 
585
                        down_read(&user_list_lock);
 
586
                        list_for_each_entry(as, &apm_user_list, list) {
 
587
                                if (as->suspend_state == SUSPEND_PENDING ||
 
588
                                    as->suspend_state == SUSPEND_READ) {
 
589
                                        as->suspend_state = SUSPEND_ACKTO;
 
590
                                        atomic_dec(&suspend_acks_pending);
 
591
                                }
 
592
                        }
 
593
                        up_read(&user_list_lock);
 
594
                        mutex_unlock(&state_lock);
 
595
                }
 
596
 
 
597
                /* let suspend proceed */
 
598
                if (err >= 0)
 
599
                        return NOTIFY_OK;
 
600
 
 
601
                /* interrupted by signal */
 
602
                return notifier_from_errno(err);
 
603
 
 
604
        case PM_POST_SUSPEND:
 
605
                /*
 
606
                 * Anyone on the APM queues will think we're still suspended.
 
607
                 * Send a message so everyone knows we're now awake again.
 
608
                 */
 
609
                queue_event(APM_NORMAL_RESUME);
 
610
 
 
611
                /*
 
612
                 * Finally, wake up anyone who is sleeping on the suspend.
 
613
                 */
 
614
                mutex_lock(&state_lock);
 
615
                down_read(&user_list_lock);
 
616
                list_for_each_entry(as, &apm_user_list, list) {
 
617
                        if (as->suspend_state == SUSPEND_ACKED) {
 
618
                                /*
 
619
                                 * TODO: maybe grab error code, needs core
 
620
                                 * changes to push the error to the notifier
 
621
                                 * chain (could use the second parameter if
 
622
                                 * implemented)
 
623
                                 */
 
624
                                as->suspend_result = 0;
 
625
                                as->suspend_state = SUSPEND_DONE;
 
626
                        }
 
627
                }
 
628
                up_read(&user_list_lock);
 
629
                mutex_unlock(&state_lock);
 
630
 
 
631
                wake_up(&apm_suspend_waitqueue);
 
632
                return NOTIFY_OK;
 
633
 
 
634
        default:
 
635
                return NOTIFY_DONE;
 
636
        }
 
637
}
 
638
 
 
639
static struct notifier_block apm_notif_block = {
 
640
        .notifier_call = apm_suspend_notifier,
 
641
};
 
642
 
 
643
static int __init apm_init(void)
 
644
{
 
645
        int ret;
 
646
 
 
647
        if (apm_disabled) {
 
648
                printk(KERN_NOTICE "apm: disabled on user request.\n");
 
649
                return -ENODEV;
 
650
        }
 
651
 
 
652
        kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");
 
653
        if (IS_ERR(kapmd_tsk)) {
 
654
                ret = PTR_ERR(kapmd_tsk);
 
655
                kapmd_tsk = NULL;
 
656
                goto out;
 
657
        }
 
658
        wake_up_process(kapmd_tsk);
 
659
 
 
660
#ifdef CONFIG_PROC_FS
 
661
        proc_create("apm", 0, NULL, &apm_proc_fops);
 
662
#endif
 
663
 
 
664
        ret = misc_register(&apm_device);
 
665
        if (ret)
 
666
                goto out_stop;
 
667
 
 
668
        ret = register_pm_notifier(&apm_notif_block);
 
669
        if (ret)
 
670
                goto out_unregister;
 
671
 
 
672
        return 0;
 
673
 
 
674
 out_unregister:
 
675
        misc_deregister(&apm_device);
 
676
 out_stop:
 
677
        remove_proc_entry("apm", NULL);
 
678
        kthread_stop(kapmd_tsk);
 
679
 out:
 
680
        return ret;
 
681
}
 
682
 
 
683
static void __exit apm_exit(void)
 
684
{
 
685
        unregister_pm_notifier(&apm_notif_block);
 
686
        misc_deregister(&apm_device);
 
687
        remove_proc_entry("apm", NULL);
 
688
 
 
689
        kthread_stop(kapmd_tsk);
 
690
}
 
691
 
 
692
module_init(apm_init);
 
693
module_exit(apm_exit);
 
694
 
 
695
MODULE_AUTHOR("Stephen Rothwell");
 
696
MODULE_DESCRIPTION("Advanced Power Management");
 
697
MODULE_LICENSE("GPL");
 
698
 
 
699
#ifndef MODULE
 
700
static int __init apm_setup(char *str)
 
701
{
 
702
        while ((str != NULL) && (*str != '\0')) {
 
703
                if (strncmp(str, "off", 3) == 0)
 
704
                        apm_disabled = 1;
 
705
                if (strncmp(str, "on", 2) == 0)
 
706
                        apm_disabled = 0;
 
707
                str = strchr(str, ',');
 
708
                if (str != NULL)
 
709
                        str += strspn(str, ", \t");
 
710
        }
 
711
        return 1;
 
712
}
 
713
 
 
714
__setup("apm=", apm_setup);
 
715
#endif
 
716
 
 
717
/**
 
718
 * apm_queue_event - queue an APM event for kapmd
 
719
 * @event: APM event
 
720
 *
 
721
 * Queue an APM event for kapmd to process and ultimately take the
 
722
 * appropriate action.  Only a subset of events are handled:
 
723
 *   %APM_LOW_BATTERY
 
724
 *   %APM_POWER_STATUS_CHANGE
 
725
 *   %APM_USER_SUSPEND
 
726
 *   %APM_SYS_SUSPEND
 
727
 *   %APM_CRITICAL_SUSPEND
 
728
 */
 
729
void apm_queue_event(apm_event_t event)
 
730
{
 
731
        unsigned long flags;
 
732
 
 
733
        spin_lock_irqsave(&kapmd_queue_lock, flags);
 
734
        queue_add_event(&kapmd_queue, event);
 
735
        spin_unlock_irqrestore(&kapmd_queue_lock, flags);
 
736
 
 
737
        wake_up_interruptible(&kapmd_wait);
 
738
}
 
739
EXPORT_SYMBOL(apm_queue_event);