Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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