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