Import 2.1.118
[davej-history.git] / drivers / char / apm_bios.c
blob32f109be32f5a84c7be79918855685694e12a7e0
1 /* -*- linux-c -*-
2 * APM BIOS driver for Linux
3 * Copyright 1994, 1995, 1996 Stephen Rothwell
4 * (Stephen.Rothwell@canb.auug.org.au)
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * $Id: apm_bios.c,v 0.22 1995/03/09 14:12:02 sfr Exp $
18 * October 1995, Rik Faith (faith@cs.unc.edu):
19 * Minor enhancements and updates (to the patch set) for 1.3.x
20 * Documentation
21 * January 1996, Rik Faith (faith@cs.unc.edu):
22 * Make /proc/apm easy to format (bump driver version)
23 * March 1996, Rik Faith (faith@cs.unc.edu):
24 * Prohibit APM BIOS calls unless apm_enabled.
25 * (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>)
26 * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
27 * Version 1.0 and 1.1
28 * May 1996, Version 1.2
29 * Feb 1998, Version 1.3
30 * Feb 1998, Version 1.4
32 * History:
33 * 0.6b: first version in official kernel, Linux 1.3.46
34 * 0.7: changed /proc/apm format, Linux 1.3.58
35 * 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
36 * 0.9: only call bios if bios is present, Linux 1.3.72
37 * 1.0: use fixed device number, consolidate /proc/apm into this file,
38 * Linux 1.3.85
39 * 1.1: support user-space standby and suspend, power off after system
40 * halted, Linux 1.3.98
41 * 1.2: When resetting RTC after resume, take care so that the time
42 * is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
43 * <jtoth@princeton.edu>); improve interaction between
44 * screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
45 * 1.2a:Simple change to stop mysterious bug reports with SMP also added
46 * levels to the printk calls. APM is not defined for SMP machines.
47 * The new replacment for it is, but Linux doesn't yet support this.
48 * Alan Cox Linux 2.1.55
49 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
50 * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
51 * Dean Gaudet <dgaudet@arctic.org>.
52 * C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
54 * APM 1.1 Reference:
56 * Intel Corporation, Microsoft Corporation. Advanced Power Management
57 * (APM) BIOS Interface Specification, Revision 1.1, September 1993.
58 * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
60 * [This document is available free from Intel by calling 800.628.8686 (fax
61 * 916.356.6100) or 800.548.4725; or via anonymous ftp from
62 * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
63 * available from Microsoft by calling 206.882.8080.]
65 * APM 1.2 Reference:
66 * Intel Corporation, Microsoft Corporation. Advanced Power Management
67 * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
69 * [This document is available from Intel at:
70 * http://www.intel.com/IAL/powermgm
71 * or Microsoft at
72 * http://www.microsoft.com/windows/thirdparty/hardware/pcfuture.htm
73 * ]
76 #include <linux/config.h>
77 #include <linux/module.h>
79 #include <asm/system.h>
80 #include <asm/uaccess.h>
82 #include <linux/poll.h>
83 #include <linux/types.h>
84 #include <linux/stddef.h>
85 #include <linux/timer.h>
86 #include <linux/fcntl.h>
87 #include <linux/malloc.h>
88 #include <linux/linkage.h>
89 #ifdef CONFIG_PROC_FS
90 #include <linux/stat.h>
91 #include <linux/proc_fs.h>
92 #endif
93 #include <linux/miscdevice.h>
94 #include <linux/apm_bios.h>
95 #include <linux/init.h>
97 EXPORT_SYMBOL(apm_register_callback);
98 EXPORT_SYMBOL(apm_unregister_callback);
100 extern unsigned long get_cmos_time(void);
103 * The apm_bios device is one of the misc char devices.
104 * This is its minor number.
106 #define APM_MINOR_DEV 134
108 /* Configurable options:
110 * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests.
111 * This is necessary on the NEC Versa M series, which generates these when
112 * resuming from SYSTEM SUSPEND. However, enabling this on other laptops
113 * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate
114 * USER SUSPEND is ignored -- this may prevent the APM driver from updating
115 * the system time on a RESUME.
117 * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of
118 * the specification: "When disabled, the APM BIOS does not automatically
119 * power manage devices, enter the Standby State, enter the Suspend State,
120 * or take power saving steps in response to CPU Idle calls." This driver
121 * will make CPU Idle calls when Linux is idle (unless this feature is
122 * turned off -- see below). This should always save battery power, but
123 * more complicated APM features will be dependent on your BIOS
124 * implementation. You may need to turn this option off if your computer
125 * hangs at boot time when using APM support, or if it beeps continuously
126 * instead of suspending. Turn this off if you have a NEC UltraLite Versa
127 * 33/C or a Toshiba T400CDT. This is off by default since most machines
128 * do fine without this feature.
130 * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the
131 * idle loop. On some machines, this can activate improved power savings,
132 * such as a slowed CPU clock rate, when the machine is idle. These idle
133 * call is made after the idle loop has run for some length of time (e.g.,
134 * 333 mS). On some machines, this will cause a hang at boot time or
135 * whenever the CPU becomes idle.
137 * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some
138 * laptops can use this to turn of the LCD backlight when the VC screen
139 * blanker blanks the screen. Note that this is only used by the VC screen
140 * blanker, and probably won't turn off the backlight when using X11. Some
141 * problems have been reported when using this option with gpm (if you'd
142 * like to debug this, please do so).
144 * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist
145 * on returning multiple suspend/standby events whenever one occurs. We
146 * really only need one at a time, so just ignore any beyond the first.
147 * This is probably safe on most laptops.
149 * If you are debugging the APM support for your laptop, note that code for
150 * all of these options is contained in this file, so you can #define or
151 * #undef these on the next line to avoid recompiling the whole kernel.
155 /* KNOWN PROBLEM MACHINES:
157 * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
158 * [Confirmed by TI representative]
159 * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
160 * [Confirmed by BIOS disassembly]
161 * P: Toshiba 1950S: battery life information only gets updated after resume
162 * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
163 * broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
165 * Legend: U = unusable with APM patches
166 * P = partially usable with APM patches
170 * Define to have debug messages.
172 #undef APM_DEBUG
175 * Define to always call the APM BIOS busy routine even if the clock was
176 * not slowed by the idle routine.
178 #define ALWAYS_CALL_BUSY
181 * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
182 * should turn interrupts on before it does a 'hlt').
184 #define APM_NOINTS
187 * Define to make the APM BIOS calls zero all data segment registers (so
188 * that an incorrect BIOS implementation will cause a kernel panic if it
189 * tries to write to arbitrary memory).
191 #define APM_ZERO_SEGS
194 * Define to make all set_limit calls use 64k limits. The APM 1.1 BIOS is
195 * supposed to provide limit information that it recognizes. Many machines
196 * do this correctly, but many others do not restrict themselves to their
197 * claimed limit. When this happens, they will cause a segmentation
198 * violation in the kernel at boot time. Most BIOS's, however, will
199 * respect a 64k limit, so we use that. If you want to be pedantic and
200 * hold your BIOS to its claims, then undefine this.
202 #define APM_RELAX_SEGMENTS
205 * Need to poll the APM BIOS every second
207 #define APM_CHECK_TIMEOUT (HZ)
210 * These are the actual BIOS calls in assembler. Depending on
211 * APM_ZERO_SEGS and APM_NOINTS, we are being really paranoid here! Not
212 * only are interrupts disabled, but all the segment registers (except SS)
213 * are saved and zeroed this means that if the BIOS tries to reference any
214 * data without explicitly loading the segment registers, the kernel will
215 * fault immediately rather than have some unforeseen circumstances for the
216 * rest of the kernel. And it will be very obvious! :-) Doing this
217 * depends on CS referring to the same physical memory as DS so that DS can
218 * be zeroed before the call. Unfortunately, we can't do anything about the
219 * stack segment/pointer. Also, we tell the compiler that everything could
220 * change.
222 #ifdef APM_NOINTS
223 # define APM_DO_CLI "cli\n\t"
224 #else
225 # define APM_DO_CLI
226 #endif
227 #ifdef APM_ZERO_SEGS
228 # define APM_DO_ZERO_SEGS \
229 "pushl %%ds\n\t" \
230 "pushl %%es\n\t" \
231 "pushl %%fs\n\t" \
232 "pushl %%gs\n\t" \
233 "xorl %%edx, %%edx\n\t" \
234 "movl %%dx, %%ds\n\t" \
235 "movl %%dx, %%es\n\t" \
236 "movl %%dx, %%fs\n\t" \
237 "movl %%dx, %%gs\n\t"
238 # define APM_DO_RESTORE_SEGS \
239 "popl %%gs\n\t" \
240 "popl %%fs\n\t" \
241 "popl %%es\n\t" \
242 "popl %%ds\n\t"
243 #else
244 # define APM_DO_ZERO_SEGS
245 # define APM_DO_RESTORE_SEGS
246 #endif
248 #define APM_BIOS_CALL(error_reg) \
249 __asm__ __volatile__( \
250 APM_DO_ZERO_SEGS \
251 "pushfl\n\t" \
252 APM_DO_CLI \
253 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" \
254 "setc %%" # error_reg "\n\t" \
255 "popfl\n\t" \
256 APM_DO_RESTORE_SEGS
257 #define APM_BIOS_CALL_END \
258 : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory")
260 #ifdef CONFIG_APM_CPU_IDLE
261 #define APM_SET_CPU_IDLE(error) \
262 APM_BIOS_CALL(al) \
263 : "=a" (error) \
264 : "a" (0x5305) \
265 APM_BIOS_CALL_END
266 #endif
268 #define APM_SET_CPU_BUSY(error) \
269 APM_BIOS_CALL(al) \
270 : "=a" (error) \
271 : "a" (0x5306) \
272 APM_BIOS_CALL_END
274 #define APM_SET_POWER_STATE(state, error) \
275 APM_BIOS_CALL(al) \
276 : "=a" (error) \
277 : "a" (0x5307), "b" (0x0001), "c" (state) \
278 APM_BIOS_CALL_END
280 #ifdef CONFIG_APM_DISPLAY_BLANK
281 #define APM_SET_DISPLAY_POWER_STATE(state, error) \
282 APM_BIOS_CALL(al) \
283 : "=a" (error) \
284 : "a" (0x5307), "b" (0x01ff), "c" (state) \
285 APM_BIOS_CALL_END
286 #endif
288 #ifdef CONFIG_APM_DO_ENABLE
289 #define APM_ENABLE_POWER_MANAGEMENT(device, error) \
290 APM_BIOS_CALL(al) \
291 : "=a" (error) \
292 : "a" (0x5308), "b" (device), "c" (1) \
293 APM_BIOS_CALL_END
294 #endif
296 #define APM_GET_POWER_STATUS(bx, cx, dx, error) \
297 APM_BIOS_CALL(al) \
298 : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \
299 : "a" (0x530a), "b" (1) \
300 APM_BIOS_CALL_END
302 #define APM_GET_BATTERY_STATUS(which, bx, cx, dx, si, error) \
303 APM_BIOS_CALL(al) \
304 : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx), "=S" (si) \
305 : "a" (0x530a), "b" (0x8000 | (which)) \
306 APM_BIOS_CALL_END
308 #define APM_GET_EVENT(event, info, error) \
309 APM_BIOS_CALL(al) \
310 : "=a" (error), "=b" (event), "=c" (info) \
311 : "a" (0x530b) \
312 APM_BIOS_CALL_END
314 #define APM_DRIVER_VERSION(ver, ax, error) \
315 APM_BIOS_CALL(bl) \
316 : "=a" (ax), "=b" (error) \
317 : "a" (0x530e), "b" (0), "c" (ver) \
318 APM_BIOS_CALL_END
320 #define APM_ENGAGE_POWER_MANAGEMENT(device, error) \
321 APM_BIOS_CALL(al) \
322 : "=a" (error) \
323 : "a" (0x530f), "b" (device), "c" (1) \
324 APM_BIOS_CALL_END
327 * Forward declarations
329 static void suspend(void);
330 static void standby(void);
331 static void set_time(void);
333 static void check_events(void);
334 static void do_apm_timer(unsigned long);
336 static int do_open(struct inode *, struct file *);
337 static int do_release(struct inode *, struct file *);
338 static ssize_t do_read(struct file *, char *, size_t , loff_t *);
339 static unsigned int do_poll(struct file *, poll_table *);
340 static int do_ioctl(struct inode *, struct file *, u_int, u_long);
342 #ifdef CONFIG_PROC_FS
343 static int apm_get_info(char *, char **, off_t, int, int);
344 #endif
346 extern int apm_register_callback(int (*)(apm_event_t));
347 extern void apm_unregister_callback(int (*)(apm_event_t));
350 * Local variables
352 static asmlinkage struct {
353 unsigned long offset;
354 unsigned short segment;
355 } apm_bios_entry;
356 static int apm_enabled = 0;
357 #ifdef CONFIG_APM_CPU_IDLE
358 static int clock_slowed = 0;
359 #endif
360 static int suspends_pending = 0;
361 static int standbys_pending = 0;
362 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
363 static int waiting_for_resume = 0;
364 #endif
366 static long clock_cmos_diff;
367 static int got_clock_diff = 0;
369 static struct wait_queue * process_list = NULL;
370 static struct apm_bios_struct * user_list = NULL;
372 static struct timer_list apm_timer;
374 static char driver_version[] = "1.4"; /* no spaces */
376 #ifdef APM_DEBUG
377 static char * apm_event_name[] = {
378 "system standby",
379 "system suspend",
380 "normal resume",
381 "critical resume",
382 "low battery",
383 "power status change",
384 "update time",
385 "critical suspend",
386 "user standby",
387 "user suspend",
388 "system standby resume",
389 "capabilities change"
391 #define NR_APM_EVENT_NAME \
392 (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
393 #endif
395 static struct file_operations apm_bios_fops = {
396 NULL, /* lseek */
397 do_read,
398 NULL, /* write */
399 NULL, /* readdir */
400 do_poll,
401 do_ioctl,
402 NULL, /* mmap */
403 do_open,
404 NULL, /* flush */
405 do_release,
406 NULL, /* fsync */
407 NULL /* fasync */
410 static struct miscdevice apm_device = {
411 APM_MINOR_DEV,
412 "apm",
413 &apm_bios_fops
416 typedef struct callback_list_t {
417 int (* callback)(apm_event_t);
418 struct callback_list_t * next;
419 } callback_list_t;
421 static callback_list_t * callback_list = NULL;
423 typedef struct lookup_t {
424 int key;
425 char * msg;
426 } lookup_t;
428 static const lookup_t error_table[] = {
429 /* N/A { APM_SUCCESS, "Operation succeeded" }, */
430 { APM_DISABLED, "Power management disabled" },
431 { APM_CONNECTED, "Real mode interface already connected" },
432 { APM_NOT_CONNECTED, "Interface not connected" },
433 { APM_16_CONNECTED, "16 bit interface already connected" },
434 /* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
435 { APM_32_CONNECTED, "32 bit interface already connected" },
436 { APM_32_UNSUPPORTED, "32 bit interface not supported" },
437 { APM_BAD_DEVICE, "Unrecognized device ID" },
438 { APM_BAD_PARAM, "Parameter out of range" },
439 { APM_NOT_ENGAGED, "Interface not engaged" },
440 { APM_BAD_FUNCTION, "Function not supported" },
441 { APM_RESUME_DISABLED, "Resume timer disabled" },
442 { APM_BAD_STATE, "Unable to enter requested state" },
443 /* N/A { APM_NO_EVENTS, "No events pending" }, */
444 { APM_NOT_PRESENT, "No APM present" }
446 #define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
448 static int apm_driver_version(u_short *val)
450 u_short error;
452 APM_DRIVER_VERSION(*val, *val, error);
454 if (error & 0xff)
455 return (*val >> 8);
456 return APM_SUCCESS;
459 static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
461 u_short error;
463 APM_GET_EVENT(*event, *info, error);
464 if (error & 0xff)
465 return (error >> 8);
466 if (apm_bios_info.version < 0x0102)
467 *info = ~0; /* indicate info not valid */
468 return APM_SUCCESS;
471 int apm_set_power_state(u_short state)
473 u_short error;
475 APM_SET_POWER_STATE(state, error);
476 if (error & 0xff)
477 return (error >> 8);
478 return APM_SUCCESS;
481 #ifdef CONFIG_APM_DISPLAY_BLANK
482 /* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
483 static int apm_set_display_power_state(u_short state)
485 u_short error;
487 APM_SET_DISPLAY_POWER_STATE(state, error);
488 if (error & 0xff)
489 return (error >> 8);
490 return APM_SUCCESS;
492 #endif
494 #ifdef CONFIG_APM_DO_ENABLE
495 /* Called by apm_setup if apm_enabled will be true. */
496 static inline int apm_enable_power_management(void)
498 u_short error;
500 APM_ENABLE_POWER_MANAGEMENT((apm_bios_info.version > 0x100)
501 ? 0x0001 : 0xffff,
502 error);
503 if (error & 0xff)
504 return (error >> 8);
505 return APM_SUCCESS;
507 #endif
509 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
511 u_short error;
513 APM_GET_POWER_STATUS(*status, *bat, *life, error);
514 if (error & 0xff)
515 return (error >> 8);
516 return APM_SUCCESS;
519 #if 0
520 /* not used anywhere */
521 static int apm_get_battery_status(u_short which,
522 u_short *bat, u_short *life, u_short *nbat)
524 u_short status, error;
526 if (apm_bios_info.version < 0x0102) {
527 /* pretend we only have one battery. */
528 if (which!=1) return APM_BAD_DEVICE;
529 *nbat = 1;
530 return apm_get_power_status(&status, bat, life);
533 APM_GET_BATTERY_STATUS(which, status, *bat, *life, *nbat, error);
534 if (error & 0xff)
535 return (error >> 8);
536 return APM_SUCCESS;
538 #endif
540 static inline int apm_engage_power_management(u_short device)
542 u_short error;
544 APM_ENGAGE_POWER_MANAGEMENT(device, error);
545 if (error & 0xff)
546 return (error >> 8);
547 return APM_SUCCESS;
550 static void apm_error(char *str, int err)
552 int i;
554 for (i = 0; i < ERROR_COUNT; i++)
555 if (error_table[i].key == err) break;
556 if (i < ERROR_COUNT)
557 printk(KERN_NOTICE "apm_bios: %s: %s\n", str, error_table[i].msg);
558 else
559 printk(KERN_NOTICE "apm_bios: %s: unknown error code %#2.2x\n", str, err);
562 /* Called from console driver -- must make sure apm_enabled. */
563 int apm_display_blank(void)
565 #ifdef CONFIG_APM_DISPLAY_BLANK
566 int error;
568 if (!apm_enabled)
569 return 0;
570 error = apm_set_display_power_state(APM_STATE_STANDBY);
571 if (error == APM_SUCCESS)
572 return 1;
573 apm_error("set display standby", error);
574 #endif
575 return 0;
578 /* Called from console driver -- must make sure apm_enabled. */
579 int apm_display_unblank(void)
581 #ifdef CONFIG_APM_DISPLAY_BLANK
582 int error;
584 if (!apm_enabled)
585 return 0;
586 error = apm_set_display_power_state(APM_STATE_READY);
587 if (error == APM_SUCCESS)
588 return 1;
589 apm_error("set display ready", error);
590 #endif
591 return 0;
594 int apm_register_callback(int (*callback)(apm_event_t))
596 callback_list_t * new;
598 new = kmalloc(sizeof(callback_list_t), GFP_KERNEL);
599 if (new == NULL)
600 return -ENOMEM;
601 new->callback = callback;
602 new->next = callback_list;
603 callback_list = new;
604 return 0;
607 void apm_unregister_callback(int (*callback)(apm_event_t))
609 callback_list_t ** ptr;
610 callback_list_t * old;
612 ptr = &callback_list;
613 for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next)
614 if ((*ptr)->callback == callback)
615 break;
616 old = *ptr;
617 *ptr = old->next;
618 kfree_s(old, sizeof(callback_list_t));
621 static int queue_empty(struct apm_bios_struct * as)
623 return as->event_head == as->event_tail;
626 static apm_event_t get_queued_event(struct apm_bios_struct * as)
628 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
629 return as->events[as->event_tail];
632 static int queue_event(apm_event_t event, struct apm_bios_struct *sender)
634 struct apm_bios_struct * as;
636 if (user_list == NULL)
637 return 0;
638 for (as = user_list; as != NULL; as = as->next) {
639 if (as == sender)
640 continue;
641 as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
642 if (as->event_head == as->event_tail) {
643 static int notified;
645 if (notified == 0) {
646 printk( "apm_bios: an event queue overflowed\n" );
647 notified = 1;
649 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
651 as->events[as->event_head] = event;
652 if (!as->suser)
653 continue;
654 switch (event) {
655 case APM_SYS_SUSPEND:
656 case APM_USER_SUSPEND:
657 as->suspends_pending++;
658 suspends_pending++;
659 break;
661 case APM_SYS_STANDBY:
662 case APM_USER_STANDBY:
663 as->standbys_pending++;
664 standbys_pending++;
665 break;
668 wake_up_interruptible(&process_list);
669 return 1;
672 static void set_time(void)
674 unsigned long flags;
676 if (!got_clock_diff) /* Don't know time zone, can't set clock */
677 return;
679 save_flags(flags);
680 cli();
681 CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
682 restore_flags(flags);
685 static void suspend(void)
687 unsigned long flags;
688 int err;
690 /* Estimate time zone so that set_time can
691 update the clock */
692 save_flags(flags);
693 clock_cmos_diff = -get_cmos_time();
694 cli();
695 clock_cmos_diff += CURRENT_TIME;
696 got_clock_diff = 1;
697 restore_flags(flags);
699 err = apm_set_power_state(APM_STATE_SUSPEND);
700 if (err)
701 apm_error("suspend", err);
702 set_time();
705 static void standby(void)
707 int err;
709 err = apm_set_power_state(APM_STATE_STANDBY);
710 if (err)
711 apm_error("standby", err);
714 static apm_event_t get_event(void)
716 int error;
717 apm_event_t event;
718 apm_eventinfo_t info;
720 static int notified = 0;
722 /* we don't use the eventinfo */
723 error = apm_get_event(&event, &info);
724 if (error == APM_SUCCESS)
725 return event;
727 if ((error != APM_NO_EVENTS) && (notified++ == 0))
728 apm_error("get_event", error);
730 return 0;
733 static void send_event(apm_event_t event, apm_event_t undo,
734 struct apm_bios_struct *sender)
736 callback_list_t * call;
737 callback_list_t * fix;
739 for (call = callback_list; call != NULL; call = call->next) {
740 if (call->callback(event) && undo) {
741 for (fix = callback_list; fix != call; fix = fix->next)
742 fix->callback(undo);
743 if (apm_bios_info.version > 0x100)
744 apm_set_power_state(APM_STATE_REJECT);
745 return;
749 queue_event(event, sender);
752 static void check_events(void)
754 apm_event_t event;
756 while ((event = get_event()) != 0) {
757 #ifdef APM_DEBUG
758 if (event <= NR_APM_EVENT_NAME)
759 printk(KERN_DEBUG "APM BIOS received %s notify\n",
760 apm_event_name[event - 1]);
761 else
762 printk(KERN_DEBUG "APM BIOS received unknown "
763 "event 0x%02x\n", event);
764 #endif
765 switch (event) {
766 case APM_SYS_STANDBY:
767 case APM_USER_STANDBY:
768 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
769 if (waiting_for_resume) {
770 return;
772 waiting_for_resume = 1;
773 #endif
774 send_event(event, APM_STANDBY_RESUME, NULL);
775 if (standbys_pending <= 0)
776 standby();
777 break;
779 case APM_USER_SUSPEND:
780 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
781 if (apm_bios_info.version > 0x100)
782 apm_set_power_state(APM_STATE_REJECT);
783 break;
784 #endif
785 case APM_SYS_SUSPEND:
786 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
787 if (waiting_for_resume) {
788 return;
790 waiting_for_resume = 1;
791 #endif
792 send_event(event, APM_NORMAL_RESUME, NULL);
793 if (suspends_pending <= 0)
794 suspend();
795 break;
797 case APM_NORMAL_RESUME:
798 case APM_CRITICAL_RESUME:
799 case APM_STANDBY_RESUME:
800 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
801 waiting_for_resume = 0;
802 #endif
803 set_time();
804 send_event(event, 0, NULL);
805 break;
807 case APM_LOW_BATTERY:
808 case APM_POWER_STATUS_CHANGE:
809 case APM_CAPABILITY_CHANGE:
810 send_event(event, 0, NULL);
811 break;
813 case APM_UPDATE_TIME:
814 set_time();
815 break;
817 case APM_CRITICAL_SUSPEND:
818 suspend();
819 break;
824 static void do_apm_timer(unsigned long unused)
826 int err;
828 static int pending_count = 0;
830 if (((standbys_pending > 0) || (suspends_pending > 0))
831 && (apm_bios_info.version > 0x100)
832 && (pending_count-- <= 0)) {
833 pending_count = 4;
835 err = apm_set_power_state(APM_STATE_BUSY);
836 if (err)
837 apm_error("busy", err);
840 if (!(((standbys_pending > 0) || (suspends_pending > 0))
841 && (apm_bios_info.version == 0x100)))
842 check_events();
844 init_timer(&apm_timer);
845 apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
846 add_timer(&apm_timer);
849 /* Called from sys_idle, must make sure apm_enabled. */
850 int apm_do_idle(void)
852 #ifdef CONFIG_APM_CPU_IDLE
853 unsigned short error;
855 if (!apm_enabled)
856 return 0;
858 APM_SET_CPU_IDLE(error);
859 if (error & 0xff)
860 return 0;
862 clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
863 return 1;
864 #else
865 return 0;
866 #endif
869 /* Called from sys_idle, must make sure apm_enabled. */
870 void apm_do_busy(void)
872 #ifdef CONFIG_APM_CPU_IDLE
873 unsigned short error;
875 if (!apm_enabled)
876 return;
878 #ifndef ALWAYS_CALL_BUSY
879 if (!clock_slowed)
880 return;
881 #endif
883 APM_SET_CPU_BUSY(error);
885 clock_slowed = 0;
886 #endif
889 static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
891 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
892 printk(KERN_ERR "apm_bios: %s passed bad filp", func);
893 return 1;
895 return 0;
898 static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
900 struct apm_bios_struct * as;
901 int i;
902 apm_event_t event;
903 struct wait_queue wait = { current, NULL };
905 as = fp->private_data;
906 if (check_apm_bios_struct(as, "read"))
907 return -EIO;
908 if (count < sizeof(apm_event_t))
909 return -EINVAL;
910 if (queue_empty(as)) {
911 if (fp->f_flags & O_NONBLOCK)
912 return -EAGAIN;
913 add_wait_queue(&process_list, &wait);
914 repeat:
915 current->state = TASK_INTERRUPTIBLE;
916 if (queue_empty(as) && !signal_pending(current)) {
917 schedule();
918 goto repeat;
920 current->state = TASK_RUNNING;
921 remove_wait_queue(&process_list, &wait);
923 i = count;
924 while ((i >= sizeof(event)) && !queue_empty(as)) {
925 event = get_queued_event(as);
926 copy_to_user(buf, &event, sizeof(event));
927 switch (event) {
928 case APM_SYS_SUSPEND:
929 case APM_USER_SUSPEND:
930 as->suspends_read++;
931 break;
933 case APM_SYS_STANDBY:
934 case APM_USER_STANDBY:
935 as->standbys_read++;
936 break;
938 buf += sizeof(event);
939 i -= sizeof(event);
941 if (i < count)
942 return count - i;
943 if (signal_pending(current))
944 return -ERESTARTSYS;
945 return 0;
948 static unsigned int do_poll(struct file *fp, poll_table * wait)
950 struct apm_bios_struct * as;
952 as = fp->private_data;
953 if (check_apm_bios_struct(as, "select"))
954 return 0;
955 poll_wait(fp, &process_list, wait);
956 if (!queue_empty(as))
957 return POLLIN | POLLRDNORM;
958 return 0;
961 static int do_ioctl(struct inode * inode, struct file *filp,
962 u_int cmd, u_long arg)
964 struct apm_bios_struct * as;
966 as = filp->private_data;
967 if (check_apm_bios_struct(as, "ioctl"))
968 return -EIO;
969 if (!as->suser)
970 return -EPERM;
971 switch (cmd) {
972 case APM_IOC_STANDBY:
973 if (as->standbys_read > 0) {
974 as->standbys_read--;
975 as->standbys_pending--;
976 standbys_pending--;
978 else
979 send_event(APM_USER_STANDBY, APM_STANDBY_RESUME, as);
980 if (standbys_pending <= 0)
981 standby();
982 break;
983 case APM_IOC_SUSPEND:
984 if (as->suspends_read > 0) {
985 as->suspends_read--;
986 as->suspends_pending--;
987 suspends_pending--;
989 else
990 send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as);
991 if (suspends_pending <= 0)
992 suspend();
993 break;
994 default:
995 return -EINVAL;
997 return 0;
1000 static int do_release(struct inode * inode, struct file * filp)
1002 struct apm_bios_struct * as;
1004 as = filp->private_data;
1005 filp->private_data = NULL;
1006 if (check_apm_bios_struct(as, "release"))
1007 return 0;
1008 if (as->standbys_pending > 0) {
1009 standbys_pending -= as->standbys_pending;
1010 if (standbys_pending <= 0)
1011 standby();
1013 if (as->suspends_pending > 0) {
1014 suspends_pending -= as->suspends_pending;
1015 if (suspends_pending <= 0)
1016 suspend();
1018 if (user_list == as)
1019 user_list = as->next;
1020 else {
1021 struct apm_bios_struct * as1;
1023 for (as1 = user_list;
1024 (as1 != NULL) && (as1->next != as);
1025 as1 = as1->next)
1027 if (as1 == NULL)
1028 printk(KERN_ERR "apm_bios: filp not in user list");
1029 else
1030 as1->next = as->next;
1032 kfree_s(as, sizeof(*as));
1033 return 0;
1036 static int do_open(struct inode * inode, struct file * filp)
1038 struct apm_bios_struct * as;
1040 as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
1041 if (as == NULL) {
1042 printk(KERN_ERR "apm_bios: cannot allocate struct of size %d bytes",
1043 sizeof(*as));
1044 return -ENOMEM;
1046 as->magic = APM_BIOS_MAGIC;
1047 as->event_tail = as->event_head = 0;
1048 as->suspends_pending = as->standbys_pending = 0;
1049 as->suspends_read = as->standbys_read = 0;
1051 * XXX - this is a tiny bit broken, when we consider BSD
1052 * process accounting. If the device is opened by root, we
1053 * instantly flag that we used superuser privs. Who knows,
1054 * we might close the device immediately without doing a
1055 * privileged operation -- cevans
1057 as->suser = capable(CAP_SYS_ADMIN);
1058 as->next = user_list;
1059 user_list = as;
1060 filp->private_data = as;
1061 return 0;
1064 #ifdef CONFIG_PROC_FS
1065 int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
1067 char * p;
1068 unsigned short bx;
1069 unsigned short cx;
1070 unsigned short dx;
1071 unsigned short error;
1072 unsigned short ac_line_status = 0xff;
1073 unsigned short battery_status = 0xff;
1074 unsigned short battery_flag = 0xff;
1075 int percentage = -1;
1076 int time_units = -1;
1077 char *units = "?";
1079 if (!apm_enabled)
1080 return 0;
1081 p = buf;
1083 if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
1084 ac_line_status = (bx >> 8) & 0xff;
1085 battery_status = bx & 0xff;
1086 if ((cx & 0xff) != 0xff)
1087 percentage = cx & 0xff;
1089 if (apm_bios_info.version > 0x100) {
1090 battery_flag = (cx >> 8) & 0xff;
1091 if (dx != 0xffff) {
1092 if ((dx & 0x8000) == 0x8000) {
1093 units = "min";
1094 time_units = dx & 0x7ffe;
1095 } else {
1096 units = "sec";
1097 time_units = dx & 0x7fff;
1102 /* Arguments, with symbols from linux/apm_bios.h. Information is
1103 from the Get Power Status (0x0a) call unless otherwise noted.
1105 0) Linux driver version (this will change if format changes)
1106 1) APM BIOS Version. Usually 1.0 or 1.1.
1107 2) APM flags from APM Installation Check (0x00):
1108 bit 0: APM_16_BIT_SUPPORT
1109 bit 1: APM_32_BIT_SUPPORT
1110 bit 2: APM_IDLE_SLOWS_CLOCK
1111 bit 3: APM_BIOS_DISABLED
1112 bit 4: APM_BIOS_DISENGAGED
1113 3) AC line status
1114 0x00: Off-line
1115 0x01: On-line
1116 0x02: On backup power (APM BIOS 1.1 only)
1117 0xff: Unknown
1118 4) Battery status
1119 0x00: High
1120 0x01: Low
1121 0x02: Critical
1122 0x03: Charging
1123 0xff: Unknown
1124 5) Battery flag
1125 bit 0: High
1126 bit 1: Low
1127 bit 2: Critical
1128 bit 3: Charging
1129 bit 7: No system battery
1130 0xff: Unknown
1131 6) Remaining battery life (percentage of charge):
1132 0-100: valid
1133 -1: Unknown
1134 7) Remaining battery life (time units):
1135 Number of remaining minutes or seconds
1136 -1: Unknown
1137 8) min = minutes; sec = seconds */
1139 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1140 driver_version,
1141 (apm_bios_info.version >> 8) & 0xff,
1142 apm_bios_info.version & 0xff,
1143 apm_bios_info.flags,
1144 ac_line_status,
1145 battery_status,
1146 battery_flag,
1147 percentage,
1148 time_units,
1149 units);
1151 return p - buf;
1153 #endif
1155 __initfunc(void apm_bios_init(void))
1157 unsigned short bx;
1158 unsigned short cx;
1159 unsigned short dx;
1160 unsigned short error;
1161 char * power_stat;
1162 char * bat_stat;
1163 static struct proc_dir_entry *ent;
1165 #ifdef __SMP__
1166 if (smp_num_cpus > 1) {
1167 printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n");
1168 return;
1170 #endif
1171 if (apm_bios_info.version == 0) {
1172 printk(KERN_INFO "APM BIOS not found.\n");
1173 return;
1175 printk(KERN_INFO "APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n",
1176 ((apm_bios_info.version >> 8) & 0xff) + '0',
1177 (apm_bios_info.version & 0xff) + '0',
1178 apm_bios_info.flags,
1179 driver_version);
1180 if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
1181 printk(KERN_INFO " No 32 bit BIOS support\n");
1182 return;
1186 * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
1187 * but is reportedly a 1.0 BIOS.
1189 if (apm_bios_info.version == 0x001)
1190 apm_bios_info.version = 0x100;
1192 /* BIOS < 1.2 doesn't set cseg_16_len */
1193 if (apm_bios_info.version < 0x102)
1194 apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */
1196 printk(KERN_INFO " Entry %x:%lx cseg16 %x dseg %x",
1197 apm_bios_info.cseg, apm_bios_info.offset,
1198 apm_bios_info.cseg_16, apm_bios_info.dseg);
1199 if (apm_bios_info.version > 0x100)
1200 printk(" cseg len %x, cseg16 len %x, dseg len %x",
1201 apm_bios_info.cseg_len, apm_bios_info.cseg_16_len,
1202 apm_bios_info.dseg_len);
1203 printk("\n");
1206 * Set up a segment that references the real mode segment 0x40
1207 * that extends up to the end of page zero (that we have reserved).
1208 * This is for buggy BIOS's that refer to (real mode) segment 0x40
1209 * even though they are called in protected mode.
1211 set_base(gdt[APM_40 >> 3],
1212 __va((unsigned long)0x40 << 4));
1213 set_limit(gdt[APM_40 >> 3], 4096 - (0x40 << 4));
1215 apm_bios_entry.offset = apm_bios_info.offset;
1216 apm_bios_entry.segment = APM_CS;
1217 set_base(gdt[APM_CS >> 3],
1218 __va((unsigned long)apm_bios_info.cseg << 4));
1219 set_base(gdt[APM_CS_16 >> 3],
1220 __va((unsigned long)apm_bios_info.cseg_16 << 4));
1221 set_base(gdt[APM_DS >> 3],
1222 __va((unsigned long)apm_bios_info.dseg << 4));
1223 if (apm_bios_info.version == 0x100) {
1224 set_limit(gdt[APM_CS >> 3], 64 * 1024);
1225 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1226 set_limit(gdt[APM_DS >> 3], 64 * 1024);
1227 } else {
1228 #ifdef APM_RELAX_SEGMENTS
1229 /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
1230 set_limit(gdt[APM_CS >> 3], 64 * 1024);
1231 /* For some unknown machine. */
1232 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1233 /* For the DEC Hinote Ultra CT475 (and others?) */
1234 set_limit(gdt[APM_DS >> 3], 64 * 1024);
1235 #else
1236 set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
1237 set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len);
1238 set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
1239 #endif
1240 /* The APM 1.2 docs state that the apm_driver_version
1241 * call can fail if we try to connect as 1.2 to a 1.1 bios.
1243 apm_bios_info.version = 0x0102;
1244 error = apm_driver_version(&apm_bios_info.version);
1245 if (error != 0) { /* Fall back to an APM 1.1 connection. */
1246 apm_bios_info.version = 0x0101;
1247 error = apm_driver_version(&apm_bios_info.version);
1249 if (error != 0) /* Fall back to an APM 1.0 connection. */
1250 apm_bios_info.version = 0x100;
1251 else {
1252 apm_engage_power_management(0x0001);
1253 printk( " Connection version %d.%d\n",
1254 (apm_bios_info.version >> 8) & 0xff,
1255 apm_bios_info.version & 0xff );
1259 error = apm_get_power_status(&bx, &cx, &dx);
1260 if (error)
1261 printk(KERN_INFO " Power status not available\n");
1262 else {
1263 switch ((bx >> 8) & 0xff) {
1264 case 0: power_stat = "off line"; break;
1265 case 1: power_stat = "on line"; break;
1266 case 2: power_stat = "on backup power"; break;
1267 default: power_stat = "unknown"; break;
1269 switch (bx & 0xff) {
1270 case 0: bat_stat = "high"; break;
1271 case 1: bat_stat = "low"; break;
1272 case 2: bat_stat = "critical"; break;
1273 case 3: bat_stat = "charging"; break;
1274 default: bat_stat = "unknown"; break;
1276 printk(KERN_INFO " AC %s, battery status %s, battery life ",
1277 power_stat, bat_stat);
1278 if ((cx & 0xff) == 0xff)
1279 printk("unknown\n");
1280 else
1281 printk("%d%%\n", cx & 0xff);
1282 if (apm_bios_info.version > 0x100) {
1283 printk(" battery flag 0x%02x, battery life ",
1284 (cx >> 8) & 0xff);
1285 if (dx == 0xffff)
1286 printk("unknown\n");
1287 else {
1288 if ((dx & 0x8000))
1289 printk("%d minutes\n", dx & 0x7ffe );
1290 else
1291 printk("%d seconds\n", dx & 0x7fff );
1296 #ifdef CONFIG_APM_DO_ENABLE
1298 * This call causes my NEC UltraLite Versa 33/C to hang if it is
1299 * booted with PM disabled but not in the docking station.
1300 * Unfortunate ...
1302 error = apm_enable_power_management();
1303 if (error)
1304 apm_error("enable power management", error);
1305 if (error == APM_DISABLED)
1306 return;
1307 #endif
1309 init_timer(&apm_timer);
1310 apm_timer.function = do_apm_timer;
1311 apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
1312 add_timer(&apm_timer);
1314 #ifdef CONFIG_PROC_FS
1315 ent = create_proc_entry("apm", 0, 0);
1316 ent->get_info = apm_get_info;
1317 #endif
1319 misc_register(&apm_device);
1321 apm_enabled = 1;