- Stephen Rothwell: APM updates
[davej-history.git] / arch / i386 / kernel / apm.c
blob9703e33044c49e87d0da0179a7b0e92b49018ede
1 /* -*- linux-c -*-
2 * APM BIOS driver for Linux
3 * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com)
5 * Initial development of this driver was funded by NEC Australia P/L
6 * and NEC Corporation
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
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
31 * Aug 1998, Version 1.5
32 * Sep 1998, Version 1.6
33 * Nov 1998, Version 1.7
34 * Jan 1999, Version 1.8
35 * Jan 1999, Version 1.9
36 * Oct 1999, Version 1.10
37 * Nov 1999, Version 1.11
38 * Jan 2000, Version 1.12
39 * Feb 2000, Version 1.13
40 * Nov 2000, Version 1.14
42 * History:
43 * 0.6b: first version in official kernel, Linux 1.3.46
44 * 0.7: changed /proc/apm format, Linux 1.3.58
45 * 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
46 * 0.9: only call bios if bios is present, Linux 1.3.72
47 * 1.0: use fixed device number, consolidate /proc/apm into this file,
48 * Linux 1.3.85
49 * 1.1: support user-space standby and suspend, power off after system
50 * halted, Linux 1.3.98
51 * 1.2: When resetting RTC after resume, take care so that the time
52 * is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
53 * <jtoth@princeton.edu>); improve interaction between
54 * screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
55 * 1.2a:Simple change to stop mysterious bug reports with SMP also added
56 * levels to the printk calls. APM is not defined for SMP machines.
57 * The new replacment for it is, but Linux doesn't yet support this.
58 * Alan Cox Linux 2.1.55
59 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
60 * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
61 * Dean Gaudet <dgaudet@arctic.org>.
62 * C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
63 * 1.5: Fix segment register reloading (in case of bad segments saved
64 * across BIOS call).
65 * Stephen Rothwell
66 * 1.6: Cope with complier/assembler differences.
67 * Only try to turn off the first display device.
68 * Fix OOPS at power off with no APM BIOS by Jan Echternach
69 * <echter@informatik.uni-rostock.de>
70 * Stephen Rothwell
71 * 1.7: Modify driver's cached copy of the disabled/disengaged flags
72 * to reflect current state of APM BIOS.
73 * Chris Rankin <rankinc@bellsouth.net>
74 * Reset interrupt 0 timer to 100Hz after suspend
75 * Chad Miller <cmiller@surfsouth.com>
76 * Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE
77 * Richard Gooch <rgooch@atnf.csiro.au>
78 * Allow boot time disabling of APM
79 * Make boot messages far less verbose by default
80 * Make asm safer
81 * Stephen Rothwell
82 * 1.8: Add CONFIG_APM_RTC_IS_GMT
83 * Richard Gooch <rgooch@atnf.csiro.au>
84 * change APM_NOINTS to CONFIG_APM_ALLOW_INTS
85 * remove dependency on CONFIG_PROC_FS
86 * Stephen Rothwell
87 * 1.9: Fix small typo. <laslo@ilo.opole.pl>
88 * Try to cope with BIOS's that need to have all display
89 * devices blanked and not just the first one.
90 * Ross Paterson <ross@soi.city.ac.uk>
91 * Fix segment limit setting it has always been wrong as
92 * the segments needed to have byte granularity.
93 * Mark a few things __init.
94 * Add hack to allow power off of SMP systems by popular request.
95 * Use CONFIG_SMP instead of __SMP__
96 * Ignore BOUNCES for three seconds.
97 * Stephen Rothwell
98 * 1.10: Fix for Thinkpad return code.
99 * Merge 2.2 and 2.3 drivers.
100 * Remove APM dependencies in arch/i386/kernel/process.c
101 * Remove APM dependencies in drivers/char/sysrq.c
102 * Reset time across standby.
103 * Allow more inititialisation on SMP.
104 * Remove CONFIG_APM_POWER_OFF and make it boot time
105 * configurable (default on).
106 * Make debug only a boot time parameter (remove APM_DEBUG).
107 * Try to blank all devices on any error.
108 * 1.11: Remove APM dependencies in drivers/char/console.c
109 * Check nr_running to detect if we are idle (from
110 * Borislav Deianov <borislav@lix.polytechnique.fr>)
111 * Fix for bioses that don't zero the top part of the
112 * entrypoint offset (Mario Sitta <sitta@al.unipmn.it>)
113 * (reported by Panos Katsaloulis <teras@writeme.com>).
114 * Real mode power off patch (Walter Hofmann
115 * <Walter.Hofmann@physik.stud.uni-erlangen.de>).
116 * 1.12: Remove CONFIG_SMP as the compiler will optimize
117 * the code away anyway (smp_num_cpus == 1 in UP)
118 * noted by Artur Skawina <skawina@geocities.com>.
119 * Make power off under SMP work again.
120 * Fix thinko with initial engaging of BIOS.
121 * Make sure power off only happens on CPU 0
122 * (Paul "Rusty" Russell <rusty@linuxcare.com>).
123 * Do error notification to user mode if BIOS calls fail.
124 * Move entrypoint offset fix to ...boot/setup.S
125 * where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>).
126 * Remove smp-power-off. SMP users must now specify
127 * "apm=power-off" on the kernel command line. Suggested
128 * by Jim Avera <jima@hal.com>, modified by Alan Cox
129 * <alan@lxorguk.ukuu.org.uk>.
130 * Register the /proc/apm entry even on SMP so that
131 * scripts that check for it before doing power off
132 * work (Jim Avera <jima@hal.com>).
133 * 1.13: Changes for new pm_ interfaces (Andy Henroid
134 * <andy_henroid@yahoo.com>).
135 * Modularize the code.
136 * Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS
137 * is now the way life works).
138 * Fix thinko in suspend() (wrong return).
139 * Notify drivers on critical suspend.
140 * Make kapmd absorb more idle time (Pavel Machek <pavel@suse.cz>
141 * modified by sfr).
142 * Disable interrupts while we are suspended (Andy Henroid
143 * <andy_henroid@yahoo.com> fixed by sfr).
144 * Make power off work on SMP again (Tony Hoyle
145 * <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr.
146 * Remove CONFIG_APM_SUSPEND_BOUNCE. The bounce ignore
147 * interval is now configurable.
148 * 1.14: Make connection version persist across module unload/load.
149 * Enable and engage power management earlier.
150 * Disengage power management on module unload.
152 * APM 1.1 Reference:
154 * Intel Corporation, Microsoft Corporation. Advanced Power Management
155 * (APM) BIOS Interface Specification, Revision 1.1, September 1993.
156 * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
158 * [This document is available free from Intel by calling 800.628.8686 (fax
159 * 916.356.6100) or 800.548.4725; or via anonymous ftp from
160 * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
161 * available from Microsoft by calling 206.882.8080.]
163 * APM 1.2 Reference:
164 * Intel Corporation, Microsoft Corporation. Advanced Power Management
165 * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
167 * [This document is available from Microsoft at:
168 * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
171 #include <linux/config.h>
172 #include <linux/module.h>
174 #include <linux/poll.h>
175 #include <linux/types.h>
176 #include <linux/stddef.h>
177 #include <linux/timer.h>
178 #include <linux/fcntl.h>
179 #include <linux/malloc.h>
180 #include <linux/stat.h>
181 #include <linux/proc_fs.h>
182 #include <linux/miscdevice.h>
183 #include <linux/apm_bios.h>
184 #include <linux/init.h>
185 #include <linux/sched.h>
186 #include <linux/pm.h>
187 #include <linux/kernel.h>
188 #include <linux/smp_lock.h>
190 #include <asm/system.h>
191 #include <asm/uaccess.h>
192 #include <asm/desc.h>
194 extern unsigned long get_cmos_time(void);
195 extern void machine_real_restart(unsigned char *, int);
197 #ifdef CONFIG_MAGIC_SYSRQ
198 extern void (*sysrq_power_off)(void);
199 #endif
200 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
201 extern int (*console_blank_hook)(int);
202 #endif
205 * The apm_bios device is one of the misc char devices.
206 * This is its minor number.
208 #define APM_MINOR_DEV 134
211 * See Documentation/Config.help for the configuration options.
213 * Various options can be changed at boot time as follows:
214 * (We allow underscores for compatibility with the modules code)
215 * apm=on/off enable/disable APM
216 * [no-]debug log some debugging messages
217 * [no-]power[-_]off power off on shutdown
220 /* KNOWN PROBLEM MACHINES:
222 * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
223 * [Confirmed by TI representative]
224 * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
225 * [Confirmed by BIOS disassembly]
226 * [This may work now ...]
227 * P: Toshiba 1950S: battery life information only gets updated after resume
228 * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
229 * broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
231 * Legend: U = unusable with APM patches
232 * P = partially usable with APM patches
236 * Define to always call the APM BIOS busy routine even if the clock was
237 * not slowed by the idle routine.
239 #define ALWAYS_CALL_BUSY
242 * Define to make the APM BIOS calls zero all data segment registers (so
243 * that an incorrect BIOS implementation will cause a kernel panic if it
244 * tries to write to arbitrary memory).
246 #define APM_ZERO_SEGS
249 * Define to make all _set_limit calls use 64k limits. The APM 1.1 BIOS is
250 * supposed to provide limit information that it recognizes. Many machines
251 * do this correctly, but many others do not restrict themselves to their
252 * claimed limit. When this happens, they will cause a segmentation
253 * violation in the kernel at boot time. Most BIOS's, however, will
254 * respect a 64k limit, so we use that. If you want to be pedantic and
255 * hold your BIOS to its claims, then undefine this.
257 #define APM_RELAX_SEGMENTS
260 * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
261 * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
262 * David Chen <chen@ctpa04.mit.edu>
264 #undef INIT_TIMER_AFTER_SUSPEND
266 #ifdef INIT_TIMER_AFTER_SUSPEND
267 #include <linux/timex.h>
268 #include <asm/io.h>
269 #include <linux/delay.h>
270 #endif
273 * Need to poll the APM BIOS every second
275 #define APM_CHECK_TIMEOUT (HZ)
278 * Ignore suspend events for this amount of time after a resume
280 #define DEFAULT_BOUNCE_INTERVAL (3 * HZ)
283 * Save a segment register away
285 #define savesegment(seg, where) \
286 __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
289 * Maximum number of events stored
291 #define APM_MAX_EVENTS 20
294 * The per-file APM data
296 struct apm_user {
297 int magic;
298 struct apm_user * next;
299 int suser: 1;
300 int suspend_wait: 1;
301 int suspend_result;
302 int suspends_pending;
303 int standbys_pending;
304 int suspends_read;
305 int standbys_read;
306 int event_head;
307 int event_tail;
308 apm_event_t events[APM_MAX_EVENTS];
312 * The magic number in apm_user
314 #define APM_BIOS_MAGIC 0x4101
317 * Local variables
319 static struct {
320 unsigned long offset;
321 unsigned short segment;
322 } apm_bios_entry;
323 #ifdef CONFIG_APM_CPU_IDLE
324 static int clock_slowed;
325 #endif
326 static int suspends_pending;
327 static int standbys_pending;
328 static int waiting_for_resume;
329 static int ignore_normal_resume;
330 static int bounce_interval = DEFAULT_BOUNCE_INTERVAL;
332 #ifdef CONFIG_APM_RTC_IS_GMT
333 # define clock_cmos_diff 0
334 # define got_clock_diff 1
335 #else
336 static long clock_cmos_diff;
337 static int got_clock_diff;
338 #endif
339 static int debug;
340 static int apm_disabled;
341 #ifdef CONFIG_SMP
342 static int power_off;
343 #else
344 static int power_off = 1;
345 #endif
346 static int exit_kapmd;
347 static int kapmd_running;
349 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
350 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
351 static struct apm_user * user_list;
353 static char driver_version[] = "1.14"; /* no spaces */
355 static char * apm_event_name[] = {
356 "system standby",
357 "system suspend",
358 "normal resume",
359 "critical resume",
360 "low battery",
361 "power status change",
362 "update time",
363 "critical suspend",
364 "user standby",
365 "user suspend",
366 "system standby resume",
367 "capabilities change"
369 #define NR_APM_EVENT_NAME \
370 (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
372 typedef struct lookup_t {
373 int key;
374 char * msg;
375 } lookup_t;
377 static const lookup_t error_table[] = {
378 /* N/A { APM_SUCCESS, "Operation succeeded" }, */
379 { APM_DISABLED, "Power management disabled" },
380 { APM_CONNECTED, "Real mode interface already connected" },
381 { APM_NOT_CONNECTED, "Interface not connected" },
382 { APM_16_CONNECTED, "16 bit interface already connected" },
383 /* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
384 { APM_32_CONNECTED, "32 bit interface already connected" },
385 { APM_32_UNSUPPORTED, "32 bit interface not supported" },
386 { APM_BAD_DEVICE, "Unrecognized device ID" },
387 { APM_BAD_PARAM, "Parameter out of range" },
388 { APM_NOT_ENGAGED, "Interface not engaged" },
389 { APM_BAD_FUNCTION, "Function not supported" },
390 { APM_RESUME_DISABLED, "Resume timer disabled" },
391 { APM_BAD_STATE, "Unable to enter requested state" },
392 /* N/A { APM_NO_EVENTS, "No events pending" }, */
393 { APM_NO_ERROR, "BIOS did not set a return code" },
394 { APM_NOT_PRESENT, "No APM present" }
396 #define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
399 * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and
400 * CONFIG_APM_ALLOW_INTS, we are being really paranoid here! Not only
401 * are interrupts disabled, but all the segment registers (except SS)
402 * are saved and zeroed this means that if the BIOS tries to reference
403 * any data without explicitly loading the segment registers, the kernel
404 * will fault immediately rather than have some unforeseen circumstances
405 * for the rest of the kernel. And it will be very obvious! :-) Doing
406 * this depends on CS referring to the same physical memory as DS so that
407 * DS can be zeroed before the call. Unfortunately, we can't do anything
408 * about the stack segment/pointer. Also, we tell the compiler that
409 * everything could change.
411 * Also, we KNOW that for the non error case of apm_bios_call, there
412 * is no useful data returned in the low order 8 bits of eax.
414 #ifndef CONFIG_APM_ALLOW_INTS
415 # define APM_DO_CLI __cli()
416 #else
417 # define APM_DO_CLI __sti()
418 #endif
419 #ifdef APM_ZERO_SEGS
420 # define APM_DECL_SEGS \
421 unsigned int saved_fs; unsigned int saved_gs;
422 # define APM_DO_SAVE_SEGS \
423 savesegment(fs, saved_fs); savesegment(gs, saved_gs)
424 # define APM_DO_ZERO_SEGS \
425 "pushl %%ds\n\t" \
426 "pushl %%es\n\t" \
427 "xorl %%edx, %%edx\n\t" \
428 "mov %%dx, %%ds\n\t" \
429 "mov %%dx, %%es\n\t" \
430 "mov %%dx, %%fs\n\t" \
431 "mov %%dx, %%gs\n\t"
432 # define APM_DO_POP_SEGS \
433 "popl %%es\n\t" \
434 "popl %%ds\n\t"
435 # define APM_DO_RESTORE_SEGS \
436 loadsegment(fs, saved_fs); loadsegment(gs, saved_gs)
437 #else
438 # define APM_DECL_SEGS
439 # define APM_DO_SAVE_SEGS
440 # define APM_DO_ZERO_SEGS
441 # define APM_DO_POP_SEGS
442 # define APM_DO_RESTORE_SEGS
443 #endif
445 static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
446 u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
448 APM_DECL_SEGS
449 unsigned long flags;
451 __save_flags(flags);
452 APM_DO_CLI;
453 APM_DO_SAVE_SEGS;
455 * N.B. We do NOT need a cld after the BIOS call
456 * because we always save and restore the flags.
458 __asm__ __volatile__(APM_DO_ZERO_SEGS
459 "pushl %%edi\n\t"
460 "pushl %%ebp\n\t"
461 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
462 "setc %%al\n\t"
463 "popl %%ebp\n\t"
464 "popl %%edi\n\t"
465 APM_DO_POP_SEGS
466 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
467 "=S" (*esi)
468 : "a" (func), "b" (ebx_in), "c" (ecx_in)
469 : "memory", "cc");
470 APM_DO_RESTORE_SEGS;
471 __restore_flags(flags);
472 return *eax & 0xff;
476 * This version only returns one value (usually an error code)
479 static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
481 u8 error;
482 APM_DECL_SEGS
483 unsigned long flags;
485 __save_flags(flags);
486 APM_DO_CLI;
487 APM_DO_SAVE_SEGS;
489 int cx, dx, si;
492 * N.B. We do NOT need a cld after the BIOS call
493 * because we always save and restore the flags.
495 __asm__ __volatile__(APM_DO_ZERO_SEGS
496 "pushl %%edi\n\t"
497 "pushl %%ebp\n\t"
498 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
499 "setc %%bl\n\t"
500 "popl %%ebp\n\t"
501 "popl %%edi\n\t"
502 APM_DO_POP_SEGS
503 : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
504 "=S" (si)
505 : "a" (func), "b" (ebx_in), "c" (ecx_in)
506 : "memory", "cc");
508 APM_DO_RESTORE_SEGS;
509 __restore_flags(flags);
510 return error;
513 static int __init apm_driver_version(u_short *val)
515 u32 eax;
517 if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax))
518 return (eax >> 8) & 0xff;
519 *val = eax;
520 return APM_SUCCESS;
523 static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
525 u32 eax;
526 u32 ebx;
527 u32 ecx;
528 u32 dummy;
530 if (apm_bios_call(APM_FUNC_GET_EVENT, 0, 0, &eax, &ebx, &ecx,
531 &dummy, &dummy))
532 return (eax >> 8) & 0xff;
533 *event = ebx;
534 if (apm_info.connection_version < 0x0102)
535 *info = ~0; /* indicate info not valid */
536 else
537 *info = ecx;
538 return APM_SUCCESS;
541 static int set_power_state(u_short what, u_short state)
543 u32 eax;
545 if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax))
546 return (eax >> 8) & 0xff;
547 return APM_SUCCESS;
550 static int apm_set_power_state(u_short state)
552 return set_power_state(APM_DEVICE_ALL, state);
555 #ifdef CONFIG_APM_CPU_IDLE
556 static int apm_do_idle(void)
558 u32 dummy;
560 if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &dummy))
561 return 0;
563 #ifdef ALWAYS_CALL_BUSY
564 clock_slowed = 1;
565 #else
566 clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
567 #endif
568 return 1;
571 static void apm_do_busy(void)
573 u32 dummy;
575 if (clock_slowed) {
576 (void) apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy);
577 clock_slowed = 0;
581 #if 0
582 extern int hlt_counter;
585 * If no process has been interested in this
586 * CPU for some time, we want to wake up the
587 * power management thread - we probably want
588 * to conserve power.
590 #define HARD_IDLE_TIMEOUT (HZ/3)
592 /* This should wake up kapmd and ask it to slow the CPU */
593 #define powermanagement_idle() do { } while (0)
596 * This is the idle thing.
598 static void apm_cpu_idle(void)
600 unsigned int start_idle;
602 start_idle = jiffies;
603 while (1) {
604 if (!current->need_resched) {
605 if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
606 if (!current_cpu_data.hlt_works_ok)
607 continue;
608 if (hlt_counter)
609 continue;
610 __cli();
611 if (!current->need_resched)
612 safe_halt();
613 else
614 __sti();
615 continue;
619 * Ok, do some power management - we've been idle for too long
621 powermanagement_idle();
624 schedule();
625 check_pgt_cache();
626 start_idle = jiffies;
629 #endif
630 #endif
632 #ifdef CONFIG_SMP
633 static int apm_magic(void * unused)
635 while (1)
636 schedule();
638 #endif
640 static void apm_power_off(void)
642 #ifdef CONFIG_APM_REAL_MODE_POWER_OFF
643 unsigned char po_bios_call[] = {
644 0xb8, 0x00, 0x10, /* movw $0x1000,ax */
645 0x8e, 0xd0, /* movw ax,ss */
646 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */
647 0xb8, 0x07, 0x53, /* movw $0x5307,ax */
648 0xbb, 0x01, 0x00, /* movw $0x0001,bx */
649 0xb9, 0x03, 0x00, /* movw $0x0003,cx */
650 0xcd, 0x15 /* int $0x15 */
652 #endif
655 * This may be called on an SMP machine.
657 #ifdef CONFIG_SMP
658 /* Some bioses don't like being called from CPU != 0 */
659 while (cpu_number_map(smp_processor_id()) != 0) {
660 kernel_thread(apm_magic, NULL,
661 CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
662 schedule();
664 #endif
665 #ifdef CONFIG_APM_REAL_MODE_POWER_OFF
666 machine_real_restart(po_bios_call, sizeof(po_bios_call));
667 #else
668 (void) apm_set_power_state(APM_STATE_OFF);
669 #endif
672 #ifdef CONFIG_APM_DO_ENABLE
673 static int apm_enable_power_management(int enable)
675 u32 eax;
677 if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
678 return APM_NOT_ENGAGED;
679 if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
680 enable, &eax))
681 return (eax >> 8) & 0xff;
682 if (enable)
683 apm_info.bios.flags &= ~APM_BIOS_DISABLED;
684 else
685 apm_info.bios.flags |= APM_BIOS_DISABLED;
686 return APM_SUCCESS;
688 #endif
690 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
692 u32 eax;
693 u32 ebx;
694 u32 ecx;
695 u32 edx;
696 u32 dummy;
698 if (apm_info.get_power_status_broken)
699 return APM_32_UNSUPPORTED;
700 if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
701 &eax, &ebx, &ecx, &edx, &dummy))
702 return (eax >> 8) & 0xff;
703 *status = ebx;
704 *bat = ecx;
705 *life = edx;
706 return APM_SUCCESS;
709 #if 0
710 static int apm_get_battery_status(u_short which, u_short *status,
711 u_short *bat, u_short *life, u_short *nbat)
713 u32 eax;
714 u32 ebx;
715 u32 ecx;
716 u32 edx;
717 u32 esi;
719 if (apm_info.connection_version < 0x0102) {
720 /* pretend we only have one battery. */
721 if (which != 1)
722 return APM_BAD_DEVICE;
723 *nbat = 1;
724 return apm_get_power_status(status, bat, life);
727 if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
728 &ebx, &ecx, &edx, &esi))
729 return (eax >> 8) & 0xff;
730 *status = ebx;
731 *bat = ecx;
732 *life = edx;
733 *nbat = esi;
734 return APM_SUCCESS;
736 #endif
738 static int apm_engage_power_management(u_short device, int enable)
740 u32 eax;
742 if ((enable == 0) && (device == APM_DEVICE_ALL)
743 && (apm_info.bios.flags & APM_BIOS_DISABLED))
744 return APM_DISABLED;
745 if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
746 return (eax >> 8) & 0xff;
747 if (device == APM_DEVICE_ALL) {
748 if (enable)
749 apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
750 else
751 apm_info.bios.flags |= APM_BIOS_DISENGAGED;
753 return APM_SUCCESS;
756 static void apm_error(char *str, int err)
758 int i;
760 for (i = 0; i < ERROR_COUNT; i++)
761 if (error_table[i].key == err) break;
762 if (i < ERROR_COUNT)
763 printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
764 else
765 printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
766 str, err);
769 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
770 static int apm_console_blank(int blank)
772 int error;
773 u_short state;
775 state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
776 /* Blank the first display device */
777 error = set_power_state(0x100, state);
778 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
779 /* try to blank them all instead */
780 error = set_power_state(0x1ff, state);
781 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
782 /* try to blank device one instead */
783 error = set_power_state(0x101, state);
785 if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
786 return 1;
787 apm_error("set display", error);
788 return 0;
790 #endif
792 static int queue_empty(struct apm_user *as)
794 return as->event_head == as->event_tail;
797 static apm_event_t get_queued_event(struct apm_user *as)
799 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
800 return as->events[as->event_tail];
803 static void queue_event(apm_event_t event, struct apm_user *sender)
805 struct apm_user * as;
807 if (user_list == NULL)
808 return;
809 for (as = user_list; as != NULL; as = as->next) {
810 if (as == sender)
811 continue;
812 as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
813 if (as->event_head == as->event_tail) {
814 static int notified;
816 if (notified++ == 0)
817 printk(KERN_ERR "apm: an event queue overflowed\n");
818 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
820 as->events[as->event_head] = event;
821 if (!as->suser)
822 continue;
823 switch (event) {
824 case APM_SYS_SUSPEND:
825 case APM_USER_SUSPEND:
826 as->suspends_pending++;
827 suspends_pending++;
828 break;
830 case APM_SYS_STANDBY:
831 case APM_USER_STANDBY:
832 as->standbys_pending++;
833 standbys_pending++;
834 break;
837 wake_up_interruptible(&apm_waitqueue);
840 static void set_time(void)
842 unsigned long flags;
844 if (got_clock_diff) { /* Must know time zone in order to set clock */
845 save_flags(flags);
846 cli();
847 CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
848 restore_flags(flags);
852 static void get_time_diff(void)
854 #ifndef CONFIG_APM_RTC_IS_GMT
855 unsigned long flags;
858 * Estimate time zone so that set_time can update the clock
860 save_flags(flags);
861 clock_cmos_diff = -get_cmos_time();
862 cli();
863 clock_cmos_diff += CURRENT_TIME;
864 got_clock_diff = 1;
865 restore_flags(flags);
866 #endif
869 static void reinit_timer(void)
871 #ifdef INIT_TIMER_AFTER_SUSPEND
872 unsigned long flags;
874 save_flags(flags);
875 cli();
876 /* set the clock to 100 Hz */
877 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
878 udelay(10);
879 outb_p(LATCH & 0xff , 0x40); /* LSB */
880 udelay(10);
881 outb(LATCH >> 8 , 0x40); /* MSB */
882 udelay(10);
883 restore_flags(flags);
884 #endif
887 static int send_event(apm_event_t event)
889 switch (event) {
890 case APM_SYS_SUSPEND:
891 case APM_CRITICAL_SUSPEND:
892 case APM_USER_SUSPEND:
893 /* map all suspends to ACPI D3 */
894 if (pm_send_all(PM_SUSPEND, (void *)3)) {
895 if (event == APM_CRITICAL_SUSPEND) {
896 printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" );
897 return 0;
899 if (apm_info.connection_version > 0x100)
900 apm_set_power_state(APM_STATE_REJECT);
901 return 0;
903 break;
904 case APM_NORMAL_RESUME:
905 case APM_CRITICAL_RESUME:
906 /* map all resumes to ACPI D0 */
907 (void) pm_send_all(PM_RESUME, (void *)0);
908 break;
911 return 1;
914 static int suspend(void)
916 int err;
917 struct apm_user *as;
919 get_time_diff();
920 cli();
921 err = apm_set_power_state(APM_STATE_SUSPEND);
922 reinit_timer();
923 set_time();
924 if (err == APM_NO_ERROR)
925 err = APM_SUCCESS;
926 if (err != APM_SUCCESS)
927 apm_error("suspend", err);
928 send_event(APM_NORMAL_RESUME);
929 sti();
930 queue_event(APM_NORMAL_RESUME, NULL);
931 for (as = user_list; as != NULL; as = as->next) {
932 as->suspend_wait = 0;
933 as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);
935 ignore_normal_resume = 1;
936 wake_up_interruptible(&apm_suspend_waitqueue);
937 return err;
940 static void standby(void)
942 int err;
944 get_time_diff();
945 err = apm_set_power_state(APM_STATE_STANDBY);
946 if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
947 apm_error("standby", err);
950 static apm_event_t get_event(void)
952 int error;
953 apm_event_t event;
954 apm_eventinfo_t info;
956 static int notified;
958 /* we don't use the eventinfo */
959 error = apm_get_event(&event, &info);
960 if (error == APM_SUCCESS)
961 return event;
963 if ((error != APM_NO_EVENTS) && (notified++ == 0))
964 apm_error("get_event", error);
966 return 0;
969 static void check_events(void)
971 apm_event_t event;
972 static unsigned long last_resume;
973 static int ignore_bounce;
975 while ((event = get_event()) != 0) {
976 if (debug) {
977 if (event <= NR_APM_EVENT_NAME)
978 printk(KERN_DEBUG "apm: received %s notify\n",
979 apm_event_name[event - 1]);
980 else
981 printk(KERN_DEBUG "apm: received unknown "
982 "event 0x%02x\n", event);
984 if (ignore_bounce
985 && ((jiffies - last_resume) > bounce_interval))
986 ignore_bounce = 0;
987 if (ignore_normal_resume && (event != APM_NORMAL_RESUME))
988 ignore_normal_resume = 0;
990 switch (event) {
991 case APM_SYS_STANDBY:
992 case APM_USER_STANDBY:
993 if (send_event(event)) {
994 queue_event(event, NULL);
995 if (standbys_pending <= 0)
996 standby();
998 break;
1000 case APM_USER_SUSPEND:
1001 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
1002 if (apm_info.connection_version > 0x100)
1003 apm_set_power_state(APM_STATE_REJECT);
1004 break;
1005 #endif
1006 case APM_SYS_SUSPEND:
1007 if (ignore_bounce) {
1008 if (apm_info.connection_version > 0x100)
1009 apm_set_power_state(APM_STATE_REJECT);
1010 break;
1013 * If we are already processing a SUSPEND,
1014 * then further SUSPEND events from the BIOS
1015 * will be ignored. We also return here to
1016 * cope with the fact that the Thinkpads keep
1017 * sending a SUSPEND event until something else
1018 * happens!
1020 if (waiting_for_resume)
1021 return;
1022 if (send_event(event)) {
1023 queue_event(event, NULL);
1024 waiting_for_resume = 1;
1025 if (suspends_pending <= 0)
1026 (void) suspend();
1028 break;
1030 case APM_NORMAL_RESUME:
1031 case APM_CRITICAL_RESUME:
1032 case APM_STANDBY_RESUME:
1033 waiting_for_resume = 0;
1034 last_resume = jiffies;
1035 ignore_bounce = 1;
1036 if ((event != APM_NORMAL_RESUME)
1037 || (ignore_normal_resume == 0)) {
1038 set_time();
1039 send_event(event);
1040 queue_event(event, NULL);
1042 break;
1044 case APM_CAPABILITY_CHANGE:
1045 case APM_LOW_BATTERY:
1046 case APM_POWER_STATUS_CHANGE:
1047 send_event(event);
1048 queue_event(event, NULL);
1049 break;
1051 case APM_UPDATE_TIME:
1052 set_time();
1053 break;
1055 case APM_CRITICAL_SUSPEND:
1056 send_event(event);
1058 * We can only hope it worked - we are not allowed
1059 * to reject a critical suspend.
1061 (void) suspend();
1062 break;
1067 static void apm_event_handler(void)
1069 static int pending_count = 4;
1070 int err;
1072 if ((standbys_pending > 0) || (suspends_pending > 0)) {
1073 if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {
1074 pending_count = 4;
1075 if (debug)
1076 printk(KERN_DEBUG "apm: setting state busy\n");
1077 err = apm_set_power_state(APM_STATE_BUSY);
1078 if (err)
1079 apm_error("busy", err);
1081 } else
1082 pending_count = 4;
1083 check_events();
1087 * This is the APM thread main loop.
1089 * Check whether we're the only running process to
1090 * decide if we should just power down.
1093 #define system_idle() (nr_running == 1)
1095 static void apm_mainloop(void)
1097 int timeout = HZ;
1098 DECLARE_WAITQUEUE(wait, current);
1100 add_wait_queue(&apm_waitqueue, &wait);
1101 set_current_state(TASK_INTERRUPTIBLE);
1102 for (;;) {
1103 /* Nothing to do, just sleep for the timeout */
1104 timeout = 2*timeout;
1105 if (timeout > APM_CHECK_TIMEOUT)
1106 timeout = APM_CHECK_TIMEOUT;
1107 schedule_timeout(timeout);
1108 if (exit_kapmd)
1109 break;
1112 * Ok, check all events, check for idle (and mark us sleeping
1113 * so as not to count towards the load average)..
1115 set_current_state(TASK_INTERRUPTIBLE);
1116 apm_event_handler();
1117 #ifdef CONFIG_APM_CPU_IDLE
1118 if (!system_idle())
1119 continue;
1120 if (apm_do_idle()) {
1121 unsigned long start = jiffies;
1122 while ((!exit_kapmd) && system_idle()) {
1123 apm_do_idle();
1124 if ((jiffies - start) > APM_CHECK_TIMEOUT) {
1125 apm_event_handler();
1126 start = jiffies;
1129 apm_do_busy();
1130 apm_event_handler();
1131 timeout = 1;
1133 #endif
1135 remove_wait_queue(&apm_waitqueue, &wait);
1138 static int check_apm_user(struct apm_user *as, const char *func)
1140 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
1141 printk(KERN_ERR "apm: %s passed bad filp\n", func);
1142 return 1;
1144 return 0;
1147 static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
1149 struct apm_user * as;
1150 int i;
1151 apm_event_t event;
1152 DECLARE_WAITQUEUE(wait, current);
1154 as = fp->private_data;
1155 if (check_apm_user(as, "read"))
1156 return -EIO;
1157 if (count < sizeof(apm_event_t))
1158 return -EINVAL;
1159 if (queue_empty(as)) {
1160 if (fp->f_flags & O_NONBLOCK)
1161 return -EAGAIN;
1162 add_wait_queue(&apm_waitqueue, &wait);
1163 repeat:
1164 set_current_state(TASK_INTERRUPTIBLE);
1165 if (queue_empty(as) && !signal_pending(current)) {
1166 schedule();
1167 goto repeat;
1169 set_current_state(TASK_RUNNING);
1170 remove_wait_queue(&apm_waitqueue, &wait);
1172 i = count;
1173 while ((i >= sizeof(event)) && !queue_empty(as)) {
1174 event = get_queued_event(as);
1175 if (copy_to_user(buf, &event, sizeof(event))) {
1176 if (i < count)
1177 break;
1178 return -EFAULT;
1180 switch (event) {
1181 case APM_SYS_SUSPEND:
1182 case APM_USER_SUSPEND:
1183 as->suspends_read++;
1184 break;
1186 case APM_SYS_STANDBY:
1187 case APM_USER_STANDBY:
1188 as->standbys_read++;
1189 break;
1191 buf += sizeof(event);
1192 i -= sizeof(event);
1194 if (i < count)
1195 return count - i;
1196 if (signal_pending(current))
1197 return -ERESTARTSYS;
1198 return 0;
1201 static unsigned int do_poll(struct file *fp, poll_table * wait)
1203 struct apm_user * as;
1205 as = fp->private_data;
1206 if (check_apm_user(as, "poll"))
1207 return 0;
1208 poll_wait(fp, &apm_waitqueue, wait);
1209 if (!queue_empty(as))
1210 return POLLIN | POLLRDNORM;
1211 return 0;
1214 static int do_ioctl(struct inode * inode, struct file *filp,
1215 u_int cmd, u_long arg)
1217 struct apm_user * as;
1218 DECLARE_WAITQUEUE(wait, current);
1220 as = filp->private_data;
1221 if (check_apm_user(as, "ioctl"))
1222 return -EIO;
1223 if (!as->suser)
1224 return -EPERM;
1225 switch (cmd) {
1226 case APM_IOC_STANDBY:
1227 if (as->standbys_read > 0) {
1228 as->standbys_read--;
1229 as->standbys_pending--;
1230 standbys_pending--;
1231 } else if (!send_event(APM_USER_STANDBY))
1232 return -EAGAIN;
1233 else
1234 queue_event(APM_USER_STANDBY, as);
1235 if (standbys_pending <= 0)
1236 standby();
1237 break;
1238 case APM_IOC_SUSPEND:
1239 if (as->suspends_read > 0) {
1240 as->suspends_read--;
1241 as->suspends_pending--;
1242 suspends_pending--;
1243 } else if (!send_event(APM_USER_SUSPEND))
1244 return -EAGAIN;
1245 else
1246 queue_event(APM_USER_SUSPEND, as);
1247 if (suspends_pending <= 0) {
1248 if (suspend() != APM_SUCCESS)
1249 return -EIO;
1250 } else {
1251 as->suspend_wait = 1;
1252 add_wait_queue(&apm_suspend_waitqueue, &wait);
1253 while (1) {
1254 set_current_state(TASK_INTERRUPTIBLE);
1255 if ((as->suspend_wait == 0)
1256 || signal_pending(current))
1257 break;
1258 schedule();
1260 set_current_state(TASK_RUNNING);
1261 remove_wait_queue(&apm_suspend_waitqueue, &wait);
1262 return as->suspend_result;
1264 break;
1265 default:
1266 return -EINVAL;
1268 return 0;
1271 static int do_release(struct inode * inode, struct file * filp)
1273 struct apm_user * as;
1275 as = filp->private_data;
1276 if (check_apm_user(as, "release"))
1277 return 0;
1278 filp->private_data = NULL;
1279 lock_kernel();
1280 if (as->standbys_pending > 0) {
1281 standbys_pending -= as->standbys_pending;
1282 if (standbys_pending <= 0)
1283 standby();
1285 if (as->suspends_pending > 0) {
1286 suspends_pending -= as->suspends_pending;
1287 if (suspends_pending <= 0)
1288 (void) suspend();
1290 if (user_list == as)
1291 user_list = as->next;
1292 else {
1293 struct apm_user * as1;
1295 for (as1 = user_list;
1296 (as1 != NULL) && (as1->next != as);
1297 as1 = as1->next)
1299 if (as1 == NULL)
1300 printk(KERN_ERR "apm: filp not in user list\n");
1301 else
1302 as1->next = as->next;
1304 unlock_kernel();
1305 kfree(as);
1306 return 0;
1309 static int do_open(struct inode * inode, struct file * filp)
1311 struct apm_user * as;
1313 as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
1314 if (as == NULL) {
1315 printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
1316 sizeof(*as));
1317 return -ENOMEM;
1319 as->magic = APM_BIOS_MAGIC;
1320 as->event_tail = as->event_head = 0;
1321 as->suspends_pending = as->standbys_pending = 0;
1322 as->suspends_read = as->standbys_read = 0;
1324 * XXX - this is a tiny bit broken, when we consider BSD
1325 * process accounting. If the device is opened by root, we
1326 * instantly flag that we used superuser privs. Who knows,
1327 * we might close the device immediately without doing a
1328 * privileged operation -- cevans
1330 as->suser = capable(CAP_SYS_ADMIN);
1331 as->next = user_list;
1332 user_list = as;
1333 filp->private_data = as;
1334 return 0;
1337 static int apm_get_info(char *buf, char **start, off_t fpos, int length)
1339 char * p;
1340 unsigned short bx;
1341 unsigned short cx;
1342 unsigned short dx;
1343 int error;
1344 unsigned short ac_line_status = 0xff;
1345 unsigned short battery_status = 0xff;
1346 unsigned short battery_flag = 0xff;
1347 int percentage = -1;
1348 int time_units = -1;
1349 char *units = "?";
1351 p = buf;
1353 if ((smp_num_cpus == 1) &&
1354 !(error = apm_get_power_status(&bx, &cx, &dx))) {
1355 ac_line_status = (bx >> 8) & 0xff;
1356 battery_status = bx & 0xff;
1357 if ((cx & 0xff) != 0xff)
1358 percentage = cx & 0xff;
1360 if (apm_info.connection_version > 0x100) {
1361 battery_flag = (cx >> 8) & 0xff;
1362 if (dx != 0xffff) {
1363 units = (dx & 0x8000) ? "min" : "sec";
1364 time_units = dx & 0x7fff;
1368 /* Arguments, with symbols from linux/apm_bios.h. Information is
1369 from the Get Power Status (0x0a) call unless otherwise noted.
1371 0) Linux driver version (this will change if format changes)
1372 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
1373 2) APM flags from APM Installation Check (0x00):
1374 bit 0: APM_16_BIT_SUPPORT
1375 bit 1: APM_32_BIT_SUPPORT
1376 bit 2: APM_IDLE_SLOWS_CLOCK
1377 bit 3: APM_BIOS_DISABLED
1378 bit 4: APM_BIOS_DISENGAGED
1379 3) AC line status
1380 0x00: Off-line
1381 0x01: On-line
1382 0x02: On backup power (BIOS >= 1.1 only)
1383 0xff: Unknown
1384 4) Battery status
1385 0x00: High
1386 0x01: Low
1387 0x02: Critical
1388 0x03: Charging
1389 0x04: Selected battery not present (BIOS >= 1.2 only)
1390 0xff: Unknown
1391 5) Battery flag
1392 bit 0: High
1393 bit 1: Low
1394 bit 2: Critical
1395 bit 3: Charging
1396 bit 7: No system battery
1397 0xff: Unknown
1398 6) Remaining battery life (percentage of charge):
1399 0-100: valid
1400 -1: Unknown
1401 7) Remaining battery life (time units):
1402 Number of remaining minutes or seconds
1403 -1: Unknown
1404 8) min = minutes; sec = seconds */
1406 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1407 driver_version,
1408 (apm_info.bios.version >> 8) & 0xff,
1409 apm_info.bios.version & 0xff,
1410 apm_info.bios.flags,
1411 ac_line_status,
1412 battery_status,
1413 battery_flag,
1414 percentage,
1415 time_units,
1416 units);
1418 return p - buf;
1421 static int apm(void *unused)
1423 unsigned short bx;
1424 unsigned short cx;
1425 unsigned short dx;
1426 int error;
1427 char * power_stat;
1428 char * bat_stat;
1430 kapmd_running = 1;
1432 daemonize();
1434 strcpy(current->comm, "kapm-idled");
1435 sigfillset(&current->blocked);
1436 current->tty = NULL; /* get rid of controlling tty */
1438 if (apm_info.connection_version == 0) {
1439 apm_info.connection_version = apm_info.bios.version;
1440 if (apm_info.connection_version > 0x100) {
1442 * We only support BIOSs up to version 1.2
1444 if (apm_info.connection_version > 0x0102)
1445 apm_info.connection_version = 0x0102;
1446 error = apm_driver_version(&apm_info.connection_version);
1447 if (error != APM_SUCCESS) {
1448 apm_error("driver version", error);
1449 /* Fall back to an APM 1.0 connection. */
1450 apm_info.connection_version = 0x100;
1455 if (debug)
1456 printk(KERN_INFO "apm: Connection version %d.%d\n",
1457 (apm_info.connection_version >> 8) & 0xff,
1458 apm_info.connection_version & 0xff);
1460 #ifdef CONFIG_APM_DO_ENABLE
1461 if (apm_info.bios.flags & APM_BIOS_DISABLED) {
1463 * This call causes my NEC UltraLite Versa 33/C to hang if it
1464 * is booted with PM disabled but not in the docking station.
1465 * Unfortunate ...
1467 error = apm_enable_power_management(1);
1468 if (error) {
1469 apm_error("enable power management", error);
1470 return -1;
1473 #endif
1475 if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
1476 && (apm_info.connection_version > 0x0100)) {
1477 error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1478 if (error) {
1479 apm_error("engage power management", error);
1480 return -1;
1484 if (debug && (smp_num_cpus == 1)) {
1485 error = apm_get_power_status(&bx, &cx, &dx);
1486 if (error)
1487 printk(KERN_INFO "apm: power status not available\n");
1488 else {
1489 switch ((bx >> 8) & 0xff) {
1490 case 0: power_stat = "off line"; break;
1491 case 1: power_stat = "on line"; break;
1492 case 2: power_stat = "on backup power"; break;
1493 default: power_stat = "unknown"; break;
1495 switch (bx & 0xff) {
1496 case 0: bat_stat = "high"; break;
1497 case 1: bat_stat = "low"; break;
1498 case 2: bat_stat = "critical"; break;
1499 case 3: bat_stat = "charging"; break;
1500 default: bat_stat = "unknown"; break;
1502 printk(KERN_INFO
1503 "apm: AC %s, battery status %s, battery life ",
1504 power_stat, bat_stat);
1505 if ((cx & 0xff) == 0xff)
1506 printk("unknown\n");
1507 else
1508 printk("%d%%\n", cx & 0xff);
1509 if (apm_info.connection_version > 0x100) {
1510 printk(KERN_INFO
1511 "apm: battery flag 0x%02x, battery life ",
1512 (cx >> 8) & 0xff);
1513 if (dx == 0xffff)
1514 printk("unknown\n");
1515 else
1516 printk("%d %s\n", dx & 0x7fff,
1517 (dx & 0x8000) ?
1518 "minutes" : "seconds");
1523 /* Install our power off handler.. */
1524 if (power_off)
1525 pm_power_off = apm_power_off;
1526 #ifdef CONFIG_MAGIC_SYSRQ
1527 sysrq_power_off = apm_power_off;
1528 #endif
1529 if (smp_num_cpus == 1) {
1530 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1531 console_blank_hook = apm_console_blank;
1532 #endif
1533 apm_mainloop();
1534 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1535 console_blank_hook = NULL;
1536 #endif
1538 kapmd_running = 0;
1540 return 0;
1543 #ifndef MODULE
1544 static int __init apm_setup(char *str)
1546 int invert;
1548 while ((str != NULL) && (*str != '\0')) {
1549 if (strncmp(str, "off", 3) == 0)
1550 apm_disabled = 1;
1551 if (strncmp(str, "on", 2) == 0)
1552 apm_disabled = 0;
1553 invert = (strncmp(str, "no-", 3) == 0);
1554 if (invert)
1555 str += 3;
1556 if (strncmp(str, "debug", 5) == 0)
1557 debug = !invert;
1558 if ((strncmp(str, "power-off", 9) == 0) ||
1559 (strncmp(str, "power_off", 9) == 0))
1560 power_off = !invert;
1561 if ((strncmp(str, "bounce-interval=", 16) == 0) ||
1562 (strncmp(str, "bounce_interval=", 16) == 0))
1563 bounce_interval = simple_strtol(str + 16, NULL, 0);
1564 str = strchr(str, ',');
1565 if (str != NULL)
1566 str += strspn(str, ", \t");
1568 return 1;
1571 __setup("apm=", apm_setup);
1572 #endif
1574 static struct file_operations apm_bios_fops = {
1575 owner: THIS_MODULE,
1576 read: do_read,
1577 poll: do_poll,
1578 ioctl: do_ioctl,
1579 open: do_open,
1580 release: do_release,
1583 static struct miscdevice apm_device = {
1584 APM_MINOR_DEV,
1585 "apm_bios",
1586 &apm_bios_fops
1590 * Just start the APM thread. We do NOT want to do APM BIOS
1591 * calls from anything but the APM thread, if for no other reason
1592 * than the fact that we don't trust the APM BIOS. This way,
1593 * most common APM BIOS problems that lead to protection errors
1594 * etc will have at least some level of being contained...
1596 * In short, if something bad happens, at least we have a choice
1597 * of just killing the apm thread..
1599 static int __init apm_init(void)
1601 struct proc_dir_entry *apm_proc;
1603 if (apm_info.bios.version == 0) {
1604 printk(KERN_INFO "apm: BIOS not found.\n");
1605 return -ENODEV;
1607 printk(KERN_INFO
1608 "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
1609 ((apm_info.bios.version >> 8) & 0xff),
1610 (apm_info.bios.version & 0xff),
1611 apm_info.bios.flags,
1612 driver_version);
1613 if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
1614 printk(KERN_INFO "apm: no 32 bit BIOS support\n");
1615 return -ENODEV;
1619 * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
1620 * but is reportedly a 1.0 BIOS.
1622 if (apm_info.bios.version == 0x001)
1623 apm_info.bios.version = 0x100;
1625 /* BIOS < 1.2 doesn't set cseg_16_len */
1626 if (apm_info.bios.version < 0x102)
1627 apm_info.bios.cseg_16_len = 0; /* 64k */
1629 if (debug) {
1630 printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
1631 apm_info.bios.cseg, apm_info.bios.offset,
1632 apm_info.bios.cseg_16, apm_info.bios.dseg);
1633 if (apm_info.bios.version > 0x100)
1634 printk(" cseg len %x, dseg len %x",
1635 apm_info.bios.cseg_len,
1636 apm_info.bios.dseg_len);
1637 if (apm_info.bios.version > 0x101)
1638 printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
1639 printk("\n");
1642 if (apm_disabled) {
1643 printk(KERN_NOTICE "apm: disabled on user request.\n");
1644 return -ENODEV;
1646 if ((smp_num_cpus > 1) && !power_off) {
1647 printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
1648 return -ENODEV;
1650 if (PM_IS_ACTIVE()) {
1651 printk(KERN_NOTICE "apm: overridden by ACPI.\n");
1652 return -ENODEV;
1654 pm_active = 1;
1657 * Set up a segment that references the real mode segment 0x40
1658 * that extends up to the end of page zero (that we have reserved).
1659 * This is for buggy BIOS's that refer to (real mode) segment 0x40
1660 * even though they are called in protected mode.
1662 set_base(gdt[APM_40 >> 3],
1663 __va((unsigned long)0x40 << 4));
1664 _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
1666 apm_bios_entry.offset = apm_info.bios.offset;
1667 apm_bios_entry.segment = APM_CS;
1668 set_base(gdt[APM_CS >> 3],
1669 __va((unsigned long)apm_info.bios.cseg << 4));
1670 set_base(gdt[APM_CS_16 >> 3],
1671 __va((unsigned long)apm_info.bios.cseg_16 << 4));
1672 set_base(gdt[APM_DS >> 3],
1673 __va((unsigned long)apm_info.bios.dseg << 4));
1674 #ifndef APM_RELAX_SEGMENTS
1675 if (apm_info.bios.version == 0x100) {
1676 #endif
1677 /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
1678 _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
1679 /* For some unknown machine. */
1680 _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
1681 /* For the DEC Hinote Ultra CT475 (and others?) */
1682 _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
1683 #ifndef APM_RELAX_SEGMENTS
1684 } else {
1685 _set_limit((char *)&gdt[APM_CS >> 3],
1686 (apm_info.bios.cseg_len - 1) & 0xffff);
1687 _set_limit((char *)&gdt[APM_CS_16 >> 3],
1688 (apm_info.bios.cseg_16_len - 1) & 0xffff);
1689 _set_limit((char *)&gdt[APM_DS >> 3],
1690 (apm_info.bios.dseg_len - 1) & 0xffff);
1692 #endif
1694 apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
1695 if (apm_proc)
1696 SET_MODULE_OWNER(apm_proc);
1698 kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
1700 if (smp_num_cpus > 1) {
1701 printk(KERN_NOTICE
1702 "apm: disabled - APM is not SMP safe (power off active).\n");
1703 return 0;
1706 misc_register(&apm_device);
1708 return 0;
1711 static void __exit apm_exit(void)
1713 int error;
1715 if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
1716 && (apm_info.connection_version > 0x0100)) {
1717 error = apm_engage_power_management(APM_DEVICE_ALL, 0);
1718 if (error)
1719 apm_error("disengage power management", error);
1721 misc_deregister(&apm_device);
1722 remove_proc_entry("apm", NULL);
1723 #ifdef CONFIG_MAGIC_SYSRQ
1724 sysrq_power_off = NULL;
1725 #endif
1726 if (power_off)
1727 pm_power_off = NULL;
1728 exit_kapmd = 1;
1729 while (kapmd_running)
1730 schedule();
1731 pm_active = 0;
1734 module_init(apm_init);
1735 module_exit(apm_exit);
1737 MODULE_AUTHOR("Stephen Rothwell");
1738 MODULE_DESCRIPTION("Advanced Power Management");
1739 MODULE_PARM(debug, "i");
1740 MODULE_PARM_DESC(debug, "Enable debug mode");
1741 MODULE_PARM(power_off, "i");
1742 MODULE_PARM_DESC(power_off, "Enable power off");
1743 MODULE_PARM(bounce_interval, "i");
1744 MODULE_PARM_DESC(bounce_interval, "Set the number of ticks to ignore suspend bounces");
1746 EXPORT_NO_SYMBOLS;