Lines Matching +full:suspend +full:- +full:in +full:- +full:wait

1 // SPDX-License-Identifier: GPL-2.0-only
3 * bios-less APM driver for ARM Linux
24 #include <linux/suspend.h>
25 #include <linux/apm-emulation.h>
55 * SUSPEND_PENDING: suspend event queued for thread and pending to be read
56 * SUSPEND_READ: suspend event read, pending acknowledgement
60 * SUSPEND_DONE: thread had acked suspend and is now notified of
63 * SUSPEND_WAIT: this thread invoked suspend and is waiting for resume
65 * A thread migrates in one of three paths:
66 * NONE -1-> PENDING -2-> READ -3-> ACKED -4-> DONE -5-> NONE
67 * -6-> ACKTO -7-> NONE
68 * NONE -8-> WAIT -9-> NONE
70 * While in PENDING or READ, the thread is accounted for in the
74 * 1: suspend event is signalled from the core PM code
75 * 2: the suspend event is read from the fd by the userspace thread
86 * 8: userspace thread issues the APM_IOC_SUSPEND ioctl (to suspend),
101 * The per-file APM data
135 * "APM" events within - specifically necessary if we're going
168 return q->event_head == q->event_tail; in queue_empty()
173 q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; in queue_get_event()
174 return q->events[q->event_tail]; in queue_get_event()
179 q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; in queue_add_event()
180 if (q->event_head == q->event_tail) { in queue_add_event()
185 q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; in queue_add_event()
187 q->events[q->event_head] = event; in queue_add_event()
196 if (as->reader) in queue_event()
197 queue_add_event(&as->queue, event); in queue_event()
205 struct apm_user *as = fp->private_data; in apm_read()
210 return -EINVAL; in apm_read()
212 if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) in apm_read()
213 return -EAGAIN; in apm_read()
215 wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); in apm_read()
217 while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { in apm_read()
218 event = queue_get_event(&as->queue); in apm_read()
220 ret = -EFAULT; in apm_read()
225 if (as->suspend_state == SUSPEND_PENDING && in apm_read()
227 as->suspend_state = SUSPEND_READ; in apm_read()
231 i -= sizeof(event); in apm_read()
235 ret = count - i; in apm_read()
240 static __poll_t apm_poll(struct file *fp, poll_table * wait) in apm_poll() argument
242 struct apm_user *as = fp->private_data; in apm_poll()
244 poll_wait(fp, &apm_waitqueue, wait); in apm_poll()
245 return queue_empty(&as->queue) ? 0 : EPOLLIN | EPOLLRDNORM; in apm_poll()
249 * apm_ioctl - handle APM ioctl
253 * - initiate a suspend
254 * - acknowledge a suspend read from /dev/apm_bios.
256 * has acknowledge does the actual suspend happen.
261 struct apm_user *as = filp->private_data; in apm_ioctl()
262 int err = -EINVAL; in apm_ioctl()
264 if (!as->suser || !as->writer) in apm_ioctl()
265 return -EPERM; in apm_ioctl()
271 as->suspend_result = -EINTR; in apm_ioctl()
273 switch (as->suspend_state) { in apm_ioctl()
276 * If we read a suspend command from /dev/apm_bios, in apm_ioctl()
280 as->suspend_state = SUSPEND_ACKED; in apm_ioctl()
291 * Wait for the suspend/resume to complete. If there in apm_ioctl()
292 * are pending acknowledges, we wait here for them. in apm_ioctl()
298 as->suspend_state != SUSPEND_ACKED)) in apm_ioctl()
302 as->suspend_result = -ETIMEDOUT; in apm_ioctl()
306 as->suspend_state = SUSPEND_WAIT; in apm_ioctl()
310 * Otherwise it is a request to suspend the system. in apm_ioctl()
314 as->suspend_result = pm_suspend(PM_SUSPEND_MEM); in apm_ioctl()
318 err = as->suspend_result; in apm_ioctl()
319 as->suspend_state = SUSPEND_NONE; in apm_ioctl()
329 struct apm_user *as = filp->private_data; in apm_release()
331 filp->private_data = NULL; in apm_release()
334 list_del(&as->list); in apm_release()
342 if (as->suspend_state == SUSPEND_PENDING || in apm_release()
343 as->suspend_state == SUSPEND_READ) in apm_release()
360 * XXX - this is a tiny bit broken, when we consider BSD in apm_open()
364 * privileged operation -- cevans in apm_open()
366 as->suser = capable(CAP_SYS_ADMIN); in apm_open()
367 as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; in apm_open()
368 as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; in apm_open()
371 list_add(&as->list, &apm_user_list); in apm_open()
374 filp->private_data = as; in apm_open()
377 return as ? 0 : -ENOMEM; in apm_open()
410 * 0x00: Off-line
411 * 0x01: On-line
429 * 0-100: valid
430 * -1: Unknown
433 * -1: Unknown
444 info.battery_life = -1; in proc_apm_show()
445 info.time = -1; in proc_apm_show()
446 info.units = -1; in proc_apm_show()
517 /* short-cut emergency suspends */ in apm_suspend_notifier()
528 * to suspend and need their ack. in apm_suspend_notifier()
534 if (as->suspend_state != SUSPEND_WAIT && as->reader && in apm_suspend_notifier()
535 as->writer && as->suser) { in apm_suspend_notifier()
536 as->suspend_state = SUSPEND_PENDING; in apm_suspend_notifier()
538 queue_add_event(&as->queue, apm_event); in apm_suspend_notifier()
547 * Wait for the suspend_acks_pending variable to drop to in apm_suspend_notifier()
548 * zero, meaning everybody acked the suspend event (or the in apm_suspend_notifier()
571 if (as->suspend_state == SUSPEND_PENDING || in apm_suspend_notifier()
572 as->suspend_state == SUSPEND_READ) { in apm_suspend_notifier()
573 as->suspend_state = SUSPEND_ACKTO; in apm_suspend_notifier()
581 /* let suspend proceed */ in apm_suspend_notifier()
599 * Finally, wake up anyone who is sleeping on the suspend. in apm_suspend_notifier()
604 if (as->suspend_state == SUSPEND_ACKED) { in apm_suspend_notifier()
611 as->suspend_result = 0; in apm_suspend_notifier()
612 as->suspend_state = SUSPEND_DONE; in apm_suspend_notifier()
636 return -ENODEV; in apm_init()
705 * apm_queue_event - queue an APM event for kapmd