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