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@suse.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 via anonymous ftp from
 193 * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc.  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/smp_lock.h>
 208#include <linux/types.h>
 209#include <linux/stddef.h>
 210#include <linux/timer.h>
 211#include <linux/fcntl.h>
 212#include <linux/slab.h>
 213#include <linux/stat.h>
 214#include <linux/proc_fs.h>
 215#include <linux/seq_file.h>
 216#include <linux/miscdevice.h>
 217#include <linux/apm_bios.h>
 218#include <linux/init.h>
 219#include <linux/time.h>
 220#include <linux/sched.h>
 221#include <linux/pm.h>
 222#include <linux/capability.h>
 223#include <linux/device.h>
 224#include <linux/kernel.h>
 225#include <linux/freezer.h>
 226#include <linux/smp.h>
 227#include <linux/dmi.h>
 228#include <linux/suspend.h>
 229#include <linux/kthread.h>
 230#include <linux/jiffies.h>
 231
 232#include <asm/system.h>
 233#include <asm/uaccess.h>
 234#include <asm/desc.h>
 235#include <asm/i8253.h>
 236#include <asm/olpc.h>
 237#include <asm/paravirt.h>
 238#include <asm/reboot.h>
 239
 240#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 241extern int (*console_blank_hook)(int);
 242#endif
 243
 244/*
 245 * The apm_bios device is one of the misc char devices.
 246 * This is its minor number.
 247 */
 248#define APM_MINOR_DEV   134
 249
 250/*
 251 * See Documentation/Config.help for the configuration options.
 252 *
 253 * Various options can be changed at boot time as follows:
 254 * (We allow underscores for compatibility with the modules code)
 255 *      apm=on/off                      enable/disable APM
 256 *          [no-]allow[-_]ints          allow interrupts during BIOS calls
 257 *          [no-]broken[-_]psr          BIOS has a broken GetPowerStatus call
 258 *          [no-]realmode[-_]power[-_]off       switch to real mode before
 259 *                                              powering off
 260 *          [no-]debug                  log some debugging messages
 261 *          [no-]power[-_]off           power off on shutdown
 262 *          [no-]smp                    Use apm even on an SMP box
 263 *          bounce[-_]interval=<n>      number of ticks to ignore suspend
 264 *                                      bounces
 265 *          idle[-_]threshold=<n>       System idle percentage above which to
 266 *                                      make APM BIOS idle calls. Set it to
 267 *                                      100 to disable.
 268 *          idle[-_]period=<n>          Period (in 1/100s of a second) over
 269 *                                      which the idle percentage is
 270 *                                      calculated.
 271 */
 272
 273/* KNOWN PROBLEM MACHINES:
 274 *
 275 * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
 276 *                         [Confirmed by TI representative]
 277 * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
 278 *                    [Confirmed by BIOS disassembly]
 279 *                    [This may work now ...]
 280 * P: Toshiba 1950S: battery life information only gets updated after resume
 281 * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
 282 *      broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
 283 * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP
 284 *      Neale Banks <neale@lowendale.com.au> December 2000
 285 *
 286 * Legend: U = unusable with APM patches
 287 *         P = partially usable with APM patches
 288 */
 289
 290/*
 291 * Define as 1 to make the driver always call the APM BIOS busy
 292 * routine even if the clock was not reported as slowed by the
 293 * idle routine.  Otherwise, define as 0.
 294 */
 295#define ALWAYS_CALL_BUSY   1
 296
 297/*
 298 * Define to make the APM BIOS calls zero all data segment registers (so
 299 * that an incorrect BIOS implementation will cause a kernel panic if it
 300 * tries to write to arbitrary memory).
 301 */
 302#define APM_ZERO_SEGS
 303
 304#include <asm/apm.h>
 305
 306/*
 307 * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
 308 * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
 309 * David Chen <chen@ctpa04.mit.edu>
 310 */
 311#undef INIT_TIMER_AFTER_SUSPEND
 312
 313#ifdef INIT_TIMER_AFTER_SUSPEND
 314#include <linux/timex.h>
 315#include <asm/io.h>
 316#include <linux/delay.h>
 317#endif
 318
 319/*
 320 * Need to poll the APM BIOS every second
 321 */
 322#define APM_CHECK_TIMEOUT       (HZ)
 323
 324/*
 325 * Ignore suspend events for this amount of time after a resume
 326 */
 327#define DEFAULT_BOUNCE_INTERVAL (3 * HZ)
 328
 329/*
 330 * Maximum number of events stored
 331 */
 332#define APM_MAX_EVENTS          20
 333
 334/*
 335 * The per-file APM data
 336 */
 337struct apm_user {
 338        int             magic;
 339        struct apm_user *next;
 340        unsigned int    suser: 1;
 341        unsigned int    writer: 1;
 342        unsigned int    reader: 1;
 343        unsigned int    suspend_wait: 1;
 344        int             suspend_result;
 345        int             suspends_pending;
 346        int             standbys_pending;
 347        int             suspends_read;
 348        int             standbys_read;
 349        int             event_head;
 350        int             event_tail;
 351        apm_event_t     events[APM_MAX_EVENTS];
 352};
 353
 354/*
 355 * The magic number in apm_user
 356 */
 357#define APM_BIOS_MAGIC          0x4101
 358
 359/*
 360 * idle percentage above which bios idle calls are done
 361 */
 362#ifdef CONFIG_APM_CPU_IDLE
 363#define DEFAULT_IDLE_THRESHOLD  95
 364#else
 365#define DEFAULT_IDLE_THRESHOLD  100
 366#endif
 367#define DEFAULT_IDLE_PERIOD     (100 / 3)
 368
 369/*
 370 * Local variables
 371 */
 372static struct {
 373        unsigned long   offset;
 374        unsigned short  segment;
 375} apm_bios_entry;
 376static int clock_slowed;
 377static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
 378static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
 379static int set_pm_idle;
 380static int suspends_pending;
 381static int standbys_pending;
 382static int ignore_sys_suspend;
 383static int ignore_normal_resume;
 384static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
 385
 386static int debug __read_mostly;
 387static int smp __read_mostly;
 388static int apm_disabled = -1;
 389#ifdef CONFIG_SMP
 390static int power_off;
 391#else
 392static int power_off = 1;
 393#endif
 394static int realmode_power_off;
 395#ifdef CONFIG_APM_ALLOW_INTS
 396static int allow_ints = 1;
 397#else
 398static int allow_ints;
 399#endif
 400static int broken_psr;
 401
 402static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 403static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 404static struct apm_user *user_list;
 405static DEFINE_SPINLOCK(user_list_lock);
 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        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        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                lock_kernel();
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                unlock_kernel();
1544                break;
1545        case APM_IOC_SUSPEND:
1546                lock_kernel();
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                } else {
1556                        as->suspend_wait = 1;
1557                        wait_event_interruptible(apm_suspend_waitqueue,
1558                                        as->suspend_wait == 0);
1559                        ret = as->suspend_result;
1560                }
1561                unlock_kernel();
1562                return ret;
1563        default:
1564                return -ENOTTY;
1565        }
1566        return 0;
1567}
1568
1569static int do_release(struct inode *inode, struct file *filp)
1570{
1571        struct apm_user *as;
1572
1573        as = filp->private_data;
1574        if (check_apm_user(as, "release"))
1575                return 0;
1576        filp->private_data = NULL;
1577        if (as->standbys_pending > 0) {
1578                standbys_pending -= as->standbys_pending;
1579                if (standbys_pending <= 0)
1580                        standby();
1581        }
1582        if (as->suspends_pending > 0) {
1583                suspends_pending -= as->suspends_pending;
1584                if (suspends_pending <= 0)
1585                        (void) suspend(1);
1586        }
1587        spin_lock(&user_list_lock);
1588        if (user_list == as)
1589                user_list = as->next;
1590        else {
1591                struct apm_user *as1;
1592
1593                for (as1 = user_list;
1594                     (as1 != NULL) && (as1->next != as);
1595                     as1 = as1->next)
1596                        ;
1597                if (as1 == NULL)
1598                        printk(KERN_ERR "apm: filp not in user list\n");
1599                else
1600                        as1->next = as->next;
1601        }
1602        spin_unlock(&user_list_lock);
1603        kfree(as);
1604        return 0;
1605}
1606
1607static int do_open(struct inode *inode, struct file *filp)
1608{
1609        struct apm_user *as;
1610
1611        lock_kernel();
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                       unlock_kernel();
1617                return -ENOMEM;
1618        }
1619        as->magic = APM_BIOS_MAGIC;
1620        as->event_tail = as->event_head = 0;
1621        as->suspends_pending = as->standbys_pending = 0;
1622        as->suspends_read = as->standbys_read = 0;
1623        /*
1624         * XXX - this is a tiny bit broken, when we consider BSD
1625         * process accounting. If the device is opened by root, we
1626         * instantly flag that we used superuser privs. Who knows,
1627         * we might close the device immediately without doing a
1628         * privileged operation -- cevans
1629         */
1630        as->suser = capable(CAP_SYS_ADMIN);
1631        as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
1632        as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
1633        spin_lock(&user_list_lock);
1634        as->next = user_list;
1635        user_list = as;
1636        spin_unlock(&user_list_lock);
1637        filp->private_data = as;
1638        unlock_kernel();
1639        return 0;
1640}
1641
1642static int proc_apm_show(struct seq_file *m, void *v)
1643{
1644        unsigned short  bx;
1645        unsigned short  cx;
1646        unsigned short  dx;
1647        int             error;
1648        unsigned short  ac_line_status = 0xff;
1649        unsigned short  battery_status = 0xff;
1650        unsigned short  battery_flag   = 0xff;
1651        int             percentage     = -1;
1652        int             time_units     = -1;
1653        char            *units         = "?";
1654
1655        if ((num_online_cpus() == 1) &&
1656            !(error = apm_get_power_status(&bx, &cx, &dx))) {
1657                ac_line_status = (bx >> 8) & 0xff;
1658                battery_status = bx & 0xff;
1659                if ((cx & 0xff) != 0xff)
1660                        percentage = cx & 0xff;
1661
1662                if (apm_info.connection_version > 0x100) {
1663                        battery_flag = (cx >> 8) & 0xff;
1664                        if (dx != 0xffff) {
1665                                units = (dx & 0x8000) ? "min" : "sec";
1666                                time_units = dx & 0x7fff;
1667                        }
1668                }
1669        }
1670        /* Arguments, with symbols from linux/apm_bios.h.  Information is
1671           from the Get Power Status (0x0a) call unless otherwise noted.
1672
1673           0) Linux driver version (this will change if format changes)
1674           1) APM BIOS Version.  Usually 1.0, 1.1 or 1.2.
1675           2) APM flags from APM Installation Check (0x00):
1676              bit 0: APM_16_BIT_SUPPORT
1677              bit 1: APM_32_BIT_SUPPORT
1678              bit 2: APM_IDLE_SLOWS_CLOCK
1679              bit 3: APM_BIOS_DISABLED
1680              bit 4: APM_BIOS_DISENGAGED
1681           3) AC line status
1682              0x00: Off-line
1683              0x01: On-line
1684              0x02: On backup power (BIOS >= 1.1 only)
1685              0xff: Unknown
1686           4) Battery status
1687              0x00: High
1688              0x01: Low
1689              0x02: Critical
1690              0x03: Charging
1691              0x04: Selected battery not present (BIOS >= 1.2 only)
1692              0xff: Unknown
1693           5) Battery flag
1694              bit 0: High
1695              bit 1: Low
1696              bit 2: Critical
1697              bit 3: Charging
1698              bit 7: No system battery
1699              0xff: Unknown
1700           6) Remaining battery life (percentage of charge):
1701              0-100: valid
1702              -1: Unknown
1703           7) Remaining battery life (time units):
1704              Number of remaining minutes or seconds
1705              -1: Unknown
1706           8) min = minutes; sec = seconds */
1707
1708        seq_printf(m, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1709                   driver_version,
1710                   (apm_info.bios.version >> 8) & 0xff,
1711                   apm_info.bios.version & 0xff,
1712                   apm_info.bios.flags,
1713                   ac_line_status,
1714                   battery_status,
1715                   battery_flag,
1716                   percentage,
1717                   time_units,
1718                   units);
1719        return 0;
1720}
1721
1722static int proc_apm_open(struct inode *inode, struct file *file)
1723{
1724        return single_open(file, proc_apm_show, NULL);
1725}
1726
1727static const struct file_operations apm_file_ops = {
1728        .owner          = THIS_MODULE,
1729        .open           = proc_apm_open,
1730        .read           = seq_read,
1731        .llseek         = seq_lseek,
1732        .release        = single_release,
1733};
1734
1735static int apm(void *unused)
1736{
1737        unsigned short  bx;
1738        unsigned short  cx;
1739        unsigned short  dx;
1740        int             error;
1741        char            *power_stat;
1742        char            *bat_stat;
1743
1744        /* 2002/08/01 - WT
1745         * This is to avoid random crashes at boot time during initialization
1746         * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
1747         * Some bioses don't like being called from CPU != 0.
1748         * Method suggested by Ingo Molnar.
1749         */
1750        set_cpus_allowed_ptr(current, cpumask_of(0));
1751        BUG_ON(smp_processor_id() != 0);
1752
1753        if (apm_info.connection_version == 0) {
1754                apm_info.connection_version = apm_info.bios.version;
1755                if (apm_info.connection_version > 0x100) {
1756                        /*
1757                         * We only support BIOSs up to version 1.2
1758                         */
1759                        if (apm_info.connection_version > 0x0102)
1760                                apm_info.connection_version = 0x0102;
1761                        error = apm_driver_version(&apm_info.connection_version);
1762                        if (error != APM_SUCCESS) {
1763                                apm_error("driver version", error);
1764                                /* Fall back to an APM 1.0 connection. */
1765                                apm_info.connection_version = 0x100;
1766                        }
1767                }
1768        }
1769
1770        if (debug)
1771                printk(KERN_INFO "apm: Connection version %d.%d\n",
1772                        (apm_info.connection_version >> 8) & 0xff,
1773                        apm_info.connection_version & 0xff);
1774
1775#ifdef CONFIG_APM_DO_ENABLE
1776        if (apm_info.bios.flags & APM_BIOS_DISABLED) {
1777                /*
1778                 * This call causes my NEC UltraLite Versa 33/C to hang if it
1779                 * is booted with PM disabled but not in the docking station.
1780                 * Unfortunate ...
1781                 */
1782                error = apm_enable_power_management(1);
1783                if (error) {
1784                        apm_error("enable power management", error);
1785                        return -1;
1786                }
1787        }
1788#endif
1789
1790        if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
1791            && (apm_info.connection_version > 0x0100)) {
1792                error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1793                if (error) {
1794                        apm_error("engage power management", error);
1795                        return -1;
1796                }
1797        }
1798
1799        if (debug && (num_online_cpus() == 1 || smp)) {
1800                error = apm_get_power_status(&bx, &cx, &dx);
1801                if (error)
1802                        printk(KERN_INFO "apm: power status not available\n");
1803                else {
1804                        switch ((bx >> 8) & 0xff) {
1805                        case 0:
1806                                power_stat = "off line";
1807                                break;
1808                        case 1:
1809                                power_stat = "on line";
1810                                break;
1811                        case 2:
1812                                power_stat = "on backup power";
1813                                break;
1814                        default:
1815                                power_stat = "unknown";
1816                                break;
1817                        }
1818                        switch (bx & 0xff) {
1819                        case 0:
1820                                bat_stat = "high";
1821                                break;
1822                        case 1:
1823                                bat_stat = "low";
1824                                break;
1825                        case 2:
1826                                bat_stat = "critical";
1827                                break;
1828                        case 3:
1829                                bat_stat = "charging";
1830                                break;
1831                        default:
1832                                bat_stat = "unknown";
1833                                break;
1834                        }
1835                        printk(KERN_INFO
1836                               "apm: AC %s, battery status %s, battery life ",
1837                               power_stat, bat_stat);
1838                        if ((cx & 0xff) == 0xff)
1839                                printk("unknown\n");
1840                        else
1841                                printk("%d%%\n", cx & 0xff);
1842                        if (apm_info.connection_version > 0x100) {
1843                                printk(KERN_INFO
1844                                       "apm: battery flag 0x%02x, battery life ",
1845                                       (cx >> 8) & 0xff);
1846                                if (dx == 0xffff)
1847                                        printk("unknown\n");
1848                                else
1849                                        printk("%d %s\n", dx & 0x7fff,
1850                                               (dx & 0x8000) ?
1851                                               "minutes" : "seconds");
1852                        }
1853                }
1854        }
1855
1856        /* Install our power off handler.. */
1857        if (power_off)
1858                pm_power_off = apm_power_off;
1859
1860        if (num_online_cpus() == 1 || smp) {
1861#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1862                console_blank_hook = apm_console_blank;
1863#endif
1864                apm_mainloop();
1865#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1866                console_blank_hook = NULL;
1867#endif
1868        }
1869
1870        return 0;
1871}
1872
1873#ifndef MODULE
1874static int __init apm_setup(char *str)
1875{
1876        int invert;
1877
1878        while ((str != NULL) && (*str != '\0')) {
1879                if (strncmp(str, "off", 3) == 0)
1880                        apm_disabled = 1;
1881                if (strncmp(str, "on", 2) == 0)
1882                        apm_disabled = 0;
1883                if ((strncmp(str, "bounce-interval=", 16) == 0) ||
1884                    (strncmp(str, "bounce_interval=", 16) == 0))
1885                        bounce_interval = simple_strtol(str + 16, NULL, 0);
1886                if ((strncmp(str, "idle-threshold=", 15) == 0) ||
1887                    (strncmp(str, "idle_threshold=", 15) == 0))
1888                        idle_threshold = simple_strtol(str + 15, NULL, 0);
1889                if ((strncmp(str, "idle-period=", 12) == 0) ||
1890                    (strncmp(str, "idle_period=", 12) == 0))
1891                        idle_period = simple_strtol(str + 12, NULL, 0);
1892                invert = (strncmp(str, "no-", 3) == 0) ||
1893                        (strncmp(str, "no_", 3) == 0);
1894                if (invert)
1895                        str += 3;
1896                if (strncmp(str, "debug", 5) == 0)
1897                        debug = !invert;
1898                if ((strncmp(str, "power-off", 9) == 0) ||
1899                    (strncmp(str, "power_off", 9) == 0))
1900                        power_off = !invert;
1901                if (strncmp(str, "smp", 3) == 0) {
1902                        smp = !invert;
1903                        idle_threshold = 100;
1904                }
1905                if ((strncmp(str, "allow-ints", 10) == 0) ||
1906                    (strncmp(str, "allow_ints", 10) == 0))
1907                        apm_info.allow_ints = !invert;
1908                if ((strncmp(str, "broken-psr", 10) == 0) ||
1909                    (strncmp(str, "broken_psr", 10) == 0))
1910                        apm_info.get_power_status_broken = !invert;
1911                if ((strncmp(str, "realmode-power-off", 18) == 0) ||
1912                    (strncmp(str, "realmode_power_off", 18) == 0))
1913                        apm_info.realmode_power_off = !invert;
1914                str = strchr(str, ',');
1915                if (str != NULL)
1916                        str += strspn(str, ", \t");
1917        }
1918        return 1;
1919}
1920
1921__setup("apm=", apm_setup);
1922#endif
1923
1924static const struct file_operations apm_bios_fops = {
1925        .owner          = THIS_MODULE,
1926        .read           = do_read,
1927        .poll           = do_poll,
1928        .unlocked_ioctl = do_ioctl,
1929        .open           = do_open,
1930        .release        = do_release,
1931};
1932
1933static struct miscdevice apm_device = {
1934        APM_MINOR_DEV,
1935        "apm_bios",
1936        &apm_bios_fops
1937};
1938
1939
1940/* Simple "print if true" callback */
1941static int __init print_if_true(const struct dmi_system_id *d)
1942{
1943        printk("%s\n", d->ident);
1944        return 0;
1945}
1946
1947/*
1948 * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it was
1949 * disabled before the suspend. Linux used to get terribly confused by that.
1950 */
1951static int __init broken_ps2_resume(const struct dmi_system_id *d)
1952{
1953        printk(KERN_INFO "%s machine detected. Mousepad Resume Bug "
1954               "workaround hopefully not needed.\n", d->ident);
1955        return 0;
1956}
1957
1958/* Some bioses have a broken protected mode poweroff and need to use realmode */
1959static int __init set_realmode_power_off(const struct dmi_system_id *d)
1960{
1961        if (apm_info.realmode_power_off == 0) {
1962                apm_info.realmode_power_off = 1;
1963                printk(KERN_INFO "%s bios detected. "
1964                       "Using realmode poweroff only.\n", d->ident);
1965        }
1966        return 0;
1967}
1968
1969/* Some laptops require interrupts to be enabled during APM calls */
1970static int __init set_apm_ints(const struct dmi_system_id *d)
1971{
1972        if (apm_info.allow_ints == 0) {
1973                apm_info.allow_ints = 1;
1974                printk(KERN_INFO "%s machine detected. "
1975                       "Enabling interrupts during APM calls.\n", d->ident);
1976        }
1977        return 0;
1978}
1979
1980/* Some APM bioses corrupt memory or just plain do not work */
1981static int __init apm_is_horked(const struct dmi_system_id *d)
1982{
1983        if (apm_info.disabled == 0) {
1984                apm_info.disabled = 1;
1985                printk(KERN_INFO "%s machine detected. "
1986                       "Disabling APM.\n", d->ident);
1987        }
1988        return 0;
1989}
1990
1991static int __init apm_is_horked_d850md(const struct dmi_system_id *d)
1992{
1993        if (apm_info.disabled == 0) {
1994                apm_info.disabled = 1;
1995                printk(KERN_INFO "%s machine detected. "
1996                       "Disabling APM.\n", d->ident);
1997                printk(KERN_INFO "This bug is fixed in bios P15 which is available for \n");
1998                printk(KERN_INFO "download from support.intel.com \n");
1999        }
2000        return 0;
2001}
2002
2003/* Some APM bioses hang on APM idle calls */
2004static int __init apm_likes_to_melt(const struct dmi_system_id *d)
2005{
2006        if (apm_info.forbid_idle == 0) {
2007                apm_info.forbid_idle = 1;
2008                printk(KERN_INFO "%s machine detected. "
2009                       "Disabling APM idle calls.\n", d->ident);
2010        }
2011        return 0;
2012}
2013
2014/*
2015 *  Check for clue free BIOS implementations who use
2016 *  the following QA technique
2017 *
2018 *      [ Write BIOS Code ]<------
2019 *               |                ^
2020 *      < Does it Compile >----N--
2021 *               |Y               ^
2022 *      < Does it Boot Win98 >-N--
2023 *               |Y
2024 *           [Ship It]
2025 *
2026 *      Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
2027 *      Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
2028 */
2029static int __init broken_apm_power(const struct dmi_system_id *d)
2030{
2031        apm_info.get_power_status_broken = 1;
2032        printk(KERN_WARNING "BIOS strings suggest APM bugs, "
2033               "disabling power status reporting.\n");
2034        return 0;
2035}
2036
2037/*
2038 * This bios swaps the APM minute reporting bytes over (Many sony laptops
2039 * have this problem).
2040 */
2041static int __init swab_apm_power_in_minutes(const struct dmi_system_id *d)
2042{
2043        apm_info.get_power_status_swabinminutes = 1;
2044        printk(KERN_WARNING "BIOS strings suggest APM reports battery life "
2045               "in minutes and wrong byte order.\n");
2046        return 0;
2047}
2048
2049static struct dmi_system_id __initdata apm_dmi_table[] = {
2050        {
2051                print_if_true,
2052                KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.",
2053                {       DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
2054                        DMI_MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"), },
2055        },
2056        {       /* Handle problems with APM on the C600 */
2057                broken_ps2_resume, "Dell Latitude C600",
2058                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
2059                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude C600"), },
2060        },
2061        {       /* Allow interrupts during suspend on Dell Latitude laptops*/
2062                set_apm_ints, "Dell Latitude",
2063                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2064                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude C510"), }
2065        },
2066        {       /* APM crashes */
2067                apm_is_horked, "Dell Inspiron 2500",
2068                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2069                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
2070                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2071                        DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
2072        },
2073        {       /* Allow interrupts during suspend on Dell Inspiron laptops*/
2074                set_apm_ints, "Dell Inspiron", {
2075                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2076                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"), },
2077        },
2078        {       /* Handle problems with APM on Inspiron 5000e */
2079                broken_apm_power, "Dell Inspiron 5000e",
2080                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2081                        DMI_MATCH(DMI_BIOS_VERSION, "A04"),
2082                        DMI_MATCH(DMI_BIOS_DATE, "08/24/2000"), },
2083        },
2084        {       /* Handle problems with APM on Inspiron 2500 */
2085                broken_apm_power, "Dell Inspiron 2500",
2086                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2087                        DMI_MATCH(DMI_BIOS_VERSION, "A12"),
2088                        DMI_MATCH(DMI_BIOS_DATE, "02/04/2002"), },
2089        },
2090        {       /* APM crashes */
2091                apm_is_horked, "Dell Dimension 4100",
2092                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2093                        DMI_MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
2094                        DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2095                        DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
2096        },
2097        {       /* Allow interrupts during suspend on Compaq Laptops*/
2098                set_apm_ints, "Compaq 12XL125",
2099                {       DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
2100                        DMI_MATCH(DMI_PRODUCT_NAME, "Compaq PC"),
2101                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2102                        DMI_MATCH(DMI_BIOS_VERSION, "4.06"), },
2103        },
2104        {       /* Allow interrupts during APM or the clock goes slow */
2105                set_apm_ints, "ASUSTeK",
2106                {       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
2107                        DMI_MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"), },
2108        },
2109        {       /* APM blows on shutdown */
2110                apm_is_horked, "ABIT KX7-333[R]",
2111                {       DMI_MATCH(DMI_BOARD_VENDOR, "ABIT"),
2112                        DMI_MATCH(DMI_BOARD_NAME, "VT8367-8233A (KX7-333[R])"), },
2113        },
2114        {       /* APM crashes */
2115                apm_is_horked, "Trigem Delhi3",
2116                {       DMI_MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
2117                        DMI_MATCH(DMI_PRODUCT_NAME, "Delhi3"), },
2118        },
2119        {       /* APM crashes */
2120                apm_is_horked, "Fujitsu-Siemens",
2121                {       DMI_MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"),
2122                        DMI_MATCH(DMI_BIOS_VERSION, "Version1.01"), },
2123        },
2124        {       /* APM crashes */
2125                apm_is_horked_d850md, "Intel D850MD",
2126                {       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2127                        DMI_MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"), },
2128        },
2129        {       /* APM crashes */
2130                apm_is_horked, "Intel D810EMO",
2131                {       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2132                        DMI_MATCH(DMI_BIOS_VERSION, "MO81010A.86A.0008.P04.0004170800"), },
2133        },
2134        {       /* APM crashes */
2135                apm_is_horked, "Dell XPS-Z",
2136                {       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
2137                        DMI_MATCH(DMI_BIOS_VERSION, "A11"),
2138                        DMI_MATCH(DMI_PRODUCT_NAME, "XPS-Z"), },
2139        },
2140        {       /* APM crashes */
2141                apm_is_horked, "Sharp PC-PJ/AX",
2142                {       DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
2143                        DMI_MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
2144                        DMI_MATCH(DMI_BIOS_VENDOR, "SystemSoft"),
2145                        DMI_MATCH(DMI_BIOS_VERSION, "Version R2.08"), },
2146        },
2147        {       /* APM crashes */
2148                apm_is_horked, "Dell Inspiron 2500",
2149                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2150                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
2151                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2152                        DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
2153        },
2154        {       /* APM idle hangs */
2155                apm_likes_to_melt, "Jabil AMD",
2156                {       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
2157                        DMI_MATCH(DMI_BIOS_VERSION, "0AASNP06"), },
2158        },
2159        {       /* APM idle hangs */
2160                apm_likes_to_melt, "AMI Bios",
2161                {       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
2162                        DMI_MATCH(DMI_BIOS_VERSION, "0AASNP05"), },
2163        },
2164        {       /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */
2165                swab_apm_power_in_minutes, "Sony VAIO",
2166                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2167                        DMI_MATCH(DMI_BIOS_VERSION, "R0206H"),
2168                        DMI_MATCH(DMI_BIOS_DATE, "08/23/99"), },
2169        },
2170        {       /* Handle problems with APM on Sony Vaio PCG-N505VX */
2171                swab_apm_power_in_minutes, "Sony VAIO",
2172                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2173                        DMI_MATCH(DMI_BIOS_VERSION, "W2K06H0"),
2174                        DMI_MATCH(DMI_BIOS_DATE, "02/03/00"), },
2175        },
2176        {       /* Handle problems with APM on Sony Vaio PCG-XG29 */
2177                swab_apm_power_in_minutes, "Sony VAIO",
2178                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2179                        DMI_MATCH(DMI_BIOS_VERSION, "R0117A0"),
2180                        DMI_MATCH(DMI_BIOS_DATE, "04/25/00"), },
2181        },
2182        {       /* Handle problems with APM on Sony Vaio PCG-Z600NE */
2183                swab_apm_power_in_minutes, "Sony VAIO",
2184                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2185                        DMI_MATCH(DMI_BIOS_VERSION, "R0121Z1"),
2186                        DMI_MATCH(DMI_BIOS_DATE, "05/11/00"), },
2187        },
2188        {       /* Handle problems with APM on Sony Vaio PCG-Z600NE */
2189                swab_apm_power_in_minutes, "Sony VAIO",
2190                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2191                        DMI_MATCH(DMI_BIOS_VERSION, "WME01Z1"),
2192                        DMI_MATCH(DMI_BIOS_DATE, "08/11/00"), },
2193        },
2194        {       /* Handle problems with APM on Sony Vaio PCG-Z600LEK(DE) */
2195                swab_apm_power_in_minutes, "Sony VAIO",
2196                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2197                        DMI_MATCH(DMI_BIOS_VERSION, "R0206Z3"),
2198                        DMI_MATCH(DMI_BIOS_DATE, "12/25/00"), },
2199        },
2200        {       /* Handle problems with APM on Sony Vaio PCG-Z505LS */
2201                swab_apm_power_in_minutes, "Sony VAIO",
2202                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2203                        DMI_MATCH(DMI_BIOS_VERSION, "R0203D0"),
2204                        DMI_MATCH(DMI_BIOS_DATE, "05/12/00"), },
2205        },
2206        {       /* Handle problems with APM on Sony Vaio PCG-Z505LS */
2207                swab_apm_power_in_minutes, "Sony VAIO",
2208                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2209                        DMI_MATCH(DMI_BIOS_VERSION, "R0203Z3"),
2210                        DMI_MATCH(DMI_BIOS_DATE, "08/25/00"), },
2211        },
2212        {       /* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
2213                swab_apm_power_in_minutes, "Sony VAIO",
2214                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2215                        DMI_MATCH(DMI_BIOS_VERSION, "R0209Z3"),
2216                        DMI_MATCH(DMI_BIOS_DATE, "05/12/01"), },
2217        },
2218        {       /* Handle problems with APM on Sony Vaio PCG-F104K */
2219                swab_apm_power_in_minutes, "Sony VAIO",
2220                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2221                        DMI_MATCH(DMI_BIOS_VERSION, "R0204K2"),
2222                        DMI_MATCH(DMI_BIOS_DATE, "08/28/00"), },
2223        },
2224
2225        {       /* Handle problems with APM on Sony Vaio PCG-C1VN/C1VE */
2226                swab_apm_power_in_minutes, "Sony VAIO",
2227                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2228                        DMI_MATCH(DMI_BIOS_VERSION, "R0208P1"),
2229                        DMI_MATCH(DMI_BIOS_DATE, "11/09/00"), },
2230        },
2231        {       /* Handle problems with APM on Sony Vaio PCG-C1VE */
2232                swab_apm_power_in_minutes, "Sony VAIO",
2233                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2234                        DMI_MATCH(DMI_BIOS_VERSION, "R0204P1"),
2235                        DMI_MATCH(DMI_BIOS_DATE, "09/12/00"), },
2236        },
2237        {       /* Handle problems with APM on Sony Vaio PCG-C1VE */
2238                swab_apm_power_in_minutes, "Sony VAIO",
2239                {       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
2240                        DMI_MATCH(DMI_BIOS_VERSION, "WXPO1Z3"),
2241                        DMI_MATCH(DMI_BIOS_DATE, "10/26/01"), },
2242        },
2243        {       /* broken PM poweroff bios */
2244                set_realmode_power_off, "Award Software v4.60 PGMA",
2245                {       DMI_MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
2246                        DMI_MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
2247                        DMI_MATCH(DMI_BIOS_DATE, "134526184"), },
2248        },
2249
2250        /* Generic per vendor APM settings  */
2251
2252        {       /* Allow interrupts during suspend on IBM laptops */
2253                set_apm_ints, "IBM",
2254                {       DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
2255        },
2256
2257        { }
2258};
2259
2260/*
2261 * Just start the APM thread. We do NOT want to do APM BIOS
2262 * calls from anything but the APM thread, if for no other reason
2263 * than the fact that we don't trust the APM BIOS. This way,
2264 * most common APM BIOS problems that lead to protection errors
2265 * etc will have at least some level of being contained...
2266 *
2267 * In short, if something bad happens, at least we have a choice
2268 * of just killing the apm thread..
2269 */
2270static int __init apm_init(void)
2271{
2272        struct desc_struct *gdt;
2273        int err;
2274
2275        dmi_check_system(apm_dmi_table);
2276
2277        if (apm_info.bios.version == 0 || paravirt_enabled() || machine_is_olpc()) {
2278                printk(KERN_INFO "apm: BIOS not found.\n");
2279                return -ENODEV;
2280        }
2281        printk(KERN_INFO
2282               "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
2283               ((apm_info.bios.version >> 8) & 0xff),
2284               (apm_info.bios.version & 0xff),
2285               apm_info.bios.flags,
2286               driver_version);
2287        if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
2288                printk(KERN_INFO "apm: no 32 bit BIOS support\n");
2289                return -ENODEV;
2290        }
2291
2292        if (allow_ints)
2293                apm_info.allow_ints = 1;
2294        if (broken_psr)
2295                apm_info.get_power_status_broken = 1;
2296        if (realmode_power_off)
2297                apm_info.realmode_power_off = 1;
2298        /* User can override, but default is to trust DMI */
2299        if (apm_disabled != -1)
2300                apm_info.disabled = apm_disabled;
2301
2302        /*
2303         * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
2304         * but is reportedly a 1.0 BIOS.
2305         */
2306        if (apm_info.bios.version == 0x001)
2307                apm_info.bios.version = 0x100;
2308
2309        /* BIOS < 1.2 doesn't set cseg_16_len */
2310        if (apm_info.bios.version < 0x102)
2311                apm_info.bios.cseg_16_len = 0; /* 64k */
2312
2313        if (debug) {
2314                printk(KERN_INFO "apm: entry %x:%x cseg16 %x dseg %x",
2315                        apm_info.bios.cseg, apm_info.bios.offset,
2316                        apm_info.bios.cseg_16, apm_info.bios.dseg);
2317                if (apm_info.bios.version > 0x100)
2318                        printk(" cseg len %x, dseg len %x",
2319                                apm_info.bios.cseg_len,
2320                                apm_info.bios.dseg_len);
2321                if (apm_info.bios.version > 0x101)
2322                        printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
2323                printk("\n");
2324        }
2325
2326        if (apm_info.disabled) {
2327                printk(KERN_NOTICE "apm: disabled on user request.\n");
2328                return -ENODEV;
2329        }
2330        if ((num_online_cpus() > 1) && !power_off && !smp) {
2331                printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
2332                apm_info.disabled = 1;
2333                return -ENODEV;
2334        }
2335        if (pm_flags & PM_ACPI) {
2336                printk(KERN_NOTICE "apm: overridden by ACPI.\n");
2337                apm_info.disabled = 1;
2338                return -ENODEV;
2339        }
2340        pm_flags |= PM_APM;
2341
2342        /*
2343         * Set up the long jump entry point to the APM BIOS, which is called
2344         * from inline assembly.
2345         */
2346        apm_bios_entry.offset = apm_info.bios.offset;
2347        apm_bios_entry.segment = APM_CS;
2348
2349        /*
2350         * The APM 1.1 BIOS is supposed to provide limit information that it
2351         * recognizes.  Many machines do this correctly, but many others do
2352         * not restrict themselves to their claimed limit.  When this happens,
2353         * they will cause a segmentation violation in the kernel at boot time.
2354         * Most BIOS's, however, will respect a 64k limit, so we use that.
2355         *
2356         * Note we only set APM segments on CPU zero, since we pin the APM
2357         * code to that CPU.
2358         */
2359        gdt = get_cpu_gdt_table(0);
2360        set_desc_base(&gdt[APM_CS >> 3],
2361                 (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4));
2362        set_desc_base(&gdt[APM_CS_16 >> 3],
2363                 (unsigned long)__va((unsigned long)apm_info.bios.cseg_16 << 4));
2364        set_desc_base(&gdt[APM_DS >> 3],
2365                 (unsigned long)__va((unsigned long)apm_info.bios.dseg << 4));
2366
2367        proc_create("apm", 0, NULL, &apm_file_ops);
2368
2369        kapmd_task = kthread_create(apm, NULL, "kapmd");
2370        if (IS_ERR(kapmd_task)) {
2371                printk(KERN_ERR "apm: disabled - Unable to start kernel "
2372                                "thread.\n");
2373                err = PTR_ERR(kapmd_task);
2374                kapmd_task = NULL;
2375                remove_proc_entry("apm", NULL);
2376                return err;
2377        }
2378        wake_up_process(kapmd_task);
2379
2380        if (num_online_cpus() > 1 && !smp) {
2381                printk(KERN_NOTICE
2382                       "apm: disabled - APM is not SMP safe (power off active).\n");
2383                return 0;
2384        }
2385
2386        /*
2387         * Note we don't actually care if the misc_device cannot be registered.
2388         * this driver can do its job without it, even if userspace can't
2389         * control it.  just log the error
2390         */
2391        if (misc_register(&apm_device))
2392                printk(KERN_WARNING "apm: Could not register misc device.\n");
2393
2394        if (HZ != 100)
2395                idle_period = (idle_period * HZ) / 100;
2396        if (idle_threshold < 100) {
2397                original_pm_idle = pm_idle;
2398                pm_idle  = apm_cpu_idle;
2399                set_pm_idle = 1;
2400        }
2401
2402        return 0;
2403}
2404
2405static void __exit apm_exit(void)
2406{
2407        int error;
2408
2409        if (set_pm_idle) {
2410                pm_idle = original_pm_idle;
2411                /*
2412                 * We are about to unload the current idle thread pm callback
2413                 * (pm_idle), Wait for all processors to update cached/local
2414                 * copies of pm_idle before proceeding.
2415                 */
2416                cpu_idle_wait();
2417        }
2418        if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
2419            && (apm_info.connection_version > 0x0100)) {
2420                error = apm_engage_power_management(APM_DEVICE_ALL, 0);
2421                if (error)
2422                        apm_error("disengage power management", error);
2423        }
2424        misc_deregister(&apm_device);
2425        remove_proc_entry("apm", NULL);
2426        if (power_off)
2427                pm_power_off = NULL;
2428        if (kapmd_task) {
2429                kthread_stop(kapmd_task);
2430                kapmd_task = NULL;
2431        }
2432        pm_flags &= ~PM_APM;
2433}
2434
2435module_init(apm_init);
2436module_exit(apm_exit);
2437
2438MODULE_AUTHOR("Stephen Rothwell");
2439MODULE_DESCRIPTION("Advanced Power Management");
2440MODULE_LICENSE("GPL");
2441module_param(debug, bool, 0644);
2442MODULE_PARM_DESC(debug, "Enable debug mode");
2443module_param(power_off, bool, 0444);
2444MODULE_PARM_DESC(power_off, "Enable power off");
2445module_param(bounce_interval, int, 0444);
2446MODULE_PARM_DESC(bounce_interval,
2447                "Set the number of ticks to ignore suspend bounces");
2448module_param(allow_ints, bool, 0444);
2449MODULE_PARM_DESC(allow_ints, "Allow interrupts during BIOS calls");
2450module_param(broken_psr, bool, 0444);
2451MODULE_PARM_DESC(broken_psr, "BIOS has a broken GetPowerStatus call");
2452module_param(realmode_power_off, bool, 0444);
2453MODULE_PARM_DESC(realmode_power_off,
2454                "Switch to real mode before powering off");
2455module_param(idle_threshold, int, 0444);
2456MODULE_PARM_DESC(idle_threshold,
2457        "System idle percentage above which to make APM BIOS idle calls");
2458module_param(idle_period, int, 0444);
2459MODULE_PARM_DESC(idle_period,
2460        "Period (in sec/100) over which to caculate the idle percentage");
2461module_param(smp, bool, 0444);
2462MODULE_PARM_DESC(smp,
2463        "Set this to enable APM use on an SMP platform. Use with caution on older systems");
2464MODULE_ALIAS_MISCDEV(APM_MINOR_DEV);
2465