Import 2.3.51pre2
[davej-history.git] / arch / i386 / kernel / apm.c
blob99e2587565ad7b14e29a2532a71b72f5e1cb3e83
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
41 * History:
42 * 0.6b: first version in official kernel, Linux 1.3.46
43 * 0.7: changed /proc/apm format, Linux 1.3.58
44 * 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
45 * 0.9: only call bios if bios is present, Linux 1.3.72
46 * 1.0: use fixed device number, consolidate /proc/apm into this file,
47 * Linux 1.3.85
48 * 1.1: support user-space standby and suspend, power off after system
49 * halted, Linux 1.3.98
50 * 1.2: When resetting RTC after resume, take care so that the time
51 * is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
52 * <jtoth@princeton.edu>); improve interaction between
53 * screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
54 * 1.2a:Simple change to stop mysterious bug reports with SMP also added
55 * levels to the printk calls. APM is not defined for SMP machines.
56 * The new replacment for it is, but Linux doesn't yet support this.
57 * Alan Cox Linux 2.1.55
58 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
59 * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
60 * Dean Gaudet <dgaudet@arctic.org>.
61 * C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
62 * 1.5: Fix segment register reloading (in case of bad segments saved
63 * across BIOS call).
64 * Stephen Rothwell
65 * 1.6: Cope with complier/assembler differences.
66 * Only try to turn off the first display device.
67 * Fix OOPS at power off with no APM BIOS by Jan Echternach
68 * <echter@informatik.uni-rostock.de>
69 * Stephen Rothwell
70 * 1.7: Modify driver's cached copy of the disabled/disengaged flags
71 * to reflect current state of APM BIOS.
72 * Chris Rankin <rankinc@bellsouth.net>
73 * Reset interrupt 0 timer to 100Hz after suspend
74 * Chad Miller <cmiller@surfsouth.com>
75 * Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE
76 * Richard Gooch <rgooch@atnf.csiro.au>
77 * Allow boot time disabling of APM
78 * Make boot messages far less verbose by default
79 * Make asm safer
80 * Stephen Rothwell
81 * 1.8: Add CONFIG_APM_RTC_IS_GMT
82 * Richard Gooch <rgooch@atnf.csiro.au>
83 * change APM_NOINTS to CONFIG_APM_ALLOW_INTS
84 * remove dependency on CONFIG_PROC_FS
85 * Stephen Rothwell
86 * 1.9: Fix small typo. <laslo@ilo.opole.pl>
87 * Try to cope with BIOS's that need to have all display
88 * devices blanked and not just the first one.
89 * Ross Paterson <ross@soi.city.ac.uk>
90 * Fix segment limit setting it has always been wrong as
91 * the segments needed to have byte granularity.
92 * Mark a few things __init.
93 * Add hack to allow power off of SMP systems by popular request.
94 * Use CONFIG_SMP instead of __SMP__
95 * Ignore BOUNCES for three seconds.
96 * Stephen Rothwell
97 * 1.10: Fix for Thinkpad return code.
98 * Merge 2.2 and 2.3 drivers.
99 * Remove APM dependencies in arch/i386/kernel/process.c
100 * Remove APM dependencies in drivers/char/sysrq.c
101 * Reset time across standby.
102 * Allow more inititialisation on SMP.
103 * Remove CONFIG_APM_POWER_OFF and make it boot time
104 * configurable (default on).
105 * Make debug only a boot time parameter (remove APM_DEBUG).
106 * Try to blank all devices on any error.
107 * 1.11: Remove APM dependencies in drivers/char/console.c
108 * Check nr_running to detect if we are idle (from
109 * Borislav Deianov <borislav@lix.polytechnique.fr>)
110 * Fix for bioses that don't zero the top part of the
111 * entrypoint offset (Mario Sitta <sitta@al.unipmn.it>)
112 * (reported by Panos Katsaloulis <teras@writeme.com>).
113 * Real mode power off patch (Walter Hofmann
114 * <Walter.Hofmann@physik.stud.uni-erlangen.de>).
115 * 1.12: Remove CONFIG_SMP as the compiler will optimize
116 * the code away anyway (smp_num_cpus == 1 in UP)
117 * noted by Artur Skawina <skawina@geocities.com>.
118 * Make power off under SMP work again.
119 * Fix thinko with initial engaging of BIOS.
120 * Make sure power off only happens on CPU 0
121 * (Paul "Rusty" Russell <rusty@linuxcare.com>).
122 * Do error notification to user mode if BIOS calls fail.
123 * Move entrypoint offset fix to ...boot/setup.S
124 * where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>).
125 * Remove smp-power-off. SMP users must now specify
126 * "apm=power-off" on the kernel command line. Suggested
127 * by Jim Avera <jima@hal.com>, modified by Alan Cox
128 * <alan@lxorguk.ukuu.org.uk>.
129 * Register the /proc/apm entry even on SMP so that
130 * scripts that check for it before doing power off
131 * work (Jim Avera <jima@hal.com>).
132 * 1.13: Changes for new pm_ interfaces (Andy Henroid
133 * <andy_henroid@yahoo.com>).
134 * Modularize the code.
136 * APM 1.1 Reference:
138 * Intel Corporation, Microsoft Corporation. Advanced Power Management
139 * (APM) BIOS Interface Specification, Revision 1.1, September 1993.
140 * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
142 * [This document is available free from Intel by calling 800.628.8686 (fax
143 * 916.356.6100) or 800.548.4725; or via anonymous ftp from
144 * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
145 * available from Microsoft by calling 206.882.8080.]
147 * APM 1.2 Reference:
148 * Intel Corporation, Microsoft Corporation. Advanced Power Management
149 * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
151 * [This document is available from Microsoft at:
152 * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
155 #include <linux/config.h>
156 #include <linux/module.h>
158 #include <linux/poll.h>
159 #include <linux/types.h>
160 #include <linux/stddef.h>
161 #include <linux/timer.h>
162 #include <linux/fcntl.h>
163 #include <linux/malloc.h>
164 #include <linux/stat.h>
165 #include <linux/proc_fs.h>
166 #include <linux/miscdevice.h>
167 #include <linux/apm_bios.h>
168 #include <linux/init.h>
169 #include <linux/sched.h>
170 #include <linux/pm.h>
172 #include <asm/system.h>
173 #include <asm/uaccess.h>
174 #include <asm/desc.h>
176 extern unsigned long get_cmos_time(void);
177 extern void machine_real_restart(unsigned char *, int);
179 #ifdef CONFIG_MAGIC_SYSRQ
180 extern void (*sysrq_power_off)(void);
181 #endif
182 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
183 extern int (*console_blank_hook)(int);
184 #endif
187 * The apm_bios device is one of the misc char devices.
188 * This is its minor number.
190 #define APM_MINOR_DEV 134
193 * See Documentation/Config.help for the configuration options.
195 * Various options can be changed at boot time as follows:
196 * (We allow underscores for compatibility with the modules code)
197 * apm=on/off enable/disable APM
198 * [no-]debug log some debugging messages
199 * [no-]power[-_]off power off on shutdown
202 /* KNOWN PROBLEM MACHINES:
204 * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
205 * [Confirmed by TI representative]
206 * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
207 * [Confirmed by BIOS disassembly]
208 * [This may work now ...]
209 * P: Toshiba 1950S: battery life information only gets updated after resume
210 * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
211 * broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
213 * Legend: U = unusable with APM patches
214 * P = partially usable with APM patches
218 * Define to always call the APM BIOS busy routine even if the clock was
219 * not slowed by the idle routine.
221 #define ALWAYS_CALL_BUSY
224 * Define to make the APM BIOS calls zero all data segment registers (so
225 * that an incorrect BIOS implementation will cause a kernel panic if it
226 * tries to write to arbitrary memory).
228 #define APM_ZERO_SEGS
231 * Define to make all _set_limit calls use 64k limits. The APM 1.1 BIOS is
232 * supposed to provide limit information that it recognizes. Many machines
233 * do this correctly, but many others do not restrict themselves to their
234 * claimed limit. When this happens, they will cause a segmentation
235 * violation in the kernel at boot time. Most BIOS's, however, will
236 * respect a 64k limit, so we use that. If you want to be pedantic and
237 * hold your BIOS to its claims, then undefine this.
239 #define APM_RELAX_SEGMENTS
242 * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
243 * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
244 * David Chen <chen@ctpa04.mit.edu>
246 #undef INIT_TIMER_AFTER_SUSPEND
248 #ifdef INIT_TIMER_AFTER_SUSPEND
249 #include <linux/timex.h>
250 #include <asm/io.h>
251 #include <linux/delay.h>
252 #endif
255 * Need to poll the APM BIOS every second
257 #define APM_CHECK_TIMEOUT (HZ)
260 * If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then
261 * ignore suspend events for this amount of time after a resume
263 #define BOUNCE_INTERVAL (3 * HZ)
266 * Save a segment register away
268 #define savesegment(seg, where) \
269 __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
272 * Maximum number of events stored
274 #define APM_MAX_EVENTS 20
277 * The per-file APM data
279 struct apm_user {
280 int magic;
281 struct apm_user * next;
282 int suser: 1;
283 int suspend_wait: 1;
284 int suspend_result;
285 int suspends_pending;
286 int standbys_pending;
287 int suspends_read;
288 int standbys_read;
289 int event_head;
290 int event_tail;
291 apm_event_t events[APM_MAX_EVENTS];
295 * The magic number in apm_user
297 #define APM_BIOS_MAGIC 0x4101
300 * Local variables
302 static struct {
303 unsigned long offset;
304 unsigned short segment;
305 } apm_bios_entry;
306 #ifdef CONFIG_APM_CPU_IDLE
307 static int clock_slowed = 0;
308 #endif
309 static int suspends_pending = 0;
310 static int standbys_pending = 0;
311 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
312 static int waiting_for_resume = 0;
313 #endif
315 #ifdef CONFIG_APM_RTC_IS_GMT
316 # define clock_cmos_diff 0
317 # define got_clock_diff 1
318 #else
319 static long clock_cmos_diff;
320 static int got_clock_diff = 0;
321 #endif
322 static int debug = 0;
323 static int apm_disabled = 0;
324 #ifdef CONFIG_SMP
325 static int power_off = 0;
326 #else
327 static int power_off = 1;
328 #endif
329 static int exit_kapmd = 0;
330 static int kapmd_running = 0;
332 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
333 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
334 static struct apm_user * user_list = NULL;
336 static char driver_version[] = "1.13"; /* no spaces */
338 static char * apm_event_name[] = {
339 "system standby",
340 "system suspend",
341 "normal resume",
342 "critical resume",
343 "low battery",
344 "power status change",
345 "update time",
346 "critical suspend",
347 "user standby",
348 "user suspend",
349 "system standby resume",
350 "capabilities change"
352 #define NR_APM_EVENT_NAME \
353 (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
355 typedef struct lookup_t {
356 int key;
357 char * msg;
358 } lookup_t;
360 static const lookup_t error_table[] = {
361 /* N/A { APM_SUCCESS, "Operation succeeded" }, */
362 { APM_DISABLED, "Power management disabled" },
363 { APM_CONNECTED, "Real mode interface already connected" },
364 { APM_NOT_CONNECTED, "Interface not connected" },
365 { APM_16_CONNECTED, "16 bit interface already connected" },
366 /* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
367 { APM_32_CONNECTED, "32 bit interface already connected" },
368 { APM_32_UNSUPPORTED, "32 bit interface not supported" },
369 { APM_BAD_DEVICE, "Unrecognized device ID" },
370 { APM_BAD_PARAM, "Parameter out of range" },
371 { APM_NOT_ENGAGED, "Interface not engaged" },
372 { APM_BAD_FUNCTION, "Function not supported" },
373 { APM_RESUME_DISABLED, "Resume timer disabled" },
374 { APM_BAD_STATE, "Unable to enter requested state" },
375 /* N/A { APM_NO_EVENTS, "No events pending" }, */
376 { APM_NO_ERROR, "BIOS did not set a return code" },
377 { APM_NOT_PRESENT, "No APM present" }
379 #define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
382 * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and
383 * CONFIG_APM_ALLOW_INTS, we are being really paranoid here! Not only
384 * are interrupts disabled, but all the segment registers (except SS)
385 * are saved and zeroed this means that if the BIOS tries to reference
386 * any data without explicitly loading the segment registers, the kernel
387 * will fault immediately rather than have some unforeseen circumstances
388 * for the rest of the kernel. And it will be very obvious! :-) Doing
389 * this depends on CS referring to the same physical memory as DS so that
390 * DS can be zeroed before the call. Unfortunately, we can't do anything
391 * about the stack segment/pointer. Also, we tell the compiler that
392 * everything could change.
394 * Also, we KNOW that for the non error case of apm_bios_call, there
395 * is no useful data returned in the low order 8 bits of eax.
397 #ifndef CONFIG_APM_ALLOW_INTS
398 # define APM_DO_CLI __cli()
399 #else
400 # define APM_DO_CLI
401 #endif
402 #ifdef APM_ZERO_SEGS
403 # define APM_DECL_SEGS \
404 unsigned int saved_fs; unsigned int saved_gs;
405 # define APM_DO_SAVE_SEGS \
406 savesegment(fs, saved_fs); savesegment(gs, saved_gs)
407 # define APM_DO_ZERO_SEGS \
408 "pushl %%ds\n\t" \
409 "pushl %%es\n\t" \
410 "xorl %%edx, %%edx\n\t" \
411 "mov %%dx, %%ds\n\t" \
412 "mov %%dx, %%es\n\t" \
413 "mov %%dx, %%fs\n\t" \
414 "mov %%dx, %%gs\n\t"
415 # define APM_DO_POP_SEGS \
416 "popl %%es\n\t" \
417 "popl %%ds\n\t"
418 # define APM_DO_RESTORE_SEGS \
419 loadsegment(fs, saved_fs); loadsegment(gs, saved_gs)
420 #else
421 # define APM_DECL_SEGS
422 # define APM_DO_SAVE_SEGS
423 # define APM_DO_ZERO_SEGS
424 # define APM_DO_POP_SEGS
425 # define APM_DO_RESTORE_SEGS
426 #endif
428 static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
429 u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
431 APM_DECL_SEGS
432 unsigned long flags;
434 __save_flags(flags);
435 APM_DO_CLI;
436 APM_DO_SAVE_SEGS;
438 * N.B. We do NOT need a cld after the BIOS call
439 * because we always save and restore the flags.
441 __asm__ __volatile__(APM_DO_ZERO_SEGS
442 "pushl %%edi\n\t"
443 "pushl %%ebp\n\t"
444 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
445 "setc %%al\n\t"
446 "popl %%ebp\n\t"
447 "popl %%edi\n\t"
448 APM_DO_POP_SEGS
449 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
450 "=S" (*esi)
451 : "a" (func), "b" (ebx_in), "c" (ecx_in)
452 : "memory", "cc");
453 APM_DO_RESTORE_SEGS;
454 __restore_flags(flags);
455 return *eax & 0xff;
459 * This version only returns one value (usually an error code)
462 static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
464 u8 error;
465 APM_DECL_SEGS
466 unsigned long flags;
468 __save_flags(flags);
469 APM_DO_CLI;
470 APM_DO_SAVE_SEGS;
472 int cx, dx, si;
475 * N.B. We do NOT need a cld after the BIOS call
476 * because we always save and restore the flags.
478 __asm__ __volatile__(APM_DO_ZERO_SEGS
479 "pushl %%edi\n\t"
480 "pushl %%ebp\n\t"
481 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
482 "setc %%bl\n\t"
483 "popl %%ebp\n\t"
484 "popl %%edi\n\t"
485 APM_DO_POP_SEGS
486 : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
487 "=S" (si)
488 : "a" (func), "b" (ebx_in), "c" (ecx_in)
489 : "memory", "cc");
491 APM_DO_RESTORE_SEGS;
492 __restore_flags(flags);
493 return error;
496 static int __init apm_driver_version(u_short *val)
498 u32 eax;
500 if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax))
501 return (eax >> 8) & 0xff;
502 *val = eax;
503 return APM_SUCCESS;
506 static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
508 u32 eax;
509 u32 ebx;
510 u32 ecx;
511 u32 dummy;
513 if (apm_bios_call(APM_FUNC_GET_EVENT, 0, 0, &eax, &ebx, &ecx,
514 &dummy, &dummy))
515 return (eax >> 8) & 0xff;
516 *event = ebx;
517 if (apm_bios_info.version < 0x0102)
518 *info = ~0; /* indicate info not valid */
519 else
520 *info = ecx;
521 return APM_SUCCESS;
524 static int set_power_state(u_short what, u_short state)
526 u32 eax;
528 if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax))
529 return (eax >> 8) & 0xff;
530 return APM_SUCCESS;
533 static int apm_set_power_state(u_short state)
535 return set_power_state(APM_DEVICE_ALL, state);
538 #ifdef CONFIG_APM_CPU_IDLE
539 static int apm_do_idle(void)
541 u32 dummy;
543 if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &dummy))
544 return 0;
546 #ifdef ALWAYS_CALL_BUSY
547 clock_slowed = 1;
548 #else
549 clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
550 #endif
551 return 1;
554 static void apm_do_busy(void)
556 u32 dummy;
558 if (clock_slowed) {
559 (void) apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy);
560 clock_slowed = 0;
564 #if 0
565 extern int hlt_counter;
568 * If no process has been interested in this
569 * CPU for some time, we want to wake up the
570 * power management thread - we probably want
571 * to conserve power.
573 #define HARD_IDLE_TIMEOUT (HZ/3)
575 /* This should wake up kapmd and ask it to slow the CPU */
576 #define powermanagement_idle() do { } while (0)
579 * This is the idle thing.
581 static void apm_cpu_idle(void)
583 unsigned int start_idle;
585 start_idle = jiffies;
586 while (1) {
587 if (!current->need_resched) {
588 if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
589 if (!current_cpu_data.hlt_works_ok)
590 continue;
591 if (hlt_counter)
592 continue;
593 __cli();
594 if (!current->need_resched)
595 safe_halt();
596 else
597 __sti();
598 continue;
602 * Ok, do some power management - we've been idle for too long
604 powermanagement_idle();
607 schedule();
608 check_pgt_cache();
609 start_idle = jiffies;
612 #endif
613 #endif
615 #ifdef CONFIG_SMP
616 static int apm_magic(void * unused)
618 while (1)
619 schedule();
621 #endif
623 static void apm_power_off(void)
625 #ifdef CONFIG_APM_REAL_MODE_POWER_OFF
626 unsigned char po_bios_call[] = {
627 0xb8, 0x00, 0x10, /* movw $0x1000,ax */
628 0x8e, 0xd0, /* movw ax,ss */
629 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */
630 0xb8, 0x07, 0x53, /* movw $0x5307,ax */
631 0xbb, 0x01, 0x00, /* movw $0x0001,bx */
632 0xb9, 0x03, 0x00, /* movw $0x0003,cx */
633 0xcd, 0x15 /* int $0x15 */
635 #endif
638 * This may be called on an SMP machine.
640 #ifdef CONFIG_SMP
641 /* Some bioses don't like being called from CPU != 0 */
642 while (cpu_number_map(smp_processor_id()) != 0) {
643 kernel_thread(apm_magic, NULL,
644 CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
645 schedule();
647 #endif
648 #ifdef CONFIG_APM_REAL_MODE_POWER_OFF
649 machine_real_restart(po_bios_call, sizeof(po_bios_call));
650 #else
651 (void) apm_set_power_state(APM_STATE_OFF);
652 #endif
655 static int apm_enable_power_management(int enable)
657 u32 eax;
659 if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
660 return APM_NOT_ENGAGED;
661 if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
662 enable, &eax))
663 return (eax >> 8) & 0xff;
664 if (enable)
665 apm_bios_info.flags &= ~APM_BIOS_DISABLED;
666 else
667 apm_bios_info.flags |= APM_BIOS_DISABLED;
668 return APM_SUCCESS;
671 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
673 u32 eax;
674 u32 ebx;
675 u32 ecx;
676 u32 edx;
677 u32 dummy;
679 if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
680 &eax, &ebx, &ecx, &edx, &dummy))
681 return (eax >> 8) & 0xff;
682 *status = ebx;
683 *bat = ecx;
684 *life = edx;
685 return APM_SUCCESS;
688 #if 0
689 static int apm_get_battery_status(u_short which, u_short *status,
690 u_short *bat, u_short *life, u_short *nbat)
692 u32 eax;
693 u32 ebx;
694 u32 ecx;
695 u32 edx;
696 u32 esi;
698 if (apm_bios_info.version < 0x0102) {
699 /* pretend we only have one battery. */
700 if (which != 1)
701 return APM_BAD_DEVICE;
702 *nbat = 1;
703 return apm_get_power_status(status, bat, life);
706 if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
707 &ebx, &ecx, &edx, &esi))
708 return (eax >> 8) & 0xff;
709 *status = ebx;
710 *bat = ecx;
711 *life = edx;
712 *nbat = esi;
713 return APM_SUCCESS;
715 #endif
717 static int apm_engage_power_management(u_short device, int enable)
719 u32 eax;
721 if ((enable == 0) && (device == APM_DEVICE_ALL)
722 && (apm_bios_info.flags & APM_BIOS_DISABLED))
723 return APM_DISABLED;
724 if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
725 return (eax >> 8) & 0xff;
726 if (device == APM_DEVICE_ALL) {
727 if (enable)
728 apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
729 else
730 apm_bios_info.flags |= APM_BIOS_DISENGAGED;
732 return APM_SUCCESS;
735 static void apm_error(char *str, int err)
737 int i;
739 for (i = 0; i < ERROR_COUNT; i++)
740 if (error_table[i].key == err) break;
741 if (i < ERROR_COUNT)
742 printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
743 else
744 printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
745 str, err);
748 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
749 static int apm_console_blank(int blank)
751 int error;
752 u_short state;
754 state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
755 /* Blank the first display device */
756 error = set_power_state(0x100, state);
757 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
758 /* try to blank them all instead */
759 error = set_power_state(0x1ff, state);
760 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
761 /* try to blank device one instead */
762 error = set_power_state(0x101, state);
764 if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
765 return 1;
766 apm_error("set display", error);
767 return 0;
769 #endif
771 static int queue_empty(struct apm_user *as)
773 return as->event_head == as->event_tail;
776 static apm_event_t get_queued_event(struct apm_user *as)
778 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
779 return as->events[as->event_tail];
782 static void queue_event(apm_event_t event, struct apm_user *sender)
784 struct apm_user * as;
786 if (user_list == NULL)
787 return;
788 for (as = user_list; as != NULL; as = as->next) {
789 if (as == sender)
790 continue;
791 as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
792 if (as->event_head == as->event_tail) {
793 static int notified;
795 if (notified++ == 0)
796 printk(KERN_ERR "apm: an event queue overflowed\n");
797 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
799 as->events[as->event_head] = event;
800 if (!as->suser)
801 continue;
802 switch (event) {
803 case APM_SYS_SUSPEND:
804 case APM_USER_SUSPEND:
805 as->suspends_pending++;
806 suspends_pending++;
807 break;
809 case APM_SYS_STANDBY:
810 case APM_USER_STANDBY:
811 as->standbys_pending++;
812 standbys_pending++;
813 break;
816 wake_up_interruptible(&apm_waitqueue);
819 static void set_time(void)
821 unsigned long flags;
823 if (got_clock_diff) { /* Must know time zone in order to set clock */
824 save_flags(flags);
825 cli();
826 CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
827 restore_flags(flags);
831 static void get_time_diff(void)
833 #ifndef CONFIG_APM_RTC_IS_GMT
834 unsigned long flags;
837 * Estimate time zone so that set_time can update the clock
839 save_flags(flags);
840 clock_cmos_diff = -get_cmos_time();
841 cli();
842 clock_cmos_diff += CURRENT_TIME;
843 got_clock_diff = 1;
844 restore_flags(flags);
845 #endif
848 static void reinit_timer(void)
850 #ifdef INIT_TIMER_AFTER_SUSPEND
851 unsigned long flags;
853 save_flags(flags);
854 cli();
855 /* set the clock to 100 Hz */
856 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
857 udelay(10);
858 outb_p(LATCH & 0xff , 0x40); /* LSB */
859 udelay(10);
860 outb(LATCH >> 8 , 0x40); /* MSB */
861 udelay(10);
862 restore_flags(flags);
863 #endif
866 static int suspend(void)
868 int err;
869 int ret;
870 struct apm_user *as;
872 get_time_diff();
873 err = apm_set_power_state(APM_STATE_SUSPEND);
874 reinit_timer();
875 set_time();
876 ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR);
877 if (!ret)
878 apm_error("suspend", err);
879 for (as = user_list; as != NULL; as = as->next) {
880 as->suspend_wait = 0;
881 as->suspend_result = (ret ? 0 : -EIO);
883 wake_up_interruptible(&apm_suspend_waitqueue);
884 return ret;
887 static void standby(void)
889 int err;
891 get_time_diff();
892 err = apm_set_power_state(APM_STATE_STANDBY);
893 if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
894 apm_error("standby", err);
897 static apm_event_t get_event(void)
899 int error;
900 apm_event_t event;
901 apm_eventinfo_t info;
903 static int notified = 0;
905 /* we don't use the eventinfo */
906 error = apm_get_event(&event, &info);
907 if (error == APM_SUCCESS)
908 return event;
910 if ((error != APM_NO_EVENTS) && (notified++ == 0))
911 apm_error("get_event", error);
913 return 0;
916 static int send_event(apm_event_t event, struct apm_user *sender)
918 switch (event) {
919 case APM_SYS_SUSPEND:
920 case APM_CRITICAL_SUSPEND:
921 case APM_USER_SUSPEND:
922 /* map all suspends to ACPI D3 */
923 if (pm_send_all(PM_SUSPEND, (void *)3)) {
924 if (apm_bios_info.version > 0x100)
925 apm_set_power_state(APM_STATE_REJECT);
926 return 0;
928 break;
929 case APM_NORMAL_RESUME:
930 case APM_CRITICAL_RESUME:
931 /* map all resumes to ACPI D0 */
932 (void) pm_send_all(PM_RESUME, (void *)0);
933 break;
936 queue_event(event, sender);
937 return 1;
940 static void check_events(void)
942 apm_event_t event;
943 #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
944 static unsigned long last_resume = 0;
945 static int ignore_bounce = 0;
946 #endif
948 while ((event = get_event()) != 0) {
949 if (debug) {
950 if (event <= NR_APM_EVENT_NAME)
951 printk(KERN_DEBUG "apm: received %s notify\n",
952 apm_event_name[event - 1]);
953 else
954 printk(KERN_DEBUG "apm: received unknown "
955 "event 0x%02x\n", event);
957 #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
958 if (ignore_bounce
959 && ((jiffies - last_resume) > BOUNCE_INTERVAL))
960 ignore_bounce = 0;
961 #endif
962 switch (event) {
963 case APM_SYS_STANDBY:
964 case APM_USER_STANDBY:
965 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
966 if (waiting_for_resume)
967 break;
968 #endif
969 if (send_event(event, NULL)) {
970 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
971 waiting_for_resume = 1;
972 #endif
973 if (standbys_pending <= 0)
974 standby();
976 break;
978 case APM_USER_SUSPEND:
979 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
980 if (apm_bios_info.version > 0x100)
981 apm_set_power_state(APM_STATE_REJECT);
982 break;
983 #endif
984 case APM_SYS_SUSPEND:
985 #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
986 if (ignore_bounce)
987 break;
988 #endif
989 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
990 if (waiting_for_resume)
991 break;
992 #endif
993 if (send_event(event, NULL)) {
994 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
995 waiting_for_resume = 1;
996 #endif
997 if (suspends_pending <= 0)
998 (void) suspend();
1000 break;
1002 case APM_NORMAL_RESUME:
1003 case APM_CRITICAL_RESUME:
1004 case APM_STANDBY_RESUME:
1005 #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
1006 waiting_for_resume = 0;
1007 #endif
1008 #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
1009 last_resume = jiffies;
1010 ignore_bounce = 1;
1011 #endif
1012 set_time();
1013 send_event(event, NULL);
1014 break;
1016 case APM_CAPABILITY_CHANGE:
1017 case APM_LOW_BATTERY:
1018 case APM_POWER_STATUS_CHANGE:
1019 send_event(event, NULL);
1020 break;
1022 case APM_UPDATE_TIME:
1023 set_time();
1024 break;
1026 case APM_CRITICAL_SUSPEND:
1027 (void) suspend();
1028 break;
1033 static void apm_event_handler(void)
1035 static int pending_count = 4;
1036 int err;
1038 if ((standbys_pending > 0) || (suspends_pending > 0)) {
1039 if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) {
1040 pending_count = 4;
1041 err = apm_set_power_state(APM_STATE_BUSY);
1042 if (err)
1043 apm_error("busy", err);
1045 } else
1046 pending_count = 4;
1047 check_events();
1051 * This is the APM thread main loop.
1053 * Check whether we're the only running process to
1054 * decide if we should just power down.
1057 #define system_idle() (nr_running == 1)
1059 static void apm_mainloop(void)
1061 DECLARE_WAITQUEUE(wait, current);
1063 if (smp_num_cpus > 1)
1064 return;
1066 add_wait_queue(&apm_waitqueue, &wait);
1067 current->state = TASK_INTERRUPTIBLE;
1068 for (;;) {
1069 /* Nothing to do, just sleep for the timeout */
1070 schedule_timeout(APM_CHECK_TIMEOUT);
1071 if (exit_kapmd)
1072 break;
1075 * Ok, check all events, check for idle (and mark us sleeping
1076 * so as not to count towards the load average)..
1078 current->state = TASK_INTERRUPTIBLE;
1079 apm_event_handler();
1080 #ifdef CONFIG_APM_CPU_IDLE
1081 if (!system_idle())
1082 continue;
1083 if (apm_do_idle()) {
1084 unsigned long start = jiffies;
1085 while (system_idle()) {
1086 apm_do_idle();
1087 if (jiffies - start > APM_CHECK_TIMEOUT)
1088 break;
1090 apm_do_busy();
1091 apm_event_handler();
1093 #endif
1097 static int check_apm_user(struct apm_user *as, const char *func)
1099 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
1100 printk(KERN_ERR "apm: %s passed bad filp", func);
1101 return 1;
1103 return 0;
1106 static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
1108 struct apm_user * as;
1109 int i;
1110 apm_event_t event;
1111 DECLARE_WAITQUEUE(wait, current);
1113 as = fp->private_data;
1114 if (check_apm_user(as, "read"))
1115 return -EIO;
1116 if (count < sizeof(apm_event_t))
1117 return -EINVAL;
1118 if (queue_empty(as)) {
1119 if (fp->f_flags & O_NONBLOCK)
1120 return -EAGAIN;
1121 add_wait_queue(&apm_waitqueue, &wait);
1122 repeat:
1123 set_current_state(TASK_INTERRUPTIBLE);
1124 if (queue_empty(as) && !signal_pending(current)) {
1125 schedule();
1126 goto repeat;
1128 current->state = TASK_RUNNING;
1129 remove_wait_queue(&apm_waitqueue, &wait);
1131 i = count;
1132 while ((i >= sizeof(event)) && !queue_empty(as)) {
1133 event = get_queued_event(as);
1134 if (copy_to_user(buf, &event, sizeof(event))) {
1135 if (i < count)
1136 break;
1137 return -EFAULT;
1139 switch (event) {
1140 case APM_SYS_SUSPEND:
1141 case APM_USER_SUSPEND:
1142 as->suspends_read++;
1143 break;
1145 case APM_SYS_STANDBY:
1146 case APM_USER_STANDBY:
1147 as->standbys_read++;
1148 break;
1150 buf += sizeof(event);
1151 i -= sizeof(event);
1153 if (i < count)
1154 return count - i;
1155 if (signal_pending(current))
1156 return -ERESTARTSYS;
1157 return 0;
1160 static unsigned int do_poll(struct file *fp, poll_table * wait)
1162 struct apm_user * as;
1164 as = fp->private_data;
1165 if (check_apm_user(as, "poll"))
1166 return 0;
1167 poll_wait(fp, &apm_waitqueue, wait);
1168 if (!queue_empty(as))
1169 return POLLIN | POLLRDNORM;
1170 return 0;
1173 static int do_ioctl(struct inode * inode, struct file *filp,
1174 u_int cmd, u_long arg)
1176 struct apm_user * as;
1177 DECLARE_WAITQUEUE(wait, current);
1179 as = filp->private_data;
1180 if (check_apm_user(as, "ioctl"))
1181 return -EIO;
1182 if (!as->suser)
1183 return -EPERM;
1184 switch (cmd) {
1185 case APM_IOC_STANDBY:
1186 if (as->standbys_read > 0) {
1187 as->standbys_read--;
1188 as->standbys_pending--;
1189 standbys_pending--;
1190 } else if (!send_event(APM_USER_STANDBY, as))
1191 return -EAGAIN;
1192 if (standbys_pending <= 0)
1193 standby();
1194 break;
1195 case APM_IOC_SUSPEND:
1196 if (as->suspends_read > 0) {
1197 as->suspends_read--;
1198 as->suspends_pending--;
1199 suspends_pending--;
1200 } else if (!send_event(APM_USER_SUSPEND, as))
1201 return -EAGAIN;
1202 if (suspends_pending <= 0) {
1203 if (!suspend())
1204 return -EIO;
1205 } else {
1206 as->suspend_wait = 1;
1207 add_wait_queue(&apm_suspend_waitqueue, &wait);
1208 while (1) {
1209 set_current_state(TASK_INTERRUPTIBLE);
1210 if ((as->suspend_wait == 0)
1211 || signal_pending(current))
1212 break;
1213 schedule();
1215 current->state = TASK_RUNNING;
1216 remove_wait_queue(&apm_suspend_waitqueue, &wait);
1217 return as->suspend_result;
1219 break;
1220 default:
1221 return -EINVAL;
1223 return 0;
1226 static int do_release(struct inode * inode, struct file * filp)
1228 struct apm_user * as;
1230 as = filp->private_data;
1231 if (check_apm_user(as, "release"))
1232 return 0;
1233 filp->private_data = NULL;
1234 if (as->standbys_pending > 0) {
1235 standbys_pending -= as->standbys_pending;
1236 if (standbys_pending <= 0)
1237 standby();
1239 if (as->suspends_pending > 0) {
1240 suspends_pending -= as->suspends_pending;
1241 if (suspends_pending <= 0)
1242 (void) suspend();
1244 if (user_list == as)
1245 user_list = as->next;
1246 else {
1247 struct apm_user * as1;
1249 for (as1 = user_list;
1250 (as1 != NULL) && (as1->next != as);
1251 as1 = as1->next)
1253 if (as1 == NULL)
1254 printk(KERN_ERR "apm: filp not in user list");
1255 else
1256 as1->next = as->next;
1258 kfree_s(as, sizeof(*as));
1259 MOD_DEC_USE_COUNT;
1260 return 0;
1263 static int do_open(struct inode * inode, struct file * filp)
1265 struct apm_user * as;
1267 MOD_INC_USE_COUNT;
1269 as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
1270 if (as == NULL) {
1271 printk(KERN_ERR "apm: cannot allocate struct of size %d bytes",
1272 sizeof(*as));
1273 MOD_DEC_USE_COUNT;
1274 return -ENOMEM;
1276 as->magic = APM_BIOS_MAGIC;
1277 as->event_tail = as->event_head = 0;
1278 as->suspends_pending = as->standbys_pending = 0;
1279 as->suspends_read = as->standbys_read = 0;
1281 * XXX - this is a tiny bit broken, when we consider BSD
1282 * process accounting. If the device is opened by root, we
1283 * instantly flag that we used superuser privs. Who knows,
1284 * we might close the device immediately without doing a
1285 * privileged operation -- cevans
1287 as->suser = capable(CAP_SYS_ADMIN);
1288 as->next = user_list;
1289 user_list = as;
1290 filp->private_data = as;
1291 return 0;
1294 static int apm_get_info(char *buf, char **start, off_t fpos, int length)
1296 char * p;
1297 unsigned short bx;
1298 unsigned short cx;
1299 unsigned short dx;
1300 unsigned short error;
1301 unsigned short ac_line_status = 0xff;
1302 unsigned short battery_status = 0xff;
1303 unsigned short battery_flag = 0xff;
1304 int percentage = -1;
1305 int time_units = -1;
1306 char *units = "?";
1308 p = buf;
1310 if ((smp_num_cpus == 1) &&
1311 !(error = apm_get_power_status(&bx, &cx, &dx))) {
1312 ac_line_status = (bx >> 8) & 0xff;
1313 battery_status = bx & 0xff;
1314 if ((cx & 0xff) != 0xff)
1315 percentage = cx & 0xff;
1317 if (apm_bios_info.version > 0x100) {
1318 battery_flag = (cx >> 8) & 0xff;
1319 if (dx != 0xffff) {
1320 units = (dx & 0x8000) ? "min" : "sec";
1321 time_units = dx & 0x7fff;
1325 /* Arguments, with symbols from linux/apm_bios.h. Information is
1326 from the Get Power Status (0x0a) call unless otherwise noted.
1328 0) Linux driver version (this will change if format changes)
1329 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
1330 2) APM flags from APM Installation Check (0x00):
1331 bit 0: APM_16_BIT_SUPPORT
1332 bit 1: APM_32_BIT_SUPPORT
1333 bit 2: APM_IDLE_SLOWS_CLOCK
1334 bit 3: APM_BIOS_DISABLED
1335 bit 4: APM_BIOS_DISENGAGED
1336 3) AC line status
1337 0x00: Off-line
1338 0x01: On-line
1339 0x02: On backup power (BIOS >= 1.1 only)
1340 0xff: Unknown
1341 4) Battery status
1342 0x00: High
1343 0x01: Low
1344 0x02: Critical
1345 0x03: Charging
1346 0x04: Selected battery not present (BIOS >= 1.2 only)
1347 0xff: Unknown
1348 5) Battery flag
1349 bit 0: High
1350 bit 1: Low
1351 bit 2: Critical
1352 bit 3: Charging
1353 bit 7: No system battery
1354 0xff: Unknown
1355 6) Remaining battery life (percentage of charge):
1356 0-100: valid
1357 -1: Unknown
1358 7) Remaining battery life (time units):
1359 Number of remaining minutes or seconds
1360 -1: Unknown
1361 8) min = minutes; sec = seconds */
1363 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1364 driver_version,
1365 (apm_bios_info.version >> 8) & 0xff,
1366 apm_bios_info.version & 0xff,
1367 apm_bios_info.flags,
1368 ac_line_status,
1369 battery_status,
1370 battery_flag,
1371 percentage,
1372 time_units,
1373 units);
1375 return p - buf;
1378 static int apm(void *unused)
1380 unsigned short bx;
1381 unsigned short cx;
1382 unsigned short dx;
1383 unsigned short error;
1384 char * power_stat;
1385 char * bat_stat;
1387 kapmd_running = 1;
1389 exit_files(current); /* daemonize doesn't do exit_files */
1390 daemonize();
1392 strcpy(current->comm, "kapmd");
1393 sigfillset(&current->blocked);
1395 if (apm_bios_info.version > 0x100) {
1397 * We only support BIOSs up to version 1.2
1399 if (apm_bios_info.version > 0x0102)
1400 apm_bios_info.version = 0x0102;
1401 if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
1402 /* Fall back to an APM 1.0 connection. */
1403 apm_bios_info.version = 0x100;
1406 if (debug && (smp_num_cpus == 1)) {
1407 printk(KERN_INFO "apm: Connection version %d.%d\n",
1408 (apm_bios_info.version >> 8) & 0xff,
1409 apm_bios_info.version & 0xff);
1411 error = apm_get_power_status(&bx, &cx, &dx);
1412 if (error)
1413 printk(KERN_INFO "apm: power status not available\n");
1414 else {
1415 switch ((bx >> 8) & 0xff) {
1416 case 0: power_stat = "off line"; break;
1417 case 1: power_stat = "on line"; break;
1418 case 2: power_stat = "on backup power"; break;
1419 default: power_stat = "unknown"; break;
1421 switch (bx & 0xff) {
1422 case 0: bat_stat = "high"; break;
1423 case 1: bat_stat = "low"; break;
1424 case 2: bat_stat = "critical"; break;
1425 case 3: bat_stat = "charging"; break;
1426 default: bat_stat = "unknown"; break;
1428 printk(KERN_INFO
1429 "apm: AC %s, battery status %s, battery life ",
1430 power_stat, bat_stat);
1431 if ((cx & 0xff) == 0xff)
1432 printk("unknown\n");
1433 else
1434 printk("%d%%\n", cx & 0xff);
1435 if (apm_bios_info.version > 0x100) {
1436 printk(KERN_INFO
1437 "apm: battery flag 0x%02x, battery life ",
1438 (cx >> 8) & 0xff);
1439 if (dx == 0xffff)
1440 printk("unknown\n");
1441 else
1442 printk("%d %s\n", dx & 0x7fff,
1443 (dx & 0x8000) ?
1444 "minutes" : "seconds");
1449 #ifdef CONFIG_APM_DO_ENABLE
1450 if (apm_bios_info.flags & APM_BIOS_DISABLED) {
1452 * This call causes my NEC UltraLite Versa 33/C to hang if it
1453 * is booted with PM disabled but not in the docking station.
1454 * Unfortunate ...
1456 error = apm_enable_power_management(1);
1457 if (error) {
1458 apm_error("enable power management", error);
1459 return -1;
1462 #endif
1463 if ((apm_bios_info.flags & APM_BIOS_DISENGAGED)
1464 && (apm_bios_info.version > 0x0100)) {
1465 error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1466 if (error) {
1467 apm_error("engage power management", error);
1468 return -1;
1472 /* Install our power off handler.. */
1473 if (power_off)
1474 pm_power_off = apm_power_off;
1475 #ifdef CONFIG_MAGIC_SYSRQ
1476 sysrq_power_off = apm_power_off;
1477 #endif
1478 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1479 if (smp_num_cpus == 1)
1480 console_blank_hook = apm_console_blank;
1481 #endif
1483 pm_active = 1;
1485 apm_mainloop();
1487 pm_active = 0;
1489 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1490 if (smp_num_cpus == 1)
1491 console_blank_hook = NULL;
1492 #endif
1493 #ifdef CONFIG_MAGIC_SYSRQ
1494 sysrq_power_off = NULL;
1495 #endif
1496 if (power_off)
1497 pm_power_off = NULL;
1499 kapmd_running = 0;
1501 return 0;
1504 static int __init apm_setup(char *str)
1506 int invert;
1508 while ((str != NULL) && (*str != '\0')) {
1509 if (strncmp(str, "off", 3) == 0)
1510 apm_disabled = 1;
1511 if (strncmp(str, "on", 2) == 0)
1512 apm_disabled = 0;
1513 invert = (strncmp(str, "no-", 3) == 0);
1514 if (invert)
1515 str += 3;
1516 if (strncmp(str, "debug", 5) == 0)
1517 debug = !invert;
1518 if ((strncmp(str, "power-off", 9) == 0) ||
1519 (strncmp(str, "power_off", 9) == 0))
1520 power_off = !invert;
1521 str = strchr(str, ',');
1522 if (str != NULL)
1523 str += strspn(str, ", \t");
1525 return 1;
1528 __setup("apm=", apm_setup);
1530 static struct file_operations apm_bios_fops = {
1531 read: do_read,
1532 poll: do_poll,
1533 ioctl: do_ioctl,
1534 open: do_open,
1535 release: do_release,
1538 static struct miscdevice apm_device = {
1539 APM_MINOR_DEV,
1540 "apm_bios",
1541 &apm_bios_fops
1544 #define APM_INIT_ERROR_RETURN return -1
1547 * Just start the APM thread. We do NOT want to do APM BIOS
1548 * calls from anything but the APM thread, if for no other reason
1549 * than the fact that we don't trust the APM BIOS. This way,
1550 * most common APM BIOS problems that lead to protection errors
1551 * etc will have at least some level of being contained...
1553 * In short, if something bad happens, at least we have a choice
1554 * of just killing the apm thread..
1556 static int __init apm_init(void)
1558 if (apm_bios_info.version == 0) {
1559 printk(KERN_INFO "apm: BIOS not found.\n");
1560 APM_INIT_ERROR_RETURN;
1562 printk(KERN_INFO
1563 "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
1564 ((apm_bios_info.version >> 8) & 0xff),
1565 (apm_bios_info.version & 0xff),
1566 apm_bios_info.flags,
1567 driver_version);
1568 if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
1569 printk(KERN_INFO "apm: no 32 bit BIOS support\n");
1570 APM_INIT_ERROR_RETURN;
1574 * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
1575 * but is reportedly a 1.0 BIOS.
1577 if (apm_bios_info.version == 0x001)
1578 apm_bios_info.version = 0x100;
1580 /* BIOS < 1.2 doesn't set cseg_16_len */
1581 if (apm_bios_info.version < 0x102)
1582 apm_bios_info.cseg_16_len = 0; /* 64k */
1584 if (debug) {
1585 printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
1586 apm_bios_info.cseg, apm_bios_info.offset,
1587 apm_bios_info.cseg_16, apm_bios_info.dseg);
1588 if (apm_bios_info.version > 0x100)
1589 printk(" cseg len %x, dseg len %x",
1590 apm_bios_info.cseg_len,
1591 apm_bios_info.dseg_len);
1592 if (apm_bios_info.version > 0x101)
1593 printk(" cseg16 len %x", apm_bios_info.cseg_16_len);
1594 printk("\n");
1597 if (apm_disabled) {
1598 printk(KERN_NOTICE "apm: disabled on user request.\n");
1599 APM_INIT_ERROR_RETURN;
1601 if ((smp_num_cpus > 1) && !power_off) {
1602 printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
1603 APM_INIT_ERROR_RETURN;
1605 if (PM_IS_ACTIVE()) {
1606 printk(KERN_NOTICE "apm: overridden by ACPI.\n");
1607 APM_INIT_ERROR_RETURN;
1611 * Set up a segment that references the real mode segment 0x40
1612 * that extends up to the end of page zero (that we have reserved).
1613 * This is for buggy BIOS's that refer to (real mode) segment 0x40
1614 * even though they are called in protected mode.
1616 set_base(gdt[APM_40 >> 3],
1617 __va((unsigned long)0x40 << 4));
1618 _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
1620 apm_bios_entry.offset = apm_bios_info.offset;
1621 apm_bios_entry.segment = APM_CS;
1622 set_base(gdt[APM_CS >> 3],
1623 __va((unsigned long)apm_bios_info.cseg << 4));
1624 set_base(gdt[APM_CS_16 >> 3],
1625 __va((unsigned long)apm_bios_info.cseg_16 << 4));
1626 set_base(gdt[APM_DS >> 3],
1627 __va((unsigned long)apm_bios_info.dseg << 4));
1628 #ifndef APM_RELAX_SEGMENTS
1629 if (apm_bios_info.version == 0x100) {
1630 #endif
1631 /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
1632 _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
1633 /* For some unknown machine. */
1634 _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
1635 /* For the DEC Hinote Ultra CT475 (and others?) */
1636 _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
1637 #ifndef APM_RELAX_SEGMENTS
1638 } else {
1639 _set_limit((char *)&gdt[APM_CS >> 3],
1640 (apm_bios_info.cseg_len - 1) & 0xffff);
1641 _set_limit((char *)&gdt[APM_CS_16 >> 3],
1642 (apm_bios_info.cseg_16_len - 1) & 0xffff);
1643 _set_limit((char *)&gdt[APM_DS >> 3],
1644 (apm_bios_info.dseg_len - 1) & 0xffff);
1646 #endif
1648 create_proc_info_entry("apm", 0, NULL, apm_get_info);
1650 kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
1652 if (smp_num_cpus > 1) {
1653 printk(KERN_NOTICE
1654 "apm: disabled - APM is not SMP safe (power off active).\n");
1655 APM_INIT_ERROR_RETURN;
1658 misc_register(&apm_device);
1660 return 0;
1663 static void __exit apm_exit(void)
1665 misc_deregister(&apm_device);
1666 remove_proc_entry("apm", NULL);
1667 exit_kapmd = 1;
1668 while (kapmd_running)
1669 schedule();
1672 module_init(apm_init);
1673 module_exit(apm_exit);
1675 MODULE_AUTHOR("Stephen Rothwell");
1676 MODULE_DESCRIPTION("Advanced Power Management");
1677 MODULE_PARM(debug, "i");
1678 MODULE_PARM_DESC(debug, "Enable debug mode");
1680 EXPORT_NO_SYMBOLS;