linux/arch/x86/kernel/apm_32.c
<<
>>
Prefs
   1/* -*- linux-c -*-
   2 * APM BIOS driver for Linux
   3 * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au)
   4 *
   5 * Initial development of this driver was funded by NEC Australia P/L
   6 *      and NEC Corporation
   7 *
   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.
  12 *
  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.
  17 *
  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 (sfr@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
  41 * Oct 2001, Version 1.15
  42 * Jan 2002, Version 1.16
  43 * Oct 2002, Version 1.16ac
  44 *
  45 * History:
  46 *    0.6b: first version in official kernel, Linux 1.3.46
  47 *    0.7: changed /proc/apm format, Linux 1.3.58
  48 *    0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
  49 *    0.9: only call bios if bios is present, Linux 1.3.72
  50 *    1.0: use fixed device number, consolidate /proc/apm into this file,
  51 *         Linux 1.3.85
  52 *    1.1: support user-space standby and suspend, power off after system
  53 *         halted, Linux 1.3.98
  54 *    1.2: When resetting RTC after resume, take care so that the time
  55 *         is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
  56 *         <jtoth@princeton.edu>); improve interaction between
  57 *         screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
  58 *    1.2a:Simple change to stop mysterious bug reports with SMP also added
  59 *         levels to the printk calls. APM is not defined for SMP machines.
  60 *         The new replacement for it is, but Linux doesn't yet support this.
  61 *         Alan Cox Linux 2.1.55
  62 *    1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
  63 *    1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
  64 *         Dean Gaudet <dgaudet@arctic.org>.
  65 *         C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
  66 *    1.5: Fix segment register reloading (in case of bad segments saved
  67 *         across BIOS call).
  68 *         Stephen Rothwell
  69 *    1.6: Cope with complier/assembler differences.
  70 *         Only try to turn off the first display device.
  71 *         Fix OOPS at power off with no APM BIOS by Jan Echternach
  72 *                   <echter@informatik.uni-rostock.de>
  73 *         Stephen Rothwell
  74 *    1.7: Modify driver's cached copy of the disabled/disengaged flags
  75 *         to reflect current state of APM BIOS.
  76 *         Chris Rankin <rankinc@bellsouth.net>
  77 *         Reset interrupt 0 timer to 100Hz after suspend
  78 *         Chad Miller <cmiller@surfsouth.com>
  79 *         Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE
  80 *         Richard Gooch <rgooch@atnf.csiro.au>
  81 *         Allow boot time disabling of APM
  82 *         Make boot messages far less verbose by default
  83 *         Make asm safer
  84 *         Stephen Rothwell
  85 *    1.8: Add CONFIG_APM_RTC_IS_GMT
  86 *         Richard Gooch <rgooch@atnf.csiro.au>
  87 *         change APM_NOINTS to CONFIG_APM_ALLOW_INTS
  88 *         remove dependency on CONFIG_PROC_FS
  89 *         Stephen Rothwell
  90 *    1.9: Fix small typo.  <laslo@wodip.opole.pl>
  91 *         Try to cope with BIOS's that need to have all display
  92 *         devices blanked and not just the first one.
  93 *         Ross Paterson <ross@soi.city.ac.uk>
  94 *         Fix segment limit setting it has always been wrong as
  95 *         the segments needed to have byte granularity.
  96 *         Mark a few things __init.
  97 *         Add hack to allow power off of SMP systems by popular request.
  98 *         Use CONFIG_SMP instead of __SMP__
  99 *         Ignore BOUNCES for three seconds.
 100 *         Stephen Rothwell
 101 *   1.10: Fix for Thinkpad return code.
 102 *         Merge 2.2 and 2.3 drivers.
 103 *         Remove APM dependencies in arch/i386/kernel/process.c
 104 *         Remove APM dependencies in drivers/char/sysrq.c
 105 *         Reset time across standby.
 106 *         Allow more inititialisation on SMP.
 107 *         Remove CONFIG_APM_POWER_OFF and make it boot time
 108 *         configurable (default on).
 109 *         Make debug only a boot time parameter (remove APM_DEBUG).
 110 *         Try to blank all devices on any error.
 111 *   1.11: Remove APM dependencies in drivers/char/console.c
 112 *         Check nr_running to detect if we are idle (from
 113 *         Borislav Deianov <borislav@lix.polytechnique.fr>)
 114 *         Fix for bioses that don't zero the top part of the
 115 *         entrypoint offset (Mario Sitta <sitta@al.unipmn.it>)
 116 *         (reported by Panos Katsaloulis <teras@writeme.com>).
 117 *         Real mode power off patch (Walter Hofmann
 118 *         <Walter.Hofmann@physik.stud.uni-erlangen.de>).
 119 *   1.12: Remove CONFIG_SMP as the compiler will optimize
 120 *         the code away anyway (smp_num_cpus == 1 in UP)
 121 *         noted by Artur Skawina <skawina@geocities.com>.
 122 *         Make power off under SMP work again.
 123 *         Fix thinko with initial engaging of BIOS.
 124 *         Make sure power off only happens on CPU 0
 125 *         (Paul "Rusty" Russell <rusty@rustcorp.com.au>).
 126 *         Do error notification to user mode if BIOS calls fail.
 127 *         Move entrypoint offset fix to ...boot/setup.S
 128 *         where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>).
 129 *         Remove smp-power-off. SMP users must now specify
 130 *         "apm=power-off" on the kernel command line. Suggested
 131 *         by Jim Avera <jima@hal.com>, modified by Alan Cox
 132 *         <alan@lxorguk.ukuu.org.uk>.
 133 *         Register the /proc/apm entry even on SMP so that
 134 *         scripts that check for it before doing power off
 135 *         work (Jim Avera <jima@hal.com>).
 136 *   1.13: Changes for new pm_ interfaces (Andy Henroid
 137 *         <andy_henroid@yahoo.com>).
 138 *         Modularize the code.
 139 *         Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS
 140 *         is now the way life works).
 141 *         Fix thinko in suspend() (wrong return).
 142 *         Notify drivers on critical suspend.
 143 *         Make kapmd absorb more idle time (Pavel Machek <pavel@ucw.cz>
 144 *         modified by sfr).
 145 *         Disable interrupts while we are suspended (Andy Henroid
 146 *         <andy_henroid@yahoo.com> fixed by sfr).
 147 *         Make power off work on SMP again (Tony Hoyle
 148 *         <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr.
 149 *         Remove CONFIG_APM_SUSPEND_BOUNCE.  The bounce ignore
 150 *         interval is now configurable.
 151 *   1.14: Make connection version persist across module unload/load.
 152 *         Enable and engage power management earlier.
 153 *         Disengage power management on module unload.
 154 *         Changed to use the sysrq-register hack for registering the
 155 *         power off function called by magic sysrq based upon discussions
 156 *         in irc://irc.openprojects.net/#kernelnewbies
 157 *         (Crutcher Dunnavant <crutcher+kernel@datastacks.com>).
 158 *         Make CONFIG_APM_REAL_MODE_POWER_OFF run time configurable.
 159 *         (Arjan van de Ven <arjanv@redhat.com>) modified by sfr.
 160 *         Work around byte swap bug in one of the Vaio's BIOS's
 161 *         (Marc Boucher <marc@mbsi.ca>).
 162 *         Exposed the disable flag to dmi so that we can handle known
 163 *         broken APM (Alan Cox <alan@lxorguk.ukuu.org.uk>).
 164 *   1.14ac: If the BIOS says "I slowed the CPU down" then don't spin
 165 *         calling it - instead idle. (Alan Cox <alan@lxorguk.ukuu.org.uk>)
 166 *         If an APM idle fails log it and idle sensibly
 167 *   1.15: Don't queue events to clients who open the device O_WRONLY.
 168 *         Don't expect replies from clients who open the device O_RDONLY.
 169 *         (Idea from Thomas Hood)
 170 *         Minor waitqueue cleanups. (John Fremlin <chief@bandits.org>)
 171 *   1.16: Fix idle calling. (Andreas Steinmetz <ast@domdv.de> et al.)
 172 *         Notify listeners of standby or suspend events before notifying
 173 *         drivers. Return EBUSY to ioctl() if suspend is rejected.
 174 *         (Russell King <rmk@arm.linux.org.uk> and Thomas Hood)
 175 *         Ignore first resume after we generate our own resume event
 176 *         after a suspend (Thomas Hood)
 177 *         Daemonize now gets rid of our controlling terminal (sfr).
 178 *         CONFIG_APM_CPU_IDLE now just affects the default value of
 179 *         idle_threshold (sfr).
 180 *         Change name of kernel apm daemon (as it no longer idles) (sfr).
 181 *   1.16ac: Fix up SMP support somewhat. You can now force SMP on and we
 182 *         make _all_ APM calls on the CPU#0. Fix unsafe sign bug.
 183 *         TODO: determine if its "boot CPU" or "CPU0" we want to lock to.
 184 *
 185 * APM 1.1 Reference:
 186 *
 187 *   Intel Corporation, Microsoft Corporation. Advanced Power Management
 188 *   (APM) BIOS Interface Specification, Revision 1.1, September 1993.
 189 *   Intel Order Number 241704-001.  Microsoft Part Number 781-110-X01.
 190 *
 191 * [This document is available free from Intel by calling 800.628.8686 (fax
 192 * 916.356.6100) or 800.548.4725; or from
 193 * http://www.microsoft.com/whdc/archive/amp_12.mspx  It is also
 194 * available from Microsoft by calling 206.882.8080.]
 195 *
 196 * APM 1.2 Reference:
 197 *   Intel Corporation, Microsoft Corporation. Advanced Power Management
 198 *   (APM) BIOS Interface Specification, Revision 1.2, February 1996.
 199 *
 200 * [This document is available from Microsoft at:
 201 *    http://www.microsoft.com/whdc/archive/amp_12.mspx]
 202 */
 203
 204#include <linux/module.h>
 205
 206#include <linux/poll.h>
 207#include <linux/types.h>
 208#include <linux/stddef.h>
 209#include <linux/timer.h>
 210#include <linux/fcntl.h>
 211#include <linux/slab.h>
 212#include <linux/stat.h>
 213#include <linux/proc_fs.h>
 214#include <linux/seq_file.h>
 215#include <linux/miscdevice.h>
 216#include <linux/apm_bios.h>
 217#include <linux/init.h>
 218#include <linux/time.h>
 219#include <linux/sched.h>
 220#include <linux/pm.h>
 221#include <linux/capability.h>
 222#include <linux/device.h>
 223#include <linux/kernel.h>
 224#include <linux/freezer.h>
 225#include <linux/smp.h>
 226#include <linux/dmi.h>
 227#include <linux/suspend.h>
 228#include <linux/kthread.h>
 229#include <linux/jiffies.h>
 230
 231#include <asm/system.h>
 232#include <asm/uaccess.h>
 233#include <asm/desc.h>
 234#include <asm/i8253.h>
 235#include <asm/olpc.h>
 236#include <asm/paravirt.h>
 237#include <asm/reboot.h>
 238
 239#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 240extern int (*console_blank_hook)(int);
 241#endif
 242
 243/*
 244 * The apm_bios device is one of the misc char devices.
 245 * This is its minor number.
 246 */
 247#define APM_MINOR_DEV   134
 248
 249/*
 250 * See Documentation/Config.help for the configuration options.
 251 *
 252 * Various options can be changed at boot time as follows:
 253 * (We allow underscores for compatibility with the modules code)
 254 *      apm=on/off                      enable/disable APM
 255 *          [no-]allow[-_]ints          allow interrupts during BIOS calls
 256 *          [no-]broken[-_]psr          BIOS has a broken GetPowerStatus call
 257 *          [no-]realmode[-_]power[-_]off       switch to real mode before
 258 *                                              powering off
 259 *          [no-]debug                  log some debugging messages
 260 *          [no-]power[-_]off           power off on shutdown
 261 *          [no-]smp                    Use apm even on an SMP box
 262 *          bounce[-_]interval=<n>      number of ticks to ignore suspend
 263 *                                      bounces
 264 *          idle[-_]threshold=<n>       System idle percentage above which to
 265 *                                      make APM BIOS idle calls. Set it to
 266 *                                      100 to disable.
 267 *          idle[-_]period=<n>          Period (in 1/100s of a second) over
 268 *                                      which the idle percentage is
 269 *                                      calculated.
 270 */
 271
 272/* KNOWN PROBLEM MACHINES:
 273 *
 274 * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
 275 *                         [Confirmed by TI representative]
 276 * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
 277 *                    [Confirmed by BIOS disassembly]
 278 *                    [This may work now ...]
 279 * P: Toshiba 1950S: battery life information only gets updated after resume
 280 * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
 281 *      broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
 282 * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP
 283 *      Neale Banks <neale@lowendale.com.au> December 2000
 284 *
 285 * Legend: U = unusable with APM patches
 286 *         P = partially usable with APM patches
 287 */
 288
 289/*
 290 * Define as 1 to make the driver always call the APM BIOS busy
 291 * routine even if the clock was not reported as slowed by the
 292 * idle routine.  Otherwise, define as 0.
 293 */
 294#define ALWAYS_CALL_BUSY   1
 295
 296/*
 297 * Define to make the APM BIOS calls zero all data segment registers (so
 298 * that an incorrect BIOS implementation will cause a kernel panic if it
 299 * tries to write to arbitrary memory).
 300 */
 301#define APM_ZERO_SEGS
 302
 303#include <asm/apm.h>
 304
 305/*
 306 * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
 307 * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
 308 * David Chen <chen@ctpa04.mit.edu>
 309 */
 310#undef INIT_TIMER_AFTER_SUSPEND
 311
 312#ifdef INIT_TIMER_AFTER_SUSPEND
 313#include <linux/timex.h>
 314#include <asm/io.h>
 315#include <linux/delay.h>
 316#endif
 317
 318/*
 319 * Need to poll the APM BIOS every second
 320 */
 321#define APM_CHECK_TIMEOUT       (HZ)
 322
 323/*
 324 * Ignore suspend events for this amount of time after a resume
 325 */
 326#define DEFAULT_BOUNCE_INTERVAL (3 * HZ)
 327
 328/*
 329 * Maximum number of events stored
 330 */
 331#define APM_MAX_EVENTS          20
 332
 333/*
 334 * The per-file APM data
 335 */
 336struct apm_user {
 337        int             magic;
 338        struct apm_user *next;
 339        unsigned int    suser: 1;
 340        unsigned int    writer: 1;
 341        unsigned int    reader: 1;
 342        unsigned int    suspend_wait: 1;
 343        int             suspend_result;
 344        int             suspends_pending;
 345        int             standbys_pending;
 346        int             suspends_read;
 347        int             standbys_read;
 348        int             event_head;
 349        int             event_tail;
 350        apm_event_t     events[APM_MAX_EVENTS];
 351};
 352
 353/*
 354 * The magic number in apm_user
 355 */
 356#define APM_BIOS_MAGIC          0x4101
 357
 358/*
 359 * idle percentage above which bios idle calls are done
 360 */
 361#ifdef CONFIG_APM_CPU_IDLE
 362#define DEFAULT_IDLE_THRESHOLD  95
 363#else
 364#define DEFAULT_IDLE_THRESHOLD  100
 365#endif
 366#define DEFAULT_IDLE_PERIOD     (100 / 3)
 367
 368/*
 369 * Local variables
 370 */
 371static struct {
 372        unsigned long   offset;
 373        unsigned short  segment;
 374} apm_bios_entry;
 375static int clock_slowed;
 376static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
 377static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
 378static int set_pm_idle;
 379static int suspends_pending;
 380static int standbys_pending;
 381static int ignore_sys_suspend;
 382static int ignore_normal_resume;
 383static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
 384
 385static int debug __read_mostly;
 386static int smp __read_mostly;
 387static int apm_disabled = -1;
 388#ifdef CONFIG_SMP
 389static int power_off;
 390#else
 391static int power_off = 1;
 392#endif
 393static int realmode_power_off;
 394#ifdef CONFIG_APM_ALLOW_INTS
 395static int allow_ints = 1;
 396#else
 397static int allow_ints;
 398#endif
 399static int broken_psr;
 400
 401static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 402static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 403static struct apm_user *user_list;
 404static DEFINE_SPINLOCK(user_list_lock);
 405static DEFINE_MUTEX(apm_mutex);
 406
 407/*
 408 * Set up a segment that references the real mode segment 0x40
 409 * that extends up to the end of page zero (that we have reserved).
 410 * This is for buggy BIOS's that refer to (real mode) segment 0x40
 411 * even though they are called in protected mode.
 412 */
 413static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092,
 414                        (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1);
 415
 416static const char driver_version[] = "1.16ac";  /* no spaces */
 417
 418static struct task_struct *kapmd_task;
 419
 420/*
 421 *      APM event names taken from the APM 1.2 specification. These are
 422 *      the message codes that the BIOS uses to tell us about events
 423 */
 424static const char * const apm_event_name[] = {
 425        "system standby",
 426        "system suspend",
 427        "normal resume",
 428        "critical resume",
 429        "low battery",
 430        "power status change",
 431        "update time",
 432        "critical suspend",
 433        "user standby",
 434        "user suspend",
 435        "system standby resume",
 436        "capabilities change"
 437};
 438#define NR_APM_EVENT_NAME ARRAY_SIZE(apm_event_name)
 439
 440typedef struct lookup_t {
 441        int     key;
 442        char    *msg;
 443} lookup_t;
 444
 445/*
 446 *      The BIOS returns a set of standard error codes in AX when the
 447 *      carry flag is set.
 448 */
 449
 450static const lookup_t error_table[] = {
 451/* N/A  { APM_SUCCESS,          "Operation succeeded" }, */
 452        { APM_DISABLED,         "Power management disabled" },
 453        { APM_CONNECTED,        "Real mode interface already connected" },
 454        { APM_NOT_CONNECTED,    "Interface not connected" },
 455        { APM_16_CONNECTED,     "16 bit interface already connected" },
 456/* N/A  { APM_16_UNSUPPORTED,   "16 bit interface not supported" }, */
 457        { APM_32_CONNECTED,     "32 bit interface already connected" },
 458        { APM_32_UNSUPPORTED,   "32 bit interface not supported" },
 459        { APM_BAD_DEVICE,       "Unrecognized device ID" },
 460        { APM_BAD_PARAM,        "Parameter out of range" },
 461        { APM_NOT_ENGAGED,      "Interface not engaged" },
 462        { APM_BAD_FUNCTION,     "Function not supported" },
 463        { APM_RESUME_DISABLED,  "Resume timer disabled" },
 464        { APM_BAD_STATE,        "Unable to enter requested state" },
 465/* N/A  { APM_NO_EVENTS,        "No events pending" }, */
 466        { APM_NO_ERROR,         "BIOS did not set a return code" },
 467        { APM_NOT_PRESENT,      "No APM present" }
 468};
 469#define ERROR_COUNT     ARRAY_SIZE(error_table)
 470
 471/**
 472 *      apm_error       -       display an APM error
 473 *      @str: information string
 474 *      @err: APM BIOS return code
 475 *
 476 *      Write a meaningful log entry to the kernel log in the event of
 477 *      an APM error.  Note that this also handles (negative) kernel errors.
 478 */
 479
 480static void apm_error(char *str, int err)
 481{
 482        int i;
 483
 484        for (i = 0; i < ERROR_COUNT; i++)
 485                if (error_table[i].key == err)
 486                        break;
 487        if (i < ERROR_COUNT)
 488                printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
 489        else if (err < 0)
 490                printk(KERN_NOTICE "apm: %s: linux error code %i\n", str, err);
 491        else
 492                printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
 493                       str, err);
 494}
 495
 496/*
 497 * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
 498 * apm_info.allow_ints, we are being really paranoid here!  Not only
 499 * are interrupts disabled, but all the segment registers (except SS)
 500 * are saved and zeroed this means that if the BIOS tries to reference
 501 * any data without explicitly loading the segment registers, the kernel
 502 * will fault immediately rather than have some unforeseen circumstances
 503 * for the rest of the kernel.  And it will be very obvious!  :-) Doing
 504 * this depends on CS referring to the same physical memory as DS so that
 505 * DS can be zeroed before the call. Unfortunately, we can't do anything
 506 * about the stack segment/pointer.  Also, we tell the compiler that
 507 * everything could change.
 508 *
 509 * Also, we KNOW that for the non error case of apm_bios_call, there
 510 * is no useful data returned in the low order 8 bits of eax.
 511 */
 512
 513static inline unsigned long __apm_irq_save(void)
 514{
 515        unsigned long flags;
 516        local_save_flags(flags);
 517        if (apm_info.allow_ints) {
 518                if (irqs_disabled_flags(flags))
 519                        local_irq_enable();
 520        } else
 521                local_irq_disable();
 522
 523        return flags;
 524}
 525
 526#define apm_irq_save(flags) \
 527        do { flags = __apm_irq_save(); } while (0)
 528
 529static inline void apm_irq_restore(unsigned long flags)
 530{
 531        if (irqs_disabled_flags(flags))
 532                local_irq_disable();
 533        else if (irqs_disabled())
 534                local_irq_enable();
 535}
 536
 537#ifdef APM_ZERO_SEGS
 538#       define APM_DECL_SEGS \
 539                unsigned int saved_fs; unsigned int saved_gs;
 540#       define APM_DO_SAVE_SEGS \
 541                savesegment(fs, saved_fs); savesegment(gs, saved_gs)
 542#       define APM_DO_RESTORE_SEGS \
 543                loadsegment(fs, saved_fs); loadsegment(gs, saved_gs)
 544#else
 545#       define APM_DECL_SEGS
 546#       define APM_DO_SAVE_SEGS
 547#       define APM_DO_RESTORE_SEGS
 548#endif
 549
 550struct apm_bios_call {
 551        u32 func;
 552        /* In and out */
 553        u32 ebx;
 554        u32 ecx;
 555        /* Out only */
 556        u32 eax;
 557        u32 edx;
 558        u32 esi;
 559
 560        /* Error: -ENOMEM, or bits 8-15 of eax */
 561        int err;
 562};
 563
 564/**
 565 *      __apm_bios_call - Make an APM BIOS 32bit call
 566 *      @_call: pointer to struct apm_bios_call.
 567 *
 568 *      Make an APM call using the 32bit protected mode interface. The
 569 *      caller is responsible for knowing if APM BIOS is configured and
 570 *      enabled. This call can disable interrupts for a long period of
 571 *      time on some laptops.  The return value is in AH and the carry
 572 *      flag is loaded into AL.  If there is an error, then the error
 573 *      code is returned in AH (bits 8-15 of eax) and this function
 574 *      returns non-zero.
 575 *
 576 *      Note: this makes the call on the current CPU.
 577 */
 578static long __apm_bios_call(void *_call)
 579{
 580        APM_DECL_SEGS
 581        unsigned long           flags;
 582        int                     cpu;
 583        struct desc_struct      save_desc_40;
 584        struct desc_struct      *gdt;
 585        struct apm_bios_call    *call = _call;
 586
 587        cpu = get_cpu();
 588        BUG_ON(cpu != 0);
 589        gdt = get_cpu_gdt_table(cpu);
 590        save_desc_40 = gdt[0x40 / 8];
 591        gdt[0x40 / 8] = bad_bios_desc;
 592
 593        apm_irq_save(flags);
 594        APM_DO_SAVE_SEGS;
 595        apm_bios_call_asm(call->func, call->ebx, call->ecx,
 596                          &call->eax, &call->ebx, &call->ecx, &call->edx,
 597                          &call->esi);
 598        APM_DO_RESTORE_SEGS;
 599        apm_irq_restore(flags);
 600        gdt[0x40 / 8] = save_desc_40;
 601        put_cpu();
 602
 603        return call->eax & 0xff;
 604}
 605
 606/* Run __apm_bios_call or __apm_bios_call_simple on CPU 0 */
 607static int on_cpu0(long (*fn)(void *), struct apm_bios_call *call)
 608{
 609        int ret;
 610
 611        /* Don't bother with work_on_cpu in the common case, so we don't
 612         * have to worry about OOM or overhead. */
 613        if (get_cpu() == 0) {
 614                ret = fn(call);
 615                put_cpu();
 616        } else {
 617                put_cpu();
 618                ret = work_on_cpu(0, fn, call);
 619        }
 620
 621        /* work_on_cpu can fail with -ENOMEM */
 622        if (ret < 0)
 623                call->err = ret;
 624        else
 625                call->err = (call->eax >> 8) & 0xff;
 626
 627        return ret;
 628}
 629
 630/**
 631 *      apm_bios_call   -       Make an APM BIOS 32bit call (on CPU 0)
 632 *      @call: the apm_bios_call registers.
 633 *
 634 *      If there is an error, it is returned in @call.err.
 635 */
 636static int apm_bios_call(struct apm_bios_call *call)
 637{
 638        return on_cpu0(__apm_bios_call, call);
 639}
 640
 641/**
 642 *      __apm_bios_call_simple - Make an APM BIOS 32bit call (on CPU 0)
 643 *      @_call: pointer to struct apm_bios_call.
 644 *
 645 *      Make a BIOS call that returns one value only, or just status.
 646 *      If there is an error, then the error code is returned in AH
 647 *      (bits 8-15 of eax) and this function returns non-zero (it can
 648 *      also return -ENOMEM). This is used for simpler BIOS operations.
 649 *      This call may hold interrupts off for a long time on some laptops.
 650 *
 651 *      Note: this makes the call on the current CPU.
 652 */
 653static long __apm_bios_call_simple(void *_call)
 654{
 655        u8                      error;
 656        APM_DECL_SEGS
 657        unsigned long           flags;
 658        int                     cpu;
 659        struct desc_struct      save_desc_40;
 660        struct desc_struct      *gdt;
 661        struct apm_bios_call    *call = _call;
 662
 663        cpu = get_cpu();
 664        BUG_ON(cpu != 0);
 665        gdt = get_cpu_gdt_table(cpu);
 666        save_desc_40 = gdt[0x40 / 8];
 667        gdt[0x40 / 8] = bad_bios_desc;
 668
 669        apm_irq_save(flags);
 670        APM_DO_SAVE_SEGS;
 671        error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
 672                                         &call->eax);
 673        APM_DO_RESTORE_SEGS;
 674        apm_irq_restore(flags);
 675        gdt[0x40 / 8] = save_desc_40;
 676        put_cpu();
 677        return error;
 678}
 679
 680/**
 681 *      apm_bios_call_simple    -       make a simple APM BIOS 32bit call
 682 *      @func: APM function to invoke
 683 *      @ebx_in: EBX register value for BIOS call
 684 *      @ecx_in: ECX register value for BIOS call
 685 *      @eax: EAX register on return from the BIOS call
 686 *      @err: bits
 687 *
 688 *      Make a BIOS call that returns one value only, or just status.
 689 *      If there is an error, then the error code is returned in @err
 690 *      and this function returns non-zero. This is used for simpler
 691 *      BIOS operations.  This call may hold interrupts off for a long
 692 *      time on some laptops.
 693 */
 694static int apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax,
 695                                int *err)
 696{
 697        struct apm_bios_call call;
 698        int ret;
 699
 700        call.func = func;
 701        call.ebx = ebx_in;
 702        call.ecx = ecx_in;
 703
 704        ret = on_cpu0(__apm_bios_call_simple, &call);
 705        *eax = call.eax;
 706        *err = call.err;
 707        return ret;
 708}
 709
 710/**
 711 *      apm_driver_version      -       APM driver version
 712 *      @val:   loaded with the APM version on return
 713 *
 714 *      Retrieve the APM version supported by the BIOS. This is only
 715 *      supported for APM 1.1 or higher. An error indicates APM 1.0 is
 716 *      probably present.
 717 *
 718 *      On entry val should point to a value indicating the APM driver
 719 *      version with the high byte being the major and the low byte the
 720 *      minor number both in BCD
 721 *
 722 *      On return it will hold the BIOS revision supported in the
 723 *      same format.
 724 */
 725
 726static int apm_driver_version(u_short *val)
 727{
 728        u32 eax;
 729        int err;
 730
 731        if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax, &err))
 732                return err;
 733        *val = eax;
 734        return APM_SUCCESS;
 735}
 736
 737/**
 738 *      apm_get_event   -       get an APM event from the BIOS
 739 *      @event: pointer to the event
 740 *      @info: point to the event information
 741 *
 742 *      The APM BIOS provides a polled information for event
 743 *      reporting. The BIOS expects to be polled at least every second
 744 *      when events are pending. When a message is found the caller should
 745 *      poll until no more messages are present.  However, this causes
 746 *      problems on some laptops where a suspend event notification is
 747 *      not cleared until it is acknowledged.
 748 *
 749 *      Additional information is returned in the info pointer, providing
 750 *      that APM 1.2 is in use. If no messges are pending the value 0x80
 751 *      is returned (No power management events pending).
 752 */
 753static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
 754{
 755        struct apm_bios_call call;
 756
 757        call.func = APM_FUNC_GET_EVENT;
 758        call.ebx = call.ecx = 0;
 759
 760        if (apm_bios_call(&call))
 761                return call.err;
 762
 763        *event = call.ebx;
 764        if (apm_info.connection_version < 0x0102)
 765                *info = ~0; /* indicate info not valid */
 766        else
 767                *info = call.ecx;
 768        return APM_SUCCESS;
 769}
 770
 771/**
 772 *      set_power_state -       set the power management state
 773 *      @what: which items to transition
 774 *      @state: state to transition to
 775 *
 776 *      Request an APM change of state for one or more system devices. The
 777 *      processor state must be transitioned last of all. what holds the
 778 *      class of device in the upper byte and the device number (0xFF for
 779 *      all) for the object to be transitioned.
 780 *
 781 *      The state holds the state to transition to, which may in fact
 782 *      be an acceptance of a BIOS requested state change.
 783 */
 784
 785static int set_power_state(u_short what, u_short state)
 786{
 787        u32 eax;
 788        int err;
 789
 790        if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax, &err))
 791                return err;
 792        return APM_SUCCESS;
 793}
 794
 795/**
 796 *      set_system_power_state - set system wide power state
 797 *      @state: which state to enter
 798 *
 799 *      Transition the entire system into a new APM power state.
 800 */
 801
 802static int set_system_power_state(u_short state)
 803{
 804        return set_power_state(APM_DEVICE_ALL, state);
 805}
 806
 807/**
 808 *      apm_do_idle     -       perform power saving
 809 *
 810 *      This function notifies the BIOS that the processor is (in the view
 811 *      of the OS) idle. It returns -1 in the event that the BIOS refuses
 812 *      to handle the idle request. On a success the function returns 1
 813 *      if the BIOS did clock slowing or 0 otherwise.
 814 */
 815
 816static int apm_do_idle(void)
 817{
 818        u32 eax;
 819        u8 ret = 0;
 820        int idled = 0;
 821        int polling;
 822        int err = 0;
 823
 824        polling = !!(current_thread_info()->status & TS_POLLING);
 825        if (polling) {
 826                current_thread_info()->status &= ~TS_POLLING;
 827                /*
 828                 * TS_POLLING-cleared state must be visible before we
 829                 * test NEED_RESCHED:
 830                 */
 831                smp_mb();
 832        }
 833        if (!need_resched()) {
 834                idled = 1;
 835                ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax, &err);
 836        }
 837        if (polling)
 838                current_thread_info()->status |= TS_POLLING;
 839
 840        if (!idled)
 841                return 0;
 842
 843        if (ret) {
 844                static unsigned long t;
 845
 846                /* This always fails on some SMP boards running UP kernels.
 847                 * Only report the failure the first 5 times.
 848                 */
 849                if (++t < 5) {
 850                        printk(KERN_DEBUG "apm_do_idle failed (%d)\n", err);
 851                        t = jiffies;
 852                }
 853                return -1;
 854        }
 855        clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
 856        return clock_slowed;
 857}
 858
 859/**
 860 *      apm_do_busy     -       inform the BIOS the CPU is busy
 861 *
 862 *      Request that the BIOS brings the CPU back to full performance.
 863 */
 864
 865static void apm_do_busy(void)
 866{
 867        u32 dummy;
 868        int err;
 869
 870        if (clock_slowed || ALWAYS_CALL_BUSY) {
 871                (void)apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy, &err);
 872                clock_slowed = 0;
 873        }
 874}
 875
 876/*
 877 * If no process has really been interested in
 878 * the CPU for some time, we want to call BIOS
 879 * power management - we probably want
 880 * to conserve power.
 881 */
 882#define IDLE_CALC_LIMIT (HZ * 100)
 883#define IDLE_LEAKY_MAX  16
 884
 885static void (*original_pm_idle)(void) __read_mostly;
 886
 887/**
 888 * apm_cpu_idle         -       cpu idling for APM capable Linux
 889 *
 890 * This is the idling function the kernel executes when APM is available. It
 891 * tries to do BIOS powermanagement based on the average system idle time.
 892 * Furthermore it calls the system default idle routine.
 893 */
 894
 895static void apm_cpu_idle(void)
 896{
 897        static int use_apm_idle; /* = 0 */
 898        static unsigned int last_jiffies; /* = 0 */
 899        static unsigned int last_stime; /* = 0 */
 900
 901        int apm_idle_done = 0;
 902        unsigned int jiffies_since_last_check = jiffies - last_jiffies;
 903        unsigned int bucket;
 904
 905recalc:
 906        if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
 907                use_apm_idle = 0;
 908                last_jiffies = jiffies;
 909                last_stime = current->stime;
 910        } else if (jiffies_since_last_check > idle_period) {
 911                unsigned int idle_percentage;
 912
 913                idle_percentage = current->stime - last_stime;
 914                idle_percentage *= 100;
 915                idle_percentage /= jiffies_since_last_check;
 916                use_apm_idle = (idle_percentage > idle_threshold);
 917                if (apm_info.forbid_idle)
 918                        use_apm_idle = 0;
 919                last_jiffies = jiffies;
 920                last_stime = current->stime;
 921        }
 922
 923        bucket = IDLE_LEAKY_MAX;
 924
 925        while (!need_resched()) {
 926                if (use_apm_idle) {
 927                        unsigned int t;
 928
 929                        t = jiffies;
 930                        switch (apm_do_idle()) {
 931                        case 0:
 932                                apm_idle_done = 1;
 933                                if (t != jiffies) {
 934                                        if (bucket) {
 935                                                bucket = IDLE_LEAKY_MAX;
 936                                                continue;
 937                                        }
 938                                } else if (bucket) {
 939                                        bucket--;
 940                                        continue;
 941                                }
 942                                break;
 943                        case 1:
 944                                apm_idle_done = 1;
 945                                break;
 946                        default: /* BIOS refused */
 947                                break;
 948                        }
 949                }
 950                if (original_pm_idle)
 951                        original_pm_idle();
 952                else
 953                        default_idle();
 954                local_irq_disable();
 955                jiffies_since_last_check = jiffies - last_jiffies;
 956                if (jiffies_since_last_check > idle_period)
 957                        goto recalc;
 958        }
 959
 960        if (apm_idle_done)
 961                apm_do_busy();
 962
 963        local_irq_enable();
 964}
 965
 966/**
 967 *      apm_power_off   -       ask the BIOS to power off
 968 *
 969 *      Handle the power off sequence. This is the one piece of code we
 970 *      will execute even on SMP machines. In order to deal with BIOS
 971 *      bugs we support real mode APM BIOS power off calls. We also make
 972 *      the SMP call on CPU0 as some systems will only honour this call
 973 *      on their first cpu.
 974 */
 975
 976static void apm_power_off(void)
 977{
 978        unsigned char po_bios_call[] = {
 979                0xb8, 0x00, 0x10,       /* movw  $0x1000,ax  */
 980                0x8e, 0xd0,             /* movw  ax,ss       */
 981                0xbc, 0x00, 0xf0,       /* movw  $0xf000,sp  */
 982                0xb8, 0x07, 0x53,       /* movw  $0x5307,ax  */
 983                0xbb, 0x01, 0x00,       /* movw  $0x0001,bx  */
 984                0xb9, 0x03, 0x00,       /* movw  $0x0003,cx  */
 985                0xcd, 0x15              /* int   $0x15       */
 986        };
 987
 988        /* Some bioses don't like being called from CPU != 0 */
 989        if (apm_info.realmode_power_off) {
 990                set_cpus_allowed_ptr(current, cpumask_of(0));
 991                machine_real_restart(po_bios_call, sizeof(po_bios_call));
 992        } else {
 993                (void)set_system_power_state(APM_STATE_OFF);
 994        }
 995}
 996
 997#ifdef CONFIG_APM_DO_ENABLE
 998
 999/**
1000 *      apm_enable_power_management - enable BIOS APM power management
1001 *      @enable: enable yes/no
1002 *
1003 *      Enable or disable the APM BIOS power services.
1004 */
1005
1006static int apm_enable_power_management(int enable)
1007{
1008        u32 eax;
1009        int err;
1010
1011        if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
1012                return APM_NOT_ENGAGED;
1013        if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
1014                                 enable, &eax, &err))
1015                return err;
1016        if (enable)
1017                apm_info.bios.flags &= ~APM_BIOS_DISABLED;
1018        else
1019                apm_info.bios.flags |= APM_BIOS_DISABLED;
1020        return APM_SUCCESS;
1021}
1022#endif
1023
1024/**
1025 *      apm_get_power_status    -       get current power state
1026 *      @status: returned status
1027 *      @bat: battery info
1028 *      @life: estimated life
1029 *
1030 *      Obtain the current power status from the APM BIOS. We return a
1031 *      status which gives the rough battery status, and current power
1032 *      source. The bat value returned give an estimate as a percentage
1033 *      of life and a status value for the battery. The estimated life
1034 *      if reported is a lifetime in secodnds/minutes at current powwer
1035 *      consumption.
1036 */
1037
1038static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
1039{
1040        struct apm_bios_call call;
1041
1042        call.func = APM_FUNC_GET_STATUS;
1043        call.ebx = APM_DEVICE_ALL;
1044        call.ecx = 0;
1045
1046        if (apm_info.get_power_status_broken)
1047                return APM_32_UNSUPPORTED;
1048        if (apm_bios_call(&call))
1049                return call.err;
1050        *status = call.ebx;
1051        *bat = call.ecx;
1052        if (apm_info.get_power_status_swabinminutes) {
1053                *life = swab16((u16)call.edx);
1054                *life |= 0x8000;
1055        } else
1056                *life = call.edx;
1057        return APM_SUCCESS;
1058}
1059
1060#if 0
1061static int apm_get_battery_status(u_short which, u_short *status,
1062                                  u_short *bat, u_short *life, u_short *nbat)
1063{
1064        u32 eax;
1065        u32 ebx;
1066        u32 ecx;
1067        u32 edx;
1068        u32 esi;
1069
1070        if (apm_info.connection_version < 0x0102) {
1071                /* pretend we only have one battery. */
1072                if (which != 1)
1073                        return APM_BAD_DEVICE;
1074                *nbat = 1;
1075                return apm_get_power_status(status, bat, life);
1076        }
1077
1078        if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
1079                          &ebx, &ecx, &edx, &esi))
1080                return (eax >> 8) & 0xff;
1081        *status = ebx;
1082        *bat = ecx;
1083        *life = edx;
1084        *nbat = esi;
1085        return APM_SUCCESS;
1086}
1087#endif
1088
1089/**
1090 *      apm_engage_power_management     -       enable PM on a device
1091 *      @device: identity of device
1092 *      @enable: on/off
1093 *
1094 *      Activate or deactive power management on either a specific device
1095 *      or the entire system (%APM_DEVICE_ALL).
1096 */
1097
1098static int apm_engage_power_management(u_short device, int enable)
1099{
1100        u32 eax;
1101        int err;
1102
1103        if ((enable == 0) && (device == APM_DEVICE_ALL)
1104            && (apm_info.bios.flags & APM_BIOS_DISABLED))
1105                return APM_DISABLED;
1106        if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable,
1107                                 &eax, &err))
1108                return err;
1109        if (device == APM_DEVICE_ALL) {
1110                if (enable)
1111                        apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
1112                else
1113                        apm_info.bios.flags |= APM_BIOS_DISENGAGED;
1114        }
1115        return APM_SUCCESS;
1116}
1117
1118#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1119
1120/**
1121 *      apm_console_blank       -       blank the display
1122 *      @blank: on/off
1123 *
1124 *      Attempt to blank the console, firstly by blanking just video device
1125 *      zero, and if that fails (some BIOSes don't support it) then it blanks
1126 *      all video devices. Typically the BIOS will do laptop backlight and
1127 *      monitor powerdown for us.
1128 */
1129
1130static int apm_console_blank(int blank)
1131{
1132        int error = APM_NOT_ENGAGED; /* silence gcc */
1133        int i;
1134        u_short state;
1135        static const u_short dev[3] = { 0x100, 0x1FF, 0x101 };
1136
1137        state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
1138
1139        for (i = 0; i < ARRAY_SIZE(dev); i++) {
1140                error = set_power_state(dev[i], state);
1141
1142                if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
1143                        return 1;
1144
1145                if (error == APM_NOT_ENGAGED)
1146                        break;
1147        }
1148
1149        if (error == APM_NOT_ENGAGED) {
1150                static int tried;
1151                int eng_error;
1152                if (tried++ == 0) {
1153                        eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1154                        if (eng_error) {
1155                                apm_error("set display", error);
1156                                apm_error("engage interface", eng_error);
1157                                return 0;
1158                        } else
1159                                return apm_console_blank(blank);
1160                }
1161        }
1162        apm_error("set display", error);
1163        return 0;
1164}
1165#endif
1166
1167static int queue_empty(struct apm_user *as)
1168{
1169        return as->event_head == as->event_tail;
1170}
1171
1172static apm_event_t get_queued_event(struct apm_user *as)
1173{
1174        if (++as->event_tail >= APM_MAX_EVENTS)
1175                as->event_tail = 0;
1176        return as->events[as->event_tail];
1177}
1178
1179static void queue_event(apm_event_t event, struct apm_user *sender)
1180{
1181        struct apm_user *as;
1182
1183        spin_lock(&user_list_lock);
1184        if (user_list == NULL)
1185                goto out;
1186        for (as = user_list; as != NULL; as = as->next) {
1187                if ((as == sender) || (!as->reader))
1188                        continue;
1189                if (++as->event_head >= APM_MAX_EVENTS)
1190                        as->event_head = 0;
1191
1192                if (as->event_head == as->event_tail) {
1193                        static int notified;
1194
1195                        if (notified++ == 0)
1196                            printk(KERN_ERR "apm: an event queue overflowed\n");
1197                        if (++as->event_tail >= APM_MAX_EVENTS)
1198                                as->event_tail = 0;
1199                }
1200                as->events[as->event_head] = event;
1201                if (!as->suser || !as->writer)
1202                        continue;
1203                switch (event) {
1204                case APM_SYS_SUSPEND:
1205                case APM_USER_SUSPEND:
1206                        as->suspends_pending++;
1207                        suspends_pending++;
1208                        break;
1209
1210                case APM_SYS_STANDBY:
1211                case APM_USER_STANDBY:
1212                        as->standbys_pending++;
1213                        standbys_pending++;
1214                        break;
1215                }
1216        }
1217        wake_up_interruptible(&apm_waitqueue);
1218out:
1219        spin_unlock(&user_list_lock);
1220}
1221
1222static void reinit_timer(void)
1223{
1224#ifdef INIT_TIMER_AFTER_SUSPEND
1225        unsigned long flags;
1226
1227        raw_spin_lock_irqsave(&i8253_lock, flags);
1228        /* set the clock to HZ */
1229        outb_pit(0x34, PIT_MODE);               /* binary, mode 2, LSB/MSB, ch 0 */
1230        udelay(10);
1231        outb_pit(LATCH & 0xff, PIT_CH0);        /* LSB */
1232        udelay(10);
1233        outb_pit(LATCH >> 8, PIT_CH0);  /* MSB */
1234        udelay(10);
1235        raw_spin_unlock_irqrestore(&i8253_lock, flags);
1236#endif
1237}
1238
1239static int suspend(int vetoable)
1240{
1241        int err;
1242        struct apm_user *as;
1243
1244        dpm_suspend_start(PMSG_SUSPEND);
1245
1246        dpm_suspend_noirq(PMSG_SUSPEND);
1247
1248        local_irq_disable();
1249        sysdev_suspend(PMSG_SUSPEND);
1250
1251        local_irq_enable();
1252
1253        save_processor_state();
1254        err = set_system_power_state(APM_STATE_SUSPEND);
1255        ignore_normal_resume = 1;
1256        restore_processor_state();
1257
1258        local_irq_disable();
1259        reinit_timer();
1260
1261        if (err == APM_NO_ERROR)
1262                err = APM_SUCCESS;
1263        if (err != APM_SUCCESS)
1264                apm_error("suspend", err);
1265        err = (err == APM_SUCCESS) ? 0 : -EIO;
1266
1267        sysdev_resume();
1268        local_irq_enable();
1269
1270        dpm_resume_noirq(PMSG_RESUME);
1271
1272        dpm_resume_end(PMSG_RESUME);
1273        queue_event(APM_NORMAL_RESUME, NULL);
1274        spin_lock(&user_list_lock);
1275        for (as = user_list; as != NULL; as = as->next) {
1276                as->suspend_wait = 0;
1277                as->suspend_result = err;
1278        }
1279        spin_unlock(&user_list_lock);
1280        wake_up_interruptible(&apm_suspend_waitqueue);
1281        return err;
1282}
1283
1284static void standby(void)
1285{
1286        int err;
1287
1288        dpm_suspend_noirq(PMSG_SUSPEND);
1289
1290        local_irq_disable();
1291        sysdev_suspend(PMSG_SUSPEND);
1292        local_irq_enable();
1293
1294        err = set_system_power_state(APM_STATE_STANDBY);
1295        if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
1296                apm_error("standby", err);
1297
1298        local_irq_disable();
1299        sysdev_resume();
1300        local_irq_enable();
1301
1302        dpm_resume_noirq(PMSG_RESUME);
1303}
1304
1305static apm_event_t get_event(void)
1306{
1307        int error;
1308        apm_event_t event = APM_NO_EVENTS; /* silence gcc */
1309        apm_eventinfo_t info;
1310
1311        static int notified;
1312
1313        /* we don't use the eventinfo */
1314        error = apm_get_event(&event, &info);
1315        if (error == APM_SUCCESS)
1316                return event;
1317
1318        if ((error != APM_NO_EVENTS) && (notified++ == 0))
1319                apm_error("get_event", error);
1320
1321        return 0;
1322}
1323
1324static void check_events(void)
1325{
1326        apm_event_t event;
1327        static unsigned long last_resume;
1328        static int ignore_bounce;
1329
1330        while ((event = get_event()) != 0) {
1331                if (debug) {
1332                        if (event <= NR_APM_EVENT_NAME)
1333                                printk(KERN_DEBUG "apm: received %s notify\n",
1334                                       apm_event_name[event - 1]);
1335                        else
1336                                printk(KERN_DEBUG "apm: received unknown "
1337                                       "event 0x%02x\n", event);
1338                }
1339                if (ignore_bounce
1340                    && (time_after(jiffies, last_resume + bounce_interval)))
1341                        ignore_bounce = 0;
1342
1343                switch (event) {
1344                case APM_SYS_STANDBY:
1345                case APM_USER_STANDBY:
1346                        queue_event(event, NULL);
1347                        if (standbys_pending <= 0)
1348                                standby();
1349                        break;
1350
1351                case APM_USER_SUSPEND:
1352#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
1353                        if (apm_info.connection_version > 0x100)
1354                                set_system_power_state(APM_STATE_REJECT);
1355                        break;
1356#endif
1357                case APM_SYS_SUSPEND:
1358                        if (ignore_bounce) {
1359                                if (apm_info.connection_version > 0x100)
1360                                        set_system_power_state(APM_STATE_REJECT);
1361                                break;
1362                        }
1363                        /*
1364                         * If we are already processing a SUSPEND,
1365                         * then further SUSPEND events from the BIOS
1366                         * will be ignored.  We also return here to
1367                         * cope with the fact that the Thinkpads keep
1368                         * sending a SUSPEND event until something else
1369                         * happens!
1370                         */
1371                        if (ignore_sys_suspend)
1372                                return;
1373                        ignore_sys_suspend = 1;
1374                        queue_event(event, NULL);
1375                        if (suspends_pending <= 0)
1376                                (void) suspend(1);
1377                        break;
1378
1379                case APM_NORMAL_RESUME:
1380                case APM_CRITICAL_RESUME:
1381                case APM_STANDBY_RESUME:
1382                        ignore_sys_suspend = 0;
1383                        last_resume = jiffies;
1384                        ignore_bounce = 1;
1385                        if ((event != APM_NORMAL_RESUME)
1386                            || (ignore_normal_resume == 0)) {
1387                                dpm_resume_end(PMSG_RESUME);
1388                                queue_event(event, NULL);
1389                        }
1390                        ignore_normal_resume = 0;
1391                        break;
1392
1393                case APM_CAPABILITY_CHANGE:
1394                case APM_LOW_BATTERY:
1395                case APM_POWER_STATUS_CHANGE:
1396                        queue_event(event, NULL);
1397                        /* If needed, notify drivers here */
1398                        break;
1399
1400                case APM_UPDATE_TIME:
1401                        break;
1402
1403                case APM_CRITICAL_SUSPEND:
1404                        /*
1405                         * We are not allowed to reject a critical suspend.
1406                         */
1407                        (void)suspend(0);
1408                        break;
1409                }
1410        }
1411}
1412
1413static void apm_event_handler(void)
1414{
1415        static int pending_count = 4;
1416        int err;
1417
1418        if ((standbys_pending > 0) || (suspends_pending > 0)) {
1419                if ((apm_info.connection_version > 0x100) &&
1420                    (pending_count-- <= 0)) {
1421                        pending_count = 4;
1422                        if (debug)
1423                                printk(KERN_DEBUG "apm: setting state busy\n");
1424                        err = set_system_power_state(APM_STATE_BUSY);
1425                        if (err)
1426                                apm_error("busy", err);
1427                }
1428        } else
1429                pending_count = 4;
1430        check_events();
1431}
1432
1433/*
1434 * This is the APM thread main loop.
1435 */
1436
1437static void apm_mainloop(void)
1438{
1439        DECLARE_WAITQUEUE(wait, current);
1440
1441        add_wait_queue(&apm_waitqueue, &wait);
1442        set_current_state(TASK_INTERRUPTIBLE);
1443        for (;;) {
1444                schedule_timeout(APM_CHECK_TIMEOUT);
1445                if (kthread_should_stop())
1446                        break;
1447                /*
1448                 * Ok, check all events, check for idle (and mark us sleeping
1449                 * so as not to count towards the load average)..
1450                 */
1451                set_current_state(TASK_INTERRUPTIBLE);
1452                apm_event_handler();
1453        }
1454        remove_wait_queue(&apm_waitqueue, &wait);
1455}
1456
1457static int check_apm_user(struct apm_user *as, const char *func)
1458{
1459        if (as == NULL || as->magic != APM_BIOS_MAGIC) {
1460                printk(KERN_ERR "apm: %s passed bad filp\n", func);
1461                return 1;
1462        }
1463        return 0;
1464}
1465
1466static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
1467{
1468        struct apm_user *as;
1469        int i;
1470        apm_event_t event;
1471
1472        as = fp->private_data;
1473        if (check_apm_user(as, "read"))
1474                return -EIO;
1475        if ((int)count < sizeof(apm_event_t))
1476                return -EINVAL;
1477        if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
1478                return -EAGAIN;
1479        wait_event_interruptible(apm_waitqueue, !queue_empty(as));
1480        i = count;
1481        while ((i >= sizeof(event)) && !queue_empty(as)) {
1482                event = get_queued_event(as);
1483                if (copy_to_user(buf, &event, sizeof(event))) {
1484                        if (i < count)
1485                                break;
1486                        return -EFAULT;
1487                }
1488                switch (event) {
1489                case APM_SYS_SUSPEND:
1490                case APM_USER_SUSPEND:
1491                        as->suspends_read++;
1492                        break;
1493
1494                case APM_SYS_STANDBY:
1495                case APM_USER_STANDBY:
1496                        as->standbys_read++;
1497                        break;
1498                }
1499                buf += sizeof(event);
1500                i -= sizeof(event);
1501        }
1502        if (i < count)
1503                return count - i;
1504        if (signal_pending(current))
1505                return -ERESTARTSYS;
1506        return 0;
1507}
1508
1509static unsigned int do_poll(struct file *fp, poll_table *wait)
1510{
1511        struct apm_user *as;
1512
1513        as = fp->private_data;
1514        if (check_apm_user(as, "poll"))
1515                return 0;
1516        poll_wait(fp, &apm_waitqueue, wait);
1517        if (!queue_empty(as))
1518                return POLLIN | POLLRDNORM;
1519        return 0;
1520}
1521
1522static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
1523{
1524        struct apm_user *as;
1525        int ret;
1526
1527        as = filp->private_data;
1528        if (check_apm_user(as, "ioctl"))
1529                return -EIO;
1530        if (!as->suser || !as->writer)
1531                return -EPERM;
1532        switch (cmd) {
1533        case APM_IOC_STANDBY:
1534                mutex_lock(&apm_mutex);
1535                if (as->standbys_read > 0) {
1536                        as->standbys_read--;
1537                        as->standbys_pending--;
1538                        standbys_pending--;
1539                } else
1540                        queue_event(APM_USER_STANDBY, as);
1541                if (standbys_pending <= 0)
1542                        standby();
1543                mutex_unlock(&apm_mutex);
1544                break;
1545        case APM_IOC_SUSPEND:
1546                mutex_lock(&apm_mutex);
1547                if (as->suspends_read > 0) {
1548                        as->suspends_read--;
1549                        as->suspends_pending--;
1550                        suspends_pending--;
1551                } else
1552                        queue_event(APM_USER_SUSPEND, as);
1553                if (suspends_pending <= 0) {
1554                        ret = suspend(1);
1555                        mutex_unlock(&apm_mutex);
1556                } else {
1557                        as->suspend_wait = 1;
1558                        mutex_unlock(&apm_mutex);
1559                        wait_event_interruptible(apm_suspend_waitqueue,
1560                                        as->suspend_wait == 0);
1561                        ret = as->suspend_result;
1562                }
1563                return ret;
1564        default:
1565                return -ENOTTY;
1566        }
1567        return 0;
1568}
1569
1570static int do_release(struct inode *inode, struct file *filp)
1571{
1572        struct apm_user *as;
1573
1574        as = filp->private_data;
1575        if (check_apm_user(as, "release"))
1576                return 0;
1577        filp->private_data = NULL;
1578        if (as->standbys_pending > 0) {
1579                standbys_pending -= as->standbys_pending;
1580                if (standbys_pending <= 0)
1581                        standby();
1582        }
1583        if (as->suspends_pending > 0) {
1584                suspends_pending -= as->suspends_pending;
1585                if (suspends_pending <= 0)
1586                        (void) suspend(1);
1587        }
1588        spin_lock(&user_list_lock);
1589        if (user_list == as)
1590                user_list = as->next;
1591        else {
1592                struct apm_user *as1;
1593
1594                for (as1 = user_list;
1595                     (as1 != NULL) && (as1->next != as);
1596                     as1 = as1->next)
1597                        ;
1598                if (as1 == NULL)
1599                        printk(KERN_ERR "apm: filp not in user list\n");
1600                else
1601                        as1->next = as->next;
1602        }
1603        spin_unlock(&user_list_lock);
1604        kfree(as);
1605        return 0;
1606}
1607
1608static int do_open(struct inode *inode, struct file *filp)
1609{
1610        struct apm_user *as;
1611
1612        as = kmalloc(sizeof(*as), GFP_KERNEL);
1613        if (as == NULL) {
1614                printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
1615                       sizeof(*as));
1616                return -ENOMEM;
1617        }
1618        as->magic = APM_BIOS_MAGIC;
1619        as->event_tail = as->event_head = 0;
1620        as->suspends_pending = as->standbys_pending = 0;
1621        as->suspends_read = as->standbys_read = 0;
1622        /*
1623         * XXX - this is a tiny bit broken, when we consider BSD
1624         * process accounting. If the device is opened by root, we
1625         * instantly flag that we used superuser privs. Who knows,
1626         * we might close the device immediately without doing a
1627         * privileged operation -- cevans
1628         */
1629        as->suser = capable(CAP_SYS_ADMIN);
1630        as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
1631        as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
1632        spin_lock(&user_list_lock);
1633        as->next = user_list;
1634        user_list = as;
1635        spin_unlock(&user_list_lock);
1636        filp->private_data = as;
1637        return 0;
1638}
1639
1640static int proc_apm_show(struct seq_file *m, void *v)
1641{
1642        unsigned short  bx;
1643        unsigned short  cx;
1644        unsigned short  dx;
1645        int             error;
1646        unsigned short  ac_line_status = 0xff;
1647        unsigned short  battery_status = 0xff;
1648        unsigned short  battery_flag   = 0xff;
1649        int             percentage     = -1;
1650        int             time_units     = -1;
1651        char            *units         = "?";
1652
1653        if ((num_online_cpus() == 1) &&
1654            !(error = apm_get_power_status(&bx, &cx, &dx))) {
1655                ac_line_status = (bx >> 8) & 0xff;
1656                battery_status = bx & 0xff;
1657                if ((cx & 0xff) != 0xff)
1658                        percentage = cx & 0xff;
1659
1660                if (apm_info.connection_version > 0x100) {
1661                        battery_flag = (cx >> 8) & 0xff;
1662                        if (dx != 0xffff) {
1663                                units = (dx & 0x8000) ? "min" : "sec";
1664                                time_units = dx & 0x7fff;
1665                        }
1666                }
1667        }
1668        /* Arguments, with symbols from linux/apm_bios.h.  Information is
1669           from the Get Power Status (0x0a) call unless otherwise noted.
1670
1671           0) Linux driver version (this will change if format changes)
1672           1) APM BIOS Version.  Usually 1.0, 1.1 or 1.2.
1673           2) APM flags from APM Installation Check (0x00):
1674              bit 0: APM_16_BIT_SUPPORT
1675              bit 1: APM_32_BIT_SUPPORT
1676              bit 2: APM_IDLE_SLOWS_CLOCK
1677              bit 3: APM_BIOS_DISABLED
1678              bit 4: APM_BIOS_DISENGAGED
1679           3) AC line status
1680              0x00: Off-line
1681              0x01: On-line
1682              0x02: On backup power (BIOS >= 1.1 only)
1683              0xff: Unknown
1684           4) Battery status
1685              0x00: High
1686              0x01: Low
1687              0x02: Critical
1688              0x03: Charging
1689              0x04: Selected battery not present (BIOS >= 1.2 only)
1690              0xff: Unknown
1691           5) Battery flag
1692              bit 0: High
1693              bit 1: Low
1694              bit 2: Critical
1695              bit 3: Charging
1696              bit 7: No system battery
1697              0xff: Unknown
1698           6) Remaining battery life (percentage of charge):
1699              0-100: valid
1700              -1: Unknown
1701           7) Remaining battery life (time units):
1702              Number of remaining minutes or seconds
1703              -1: Unknown
1704           8) min = minutes; sec = seconds */
1705
1706        seq_printf(m, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1707                   driver_version,
1708                   (apm_info.bios.version >> 8) & 0xff,
1709                   apm_info.bios.version & 0xff,
1710                   apm_info.bios.flags,
1711                   ac_line_status,
1712                   battery_status,
1713                   battery_flag,
1714                   percentage,
1715                   time_units,
1716                   units);
1717        return 0;
1718}
1719
1720static int proc_apm_open(struct inode *inode, struct file *file)
1721{
1722        return single_open(file, proc_apm_show, NULL);
1723}
1724
1725static const struct file_operations apm_file_ops = {
1726        .owner          = THIS_MODULE,
1727        .open           = proc_apm_open,
1728        .read           = seq_read,
1729        .llseek         = seq_lseek,
1730        .release        = single_release,
1731};
1732
1733static int apm(void *unused)
1734{
1735        unsigned short  bx;
1736        unsigned short  cx;
1737        unsigned short  dx;
1738        int             error;
1739        char            *power_stat;
1740        char            *bat_stat;
1741
1742        /* 2002/08/01 - WT
1743         * This is to avoid random crashes at boot time during initialization
1744         * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
1745         * Some bioses don't like being called from CPU != 0.
1746         * Method suggested by Ingo Molnar.
1747         */
1748        set_cpus_allowed_ptr(current, cpumask_of(0));
1749        BUG_ON(smp_processor_id() != 0);
1750
1751        if (apm_info.connection_version == 0) {
1752                apm_info.connection_version = apm_info.bios.version;
1753                if (apm_info.connection_version > 0x100) {
1754                        /*
1755                         * We only support BIOSs up to version 1.2
1756                         */
1757                        if (apm_info.connection_version > 0x0102)
1758                                apm_info.connection_version = 0x0102;
1759                        error = apm_driver_version(&apm_info.connection_version);
1760                        if (error != APM_SUCCESS) {
1761                                apm_error("driver version", error);
1762                                /* Fall back to an APM 1.0 connection. */
1763                                apm_info.connection_version = 0x100;
1764                        }
1765                }
1766        }
1767
1768        if (debug)
1769                printk(KERN_INFO "apm: Connection version %d.%d\n",
1770                        (apm_info.connection_version >> 8) & 0xff,
1771                        apm_info.connection_version & 0xff);
1772
1773#ifdef CONFIG_APM_DO_ENABLE
1774        if (apm_info.bios.flags & APM_BIOS_DISABLED) {
1775                /*
1776                 * This call causes my NEC UltraLite Versa 33/C to hang if it
1777                 * is booted with PM disabled but not in the docking station.
1778                 * Unfortunate ...
1779                 */
1780                error = apm_enable_power_management(1);
1781                if (error) {
1782                        apm_error("enable power management", error);
1783                        return -1;
1784                }
1785        }
1786#endif
1787
1788        if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
1789            && (apm_info.connection_version > 0x0100)) {
1790                error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1791                if (error) {
1792                        apm_error("engage power management", error);
1793                        return -1;
1794                }
1795        }
1796
1797        if (debug && (num_online_cpus() == 1 || smp)) {
1798                error = apm_get_power_status(&bx, &cx, &dx);
1799                if (error)
1800                        printk(KERN_INFO "apm: power status not available\n");
1801                else {
1802                        switch ((bx >> 8) & 0xff) {
1803                        case 0:
1804                                power_stat = "off line";
1805                                break;
1806                        case 1:
1807                                power_stat = "on line";
1808                                break;
1809                        case 2:
1810                                power_stat = "on backup power";
1811                                break;
1812                        default:
1813                                power_stat = "unknown";
1814                                break;
1815                        }
1816                        switch (bx & 0xff) {
1817                        case 0:
1818                                bat_stat = "high";
1819                                break;
1820                        case 1:
1821                                bat_stat = "low";
1822                                break;
1823                        case 2:
1824                                bat_stat = "critical";
1825                                break;
1826                        case 3:
1827                                bat_stat = "charging";
1828                                break;
1829                        default:
1830                                bat_stat = "unknown";
1831                                break;
1832                        }
1833                        printk(KERN_INFO
1834                               "apm: AC %s, battery status %s, battery life ",
1835                               power_stat, bat_stat);
1836                        if ((cx & 0xff) == 0xff)
1837                                printk("unknown\n");
1838                        else
1839                                printk("%d%%\n", cx & 0xff);
1840                        if (apm_info.connection_version > 0x100) {
1841                                printk(KERN_INFO
1842                                       "apm: battery flag 0x%02x, battery life ",
1843                                       (cx >> 8) & 0xff);
1844                                if (dx == 0xffff)
1845                                        printk("unknown\n");
1846                                else
1847                                        printk("%d %s\n", dx & 0x7fff,
1848                                               (dx & 0x8000) ?
1849                                               "minutes" : "seconds");
1850                        }
1851                }
1852        }
1853
1854        /* Install our power off handler.. */
1855        if (power_off)
1856                pm_power_off = apm_power_off;
1857
1858        if (num_online_cpus() == 1 || smp) {
1859#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1860                console_blank_hook = apm_console_blank;
1861#endif
1862                apm_mainloop();
1863#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1864                console_blank_hook = NULL;
1865#endif
1866        }
1867
1868        return 0;
1869}
1870
1871#ifndef MODULE
1872static int __init apm_setup(char *str)
1873{
1874        int invert;
1875
1876        while ((str != NULL) && (*str != '\0')) {
1877                if (strncmp(str, "off", 3) == 0)
1878                        apm_disabled = 1;
1879                if (strncmp(str, "on", 2) == 0)
1880                        apm_disabled = 0;
1881                if ((strncmp(str, "bounce-interval=", 16) == 0) ||
1882                    (strncmp(str, "bounce_interval=", 16) == 0))
1883                        bounce_interval = simple_strtol(str + 16, NULL, 0);
1884                if ((strncmp(str, "idle-threshold=", 15) == 0) ||
1885                    (strncmp(str, "idle_threshold=", 15) == 0))
1886                        idle_threshold = simple_strtol(str + 15, NULL, 0);
1887                if ((strncmp(str, "idle-period=", 12) == 0) ||
1888                    (strncmp(str, "idle_period=", 12) == 0))
1889                        idle_period = simple_strtol(str + 12, NULL, 0);
1890                invert = (strncmp(str, "no-", 3) == 0) ||
1891                        (strncmp(str, "no_", 3) == 0);
1892                if (invert)
1893                        str += 3;
1894                if (strncmp(str, "debug", 5) == 0)
1895                        debug = !invert;
1896                if ((strncmp(str, "power-off", 9) == 0) ||
1897                    (strncmp(str, "power_off", 9) == 0))
1898                        power_off = !invert;
1899                if (strncmp(str, "smp", 3) == 0) {
1900                        smp = !invert;
1901                        idle_threshold = 100;
1902                }
1903                if ((strncmp(str, "allow-ints", 10) == 0) ||
1904                    (strncmp(str, "allow_ints", 10) == 0))
1905                        apm_info.allow_ints = !invert;
1906                if ((strncmp(str, "broken-psr", 10) == 0) ||
1907                    (strncmp(str, "broken_psr", 10) == 0))
1908                        apm_info.get_power_status_broken = !invert;
1909                if ((strncmp(str, "realmode-power-off", 18) == 0) ||
1910                    (strncmp(str, "realmode_power_off", 18) == 0))
1911                        apm_info.realmode_power_off = !invert;
1912                str = strchr(str, ',');
1913                if (str != NULL)
1914                        str += strspn(str, ", \t");
1915        }
1916        return 1;
1917}
1918
1919__setup("apm=", apm_setup);
1920#endif
1921
1922static const struct file_operations apm_bios_fops = {
1923        .owner          = THIS_MODULE,
1924        .read           = do_read,
1925        .poll           = do_poll,
1926        .unlocked_ioctl = do_ioctl,
1927        .open           = do_open,
1928        .release        = do_release,
1929        .llseek         = noop_llseek,
1930};
1931
1932static struct miscdevice apm_device = {
1933        APM_MINOR_DEV,
1934        "apm_bios",
1935        &apm_bios_fops
1936};
1937
1938
1939/* Simple "print if true" callback */
1940static int __init print_if_true(const struct dmi_system_id *d)
1941{
1942        printk("%s\n", d->ident);
1943        return 0;
1944}
1945
1946/*
1947 * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it was
1948 * disabled before the suspend. Linux used to get terribly confused by that.
1949 */
1950static int __init broken_ps2_resume(const struct dmi_system_id *d)
1951{
1952        printk(KERN_INFO "%s machine detected. Mousepad Resume Bug "
1953               "workaround hopefully not needed.\n", d->ident);
1954        return 0;
1955}
1956
1957/* Some bioses have a broken protected mode poweroff and need to use realmode */
1958static int __init set_realmode_power_off(const struct dmi_system_id *d)
1959{
1960        if (apm_info.realmode_power_off == 0) {
1961                apm_info.realmode_power_off = 1;
1962                printk(KERN_INFO "%s bios detected. "
1963                       "Using realmode poweroff only.\n", d->ident);
1964        }
1965        return 0;
1966}
1967
1968/* Some laptops require interrupts to be enabled during APM calls */
1969static int __init set_apm_ints(const struct dmi_system_id *d)
1970{
1971        if (apm_info.allow_ints == 0) {
1972                apm_info.allow_ints = 1;
1973                printk(KERN_INFO "%s machine detected. "
1974                       "Enabling interrupts during APM calls.\n", d->ident);
1975        }
1976        return 0;
1977}
1978
1979/* Some APM bioses corrupt memory or just plain do not work */
1980static int __init apm_is_horked(const struct dmi_system_id *d)
1981{
1982        if (apm_info.disabled == 0) {
1983                apm_info.disabled = 1;
1984                printk(KERN_INFO "%s machine detected. "
1985                       "Disabling APM.\n", d->ident);
1986        }
1987        return 0;
1988}
1989
1990static int __init apm_is_horked_d850md(const struct dmi_system_id *d)
1991{
1992        if (apm_info.disabled == 0) {
1993                apm_info.disabled = 1;
1994                printk(KERN_INFO "%s machine detected. "
1995                       "Disabling APM.\n", d->ident);
1996                printk(KERN_INFO "This bug is fixed in bios P15 which is available for\n");
1997                printk(KERN_INFO "download from support.intel.com\n");
1998        }
1999        return 0;
2000}
2001
2002/* Some APM bioses hang on APM idle calls */
2003static int __init apm_likes_to_melt(const struct dmi_system_id *d)
2004{
2005        if (apm_info.forbid_idle == 0) {
2006                apm_info.forbid_idle = 1;
2007                printk(KERN_INFO "%s machine detected. "
2008                       "Disabling APM idle calls.\n", d->ident);
2009        }
2010        return 0;
2011}
2012
2013/*
2014 *  Check for clue free BIOS implementations who use
2015 *  the following QA technique
2016 *
2017 *      [ Write BIOS Code ]<------
2018 *               |                ^
2019 *      < Does it Compile >----N--
2020 *               |Y               ^
2021 *      < Does it Boot Win98 >-N--
2022 *               |Y
2023 *           [Ship It]
2024 *
2025 *      Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
2026 *      Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
2027 */
2028static int __init broken_apm_power(const struct dmi_system_id *d)
2029{
2030        apm_info.get_power_status_broken = 1;
2031        printk(KERN_WARNING "BIOS strings suggest APM bugs, "
2032               "disabling power status reporting.\n");
2033        return 0;
2034}
2035
2036/*
2037 * This bios swaps the APM minute reporting bytes over (Many sony laptops
2038 * have this problem).
2039 */
2040static int __init swab_apm_power_in_minutes(const struct dmi_system_id *d)
2041{
2042        apm_info.get_power_status_swabinminutes = 1;
2043        printk(KERN_WARNING "BIOS strings suggest APM reports battery life "
2044               "in minutes and wrong byte order.\n");
2045        return 0;
2046}
2047
2048static struct dmi_system_id __initdata apm_dmi_table[] = {
2049        {
2050                print_if_true,
2051                KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.",
2052                {       DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
2053                        DMI_MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"), },
2054        },
2055        {       /* Handle problems with APM on the C600 */
2056                broken_ps2_resume, "Dell Latitude C600",
2057                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
2058                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude C600"), },
2059        },
2060        {       /* Allow interrupts during suspend on Dell Latitude laptops*/
2061                set_apm_ints, "Dell Latitude",
2062                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2063                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude C510"), }
2064        },
2065        {       /* APM crashes */
2066                apm_is_horked, "Dell Inspiron 2500",
2067                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2068                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
2069                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2070                        DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
2071        },
2072        {       /* Allow interrupts during suspend on Dell Inspiron laptops*/
2073                set_apm_ints, "Dell Inspiron", {
2074                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2075                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"), },
2076        },
2077        {       /* Handle problems with APM on Inspiron 5000e */
2078                broken_apm_power, "Dell Inspiron 5000e",
2079                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2080                        DMI_MATCH(DMI_BIOS_VERSION, "A04"),
2081                        DMI_MATCH(DMI_BIOS_DATE, "08/24/2000"), },
2082        },
2083        {       /* Handle problems with APM on Inspiron 2500 */
2084                broken_apm_power, "Dell Inspiron 2500",
2085                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2086                        DMI_MATCH(DMI_BIOS_VERSION, "A12"),
2087                        DMI_MATCH(DMI_BIOS_DATE, "02/04/2002"), },
2088        },
2089        {       /* APM crashes */
2090                apm_is_horked, "Dell Dimension 4100",
2091                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2092                        DMI_MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
2093                        DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2094                        DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
2095        },
2096        {       /* Allow interrupts during suspend on Compaq Laptops*/
2097                set_apm_ints, "Compaq 12XL125",
2098                {       DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
2099                        DMI_MATCH(DMI_PRODUCT_NAME, "Compaq PC"),
2100                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2101                        DMI_MATCH(DMI_BIOS_VERSION, "4.06"), },
2102        },
2103        {       /* Allow interrupts during APM or the clock goes slow */
2104                set_apm_ints, "ASUSTeK",
2105                {       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
2106                        DMI_MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"), },
2107        },
2108        {       /* APM blows on shutdown */
2109                apm_is_horked, "ABIT KX7-333[R]",
2110                {       DMI_MATCH(DMI_BOARD_VENDOR, "ABIT"),
2111                        DMI_MATCH(DMI_BOARD_NAME, "VT8367-8233A (KX7-333[R])"), },
2112        },
2113        {       /* APM crashes */
2114                apm_is_horked, "Trigem Delhi3",
2115                {       DMI_MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
2116                        DMI_MATCH(DMI_PRODUCT_NAME, "Delhi3"), },
2117        },
2118        {       /* APM crashes */
2119                apm_is_horked, "Fujitsu-Siemens",
2120                {       DMI_MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"),
2121                        DMI_MATCH(DMI_BIOS_VERSION, "Version1.01"), },
2122        },
2123        {       /* APM crashes */
2124                apm_is_horked_d850md, "Intel D850MD",
2125                {       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2126                        DMI_MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"), },
2127        },
2128        {       /* APM crashes */
2129                apm_is_horked, "Intel D810EMO",
2130                {       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2131                        DMI_MATCH(DMI_BIOS_VERSION, "MO81010A.86A.0008.P04.0004170800"), },
2132        },
2133        {       /* APM crashes */
2134                apm_is_horked, "Dell XPS-Z",
2135                {       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2136                        DMI_MATCH(DMI_BIOS_VERSION, "A11"),
2137                        DMI_MATCH(DMI_PRODUCT_NAME, "XPS-Z"), },
2138        },
2139        {       /* APM crashes */
2140                apm_is_horked, "Sharp PC-PJ/AX",
2141                {       DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
2142                        DMI_MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
2143                        DMI_MATCH(DMI_BIOS_VENDOR, "SystemSoft"),
2144                        DMI_MATCH(DMI_BIOS_VERSION, "Version R2.08"), },
2145        },
2146        {       /* APM crashes */
2147                apm_is_horked, "Dell Inspiron 2500",
2148                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2149                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
2150                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2151                        DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
2152        },
2153        {       /* APM idle hangs */
2154                apm_likes_to_melt, "Jabil AMD",
2155                {       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
2156                        DMI_MATCH(DMI_BIOS_VERSION, "0AASNP06"), },
2157        },
2158        {       /* APM idle hangs */
2159                apm_likes_to_melt, "AMI Bios",
2160                {       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
2161                        DMI_MATCH(DMI_BIOS_VERSION, "0AASNP05"), },
2162        },
2163        {       /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */
2164                swab_apm_power_in_minutes, "Sony VAIO",
2165                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2166                        DMI_MATCH(DMI_BIOS_VERSION, "R0206H"),
2167                        DMI_MATCH(DMI_BIOS_DATE, "08/23/99"), },
2168        },
2169        {       /* Handle problems with APM on Sony Vaio PCG-N505VX */
2170                swab_apm_power_in_minutes, "Sony VAIO",
2171                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2172                        DMI_MATCH(DMI_BIOS_VERSION, "W2K06H0"),
2173                        DMI_MATCH(DMI_BIOS_DATE, "02/03/00"), },
2174        },
2175        {       /* Handle problems with APM on Sony Vaio PCG-XG29 */
2176                swab_apm_power_in_minutes, "Sony VAIO",
2177                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2178                        DMI_MATCH(DMI_BIOS_VERSION, "R0117A0"),
2179                        DMI_MATCH(DMI_BIOS_DATE, "04/25/00"), },
2180        },
2181        {       /* Handle problems with APM on Sony Vaio PCG-Z600NE */
2182                swab_apm_power_in_minutes, "Sony VAIO",
2183                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2184                        DMI_MATCH(DMI_BIOS_VERSION, "R0121Z1"),
2185                        DMI_MATCH(DMI_BIOS_DATE, "05/11/00"), },
2186        },
2187        {       /* Handle problems with APM on Sony Vaio PCG-Z600NE */
2188                swab_apm_power_in_minutes, "Sony VAIO",
2189                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2190                        DMI_MATCH(DMI_BIOS_VERSION, "WME01Z1"),
2191                        DMI_MATCH(DMI_BIOS_DATE, "08/11/00"), },
2192        },
2193        {       /* Handle problems with APM on Sony Vaio PCG-Z600LEK(DE) */
2194                swab_apm_power_in_minutes, "Sony VAIO",
2195                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2196                        DMI_MATCH(DMI_BIOS_VERSION, "R0206Z3"),
2197                        DMI_MATCH(DMI_BIOS_DATE, "12/25/00"), },
2198        },
2199        {       /* Handle problems with APM on Sony Vaio PCG-Z505LS */
2200                swab_apm_power_in_minutes, "Sony VAIO",
2201                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2202                        DMI_MATCH(DMI_BIOS_VERSION, "R0203D0"),
2203                        DMI_MATCH(DMI_BIOS_DATE, "05/12/00"), },
2204        },
2205        {       /* Handle problems with APM on Sony Vaio PCG-Z505LS */
2206                swab_apm_power_in_minutes, "Sony VAIO",
2207                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2208                        DMI_MATCH(DMI_BIOS_VERSION, "R0203Z3"),
2209                        DMI_MATCH(DMI_BIOS_DATE, "08/25/00"), },
2210        },
2211        {       /* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
2212                swab_apm_power_in_minutes, "Sony VAIO",
2213                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2214                        DMI_MATCH(DMI_BIOS_VERSION, "R0209Z3"),
2215                        DMI_MATCH(DMI_BIOS_DATE, "05/12/01"), },
2216        },
2217        {       /* Handle problems with APM on Sony Vaio PCG-F104K */
2218                swab_apm_power_in_minutes, "Sony VAIO",
2219                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2220                        DMI_MATCH(DMI_BIOS_VERSION, "R0204K2"),
2221                        DMI_MATCH(DMI_BIOS_DATE, "08/28/00"), },
2222        },
2223
2224        {       /* Handle problems with APM on Sony Vaio PCG-C1VN/C1VE */
2225                swab_apm_power_in_minutes, "Sony VAIO",
2226                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2227                        DMI_MATCH(DMI_BIOS_VERSION, "R0208P1"),
2228                        DMI_MATCH(DMI_BIOS_DATE, "11/09/00"), },
2229        },
2230        {       /* Handle problems with APM on Sony Vaio PCG-C1VE */
2231                swab_apm_power_in_minutes, "Sony VAIO",
2232                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2233                        DMI_MATCH(DMI_BIOS_VERSION, "R0204P1"),
2234                        DMI_MATCH(DMI_BIOS_DATE, "09/12/00"), },
2235        },
2236        {       /* Handle problems with APM on Sony Vaio PCG-C1VE */
2237                swab_apm_power_in_minutes, "Sony VAIO",
2238                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2239                        DMI_MATCH(DMI_BIOS_VERSION, "WXPO1Z3"),
2240                        DMI_MATCH(DMI_BIOS_DATE, "10/26/01"), },
2241        },
2242        {       /* broken PM poweroff bios */
2243                set_realmode_power_off, "Award Software v4.60 PGMA",
2244                {       DMI_MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
2245                        DMI_MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
2246                        DMI_MATCH(DMI_BIOS_DATE, "134526184"), },
2247        },
2248
2249        /* Generic per vendor APM settings  */
2250
2251        {       /* Allow interrupts during suspend on IBM laptops */
2252                set_apm_ints, "IBM",
2253                {       DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
2254        },
2255
2256        { }
2257};
2258
2259/*
2260 * Just start the APM thread. We do NOT want to do APM BIOS
2261 * calls from anything but the APM thread, if for no other reason
2262 * than the fact that we don't trust the APM BIOS. This way,
2263 * most common APM BIOS problems that lead to protection errors
2264 * etc will have at least some level of being contained...
2265 *
2266 * In short, if something bad happens, at least we have a choice
2267 * of just killing the apm thread..
2268 */
2269static int __init apm_init(void)
2270{
2271        struct desc_struct *gdt;
2272        int err;
2273
2274        dmi_check_system(apm_dmi_table);
2275
2276        if (apm_info.bios.version == 0 || paravirt_enabled() || machine_is_olpc()) {
2277                printk(KERN_INFO "apm: BIOS not found.\n");
2278                return -ENODEV;
2279        }
2280        printk(KERN_INFO
2281               "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
2282               ((apm_info.bios.version >> 8) & 0xff),
2283               (apm_info.bios.version & 0xff),
2284               apm_info.bios.flags,
2285               driver_version);
2286        if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
2287                printk(KERN_INFO "apm: no 32 bit BIOS support\n");
2288                return -ENODEV;
2289        }
2290
2291        if (allow_ints)
2292                apm_info.allow_ints = 1;
2293        if (broken_psr)
2294                apm_info.get_power_status_broken = 1;
2295        if (realmode_power_off)
2296                apm_info.realmode_power_off = 1;
2297        /* User can override, but default is to trust DMI */
2298        if (apm_disabled != -1)
2299                apm_info.disabled = apm_disabled;
2300
2301        /*
2302         * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
2303         * but is reportedly a 1.0 BIOS.
2304         */
2305        if (apm_info.bios.version == 0x001)
2306                apm_info.bios.version = 0x100;
2307
2308        /* BIOS < 1.2 doesn't set cseg_16_len */
2309        if (apm_info.bios.version < 0x102)
2310                apm_info.bios.cseg_16_len = 0; /* 64k */
2311
2312        if (debug) {
2313                printk(KERN_INFO "apm: entry %x:%x cseg16 %x dseg %x",
2314                        apm_info.bios.cseg, apm_info.bios.offset,
2315                        apm_info.bios.cseg_16, apm_info.bios.dseg);
2316                if (apm_info.bios.version > 0x100)
2317                        printk(" cseg len %x, dseg len %x",
2318                                apm_info.bios.cseg_len,
2319                                apm_info.bios.dseg_len);
2320                if (apm_info.bios.version > 0x101)
2321                        printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
2322                printk("\n");
2323        }
2324
2325        if (apm_info.disabled) {
2326                printk(KERN_NOTICE "apm: disabled on user request.\n");
2327                return -ENODEV;
2328        }
2329        if ((num_online_cpus() > 1) && !power_off && !smp) {
2330                printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
2331                apm_info.disabled = 1;
2332                return -ENODEV;
2333        }
2334        if (pm_flags & PM_ACPI) {
2335                printk(KERN_NOTICE "apm: overridden by ACPI.\n");
2336                apm_info.disabled = 1;
2337                return -ENODEV;
2338        }
2339        pm_flags |= PM_APM;
2340
2341        /*
2342         * Set up the long jump entry point to the APM BIOS, which is called
2343         * from inline assembly.
2344         */
2345        apm_bios_entry.offset = apm_info.bios.offset;
2346        apm_bios_entry.segment = APM_CS;
2347
2348        /*
2349         * The APM 1.1 BIOS is supposed to provide limit information that it
2350         * recognizes.  Many machines do this correctly, but many others do
2351         * not restrict themselves to their claimed limit.  When this happens,
2352         * they will cause a segmentation violation in the kernel at boot time.
2353         * Most BIOS's, however, will respect a 64k limit, so we use that.
2354         *
2355         * Note we only set APM segments on CPU zero, since we pin the APM
2356         * code to that CPU.
2357         */
2358        gdt = get_cpu_gdt_table(0);
2359        set_desc_base(&gdt[APM_CS >> 3],
2360                 (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4));
2361        set_desc_base(&gdt[APM_CS_16 >> 3],
2362                 (unsigned long)__va((unsigned long)apm_info.bios.cseg_16 << 4));
2363        set_desc_base(&gdt[APM_DS >> 3],
2364                 (unsigned long)__va((unsigned long)apm_info.bios.dseg << 4));
2365
2366        proc_create("apm", 0, NULL, &apm_file_ops);
2367
2368        kapmd_task = kthread_create(apm, NULL, "kapmd");
2369        if (IS_ERR(kapmd_task)) {
2370                printk(KERN_ERR "apm: disabled - Unable to start kernel "
2371                                "thread.\n");
2372                err = PTR_ERR(kapmd_task);
2373                kapmd_task = NULL;
2374                remove_proc_entry("apm", NULL);
2375                return err;
2376        }
2377        wake_up_process(kapmd_task);
2378
2379        if (num_online_cpus() > 1 && !smp) {
2380                printk(KERN_NOTICE
2381                       "apm: disabled - APM is not SMP safe (power off active).\n");
2382                return 0;
2383        }
2384
2385        /*
2386         * Note we don't actually care if the misc_device cannot be registered.
2387         * this driver can do its job without it, even if userspace can't
2388         * control it.  just log the error
2389         */
2390        if (misc_register(&apm_device))
2391                printk(KERN_WARNING "apm: Could not register misc device.\n");
2392
2393        if (HZ != 100)
2394                idle_period = (idle_period * HZ) / 100;
2395        if (idle_threshold < 100) {
2396                original_pm_idle = pm_idle;
2397                pm_idle  = apm_cpu_idle;
2398                set_pm_idle = 1;
2399        }
2400
2401        return 0;
2402}
2403
2404static void __exit apm_exit(void)
2405{
2406        int error;
2407
2408        if (set_pm_idle) {
2409                pm_idle = original_pm_idle;
2410                /*
2411                 * We are about to unload the current idle thread pm callback
2412                 * (pm_idle), Wait for all processors to update cached/local
2413                 * copies of pm_idle before proceeding.
2414                 */
2415                cpu_idle_wait();
2416        }
2417        if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
2418            && (apm_info.connection_version > 0x0100)) {
2419                error = apm_engage_power_management(APM_DEVICE_ALL, 0);
2420                if (error)
2421                        apm_error("disengage power management", error);
2422        }
2423        misc_deregister(&apm_device);
2424        remove_proc_entry("apm", NULL);
2425        if (power_off)
2426                pm_power_off = NULL;
2427        if (kapmd_task) {
2428                kthread_stop(kapmd_task);
2429                kapmd_task = NULL;
2430        }
2431        pm_flags &= ~PM_APM;
2432}
2433
2434module_init(apm_init);
2435module_exit(apm_exit);
2436
2437MODULE_AUTHOR("Stephen Rothwell");
2438MODULE_DESCRIPTION("Advanced Power Management");
2439MODULE_LICENSE("GPL");
2440module_param(debug, bool, 0644);
2441MODULE_PARM_DESC(debug, "Enable debug mode");
2442module_param(power_off, bool, 0444);
2443MODULE_PARM_DESC(power_off, "Enable power off");
2444module_param(bounce_interval, int, 0444);
2445MODULE_PARM_DESC(bounce_interval,
2446                "Set the number of ticks to ignore suspend bounces");
2447module_param(allow_ints, bool, 0444);
2448MODULE_PARM_DESC(allow_ints, "Allow interrupts during BIOS calls");
2449module_param(broken_psr, bool, 0444);
2450MODULE_PARM_DESC(broken_psr, "BIOS has a broken GetPowerStatus call");
2451module_param(realmode_power_off, bool, 0444);
2452MODULE_PARM_DESC(realmode_power_off,
2453                "Switch to real mode before powering off");
2454module_param(idle_threshold, int, 0444);
2455MODULE_PARM_DESC(idle_threshold,
2456        "System idle percentage above which to make APM BIOS idle calls");
2457module_param(idle_period, int, 0444);
2458MODULE_PARM_DESC(idle_period,
2459        "Period (in sec/100) over which to caculate the idle percentage");
2460module_param(smp, bool, 0444);
2461MODULE_PARM_DESC(smp,
2462        "Set this to enable APM use on an SMP platform. Use with caution on older systems");
2463MODULE_ALIAS_MISCDEV(APM_MINOR_DEV);
2464