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