^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);