⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apm.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- linux-c -*- * APM BIOS driver for Linux * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * Initial development of this driver was funded by NEC Australia P/L *	and NEC Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * October 1995, Rik Faith (faith@cs.unc.edu): *    Minor enhancements and updates (to the patch set) for 1.3.x *    Documentation * January 1996, Rik Faith (faith@cs.unc.edu): *    Make /proc/apm easy to format (bump driver version) * March 1996, Rik Faith (faith@cs.unc.edu): *    Prohibit APM BIOS calls unless apm_enabled. *    (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>) * April 1996, Stephen Rothwell (sfr@canb.auug.org.au) *    Version 1.0 and 1.1 * May 1996, Version 1.2 * Feb 1998, Version 1.3 * Feb 1998, Version 1.4 * Aug 1998, Version 1.5 * Sep 1998, Version 1.6 * Nov 1998, Version 1.7 * Jan 1999, Version 1.8 * Jan 1999, Version 1.9 * Oct 1999, Version 1.10 * Nov 1999, Version 1.11 * Jan 2000, Version 1.12 * Feb 2000, Version 1.13 * Nov 2000, Version 1.14 * Oct 2001, Version 1.15 * Jan 2002, Version 1.16 * * History: *    0.6b: first version in official kernel, Linux 1.3.46 *    0.7: changed /proc/apm format, Linux 1.3.58 *    0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59 *    0.9: only call bios if bios is present, Linux 1.3.72 *    1.0: use fixed device number, consolidate /proc/apm into this file, *         Linux 1.3.85 *    1.1: support user-space standby and suspend, power off after system *         halted, Linux 1.3.98 *    1.2: When resetting RTC after resume, take care so that the time *         is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth *         <jtoth@princeton.edu>); improve interaction between *         screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4 *    1.2a:Simple change to stop mysterious bug reports with SMP also added *	   levels to the printk calls. APM is not defined for SMP machines. *         The new replacment for it is, but Linux doesn't yet support this. *         Alan Cox Linux 2.1.55 *    1.3: Set up a valid data descriptor 0x40 for buggy BIOS's *    1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by *         Dean Gaudet <dgaudet@arctic.org>. *         C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87 *    1.5: Fix segment register reloading (in case of bad segments saved *         across BIOS call). *         Stephen Rothwell *    1.6: Cope with complier/assembler differences. *         Only try to turn off the first display device. *         Fix OOPS at power off with no APM BIOS by Jan Echternach *                   <echter@informatik.uni-rostock.de> *         Stephen Rothwell *    1.7: Modify driver's cached copy of the disabled/disengaged flags *         to reflect current state of APM BIOS. *         Chris Rankin <rankinc@bellsouth.net> *         Reset interrupt 0 timer to 100Hz after suspend *         Chad Miller <cmiller@surfsouth.com> *         Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE *         Richard Gooch <rgooch@atnf.csiro.au> *         Allow boot time disabling of APM *         Make boot messages far less verbose by default *         Make asm safer *         Stephen Rothwell *    1.8: Add CONFIG_APM_RTC_IS_GMT *         Richard Gooch <rgooch@atnf.csiro.au> *         change APM_NOINTS to CONFIG_APM_ALLOW_INTS *         remove dependency on CONFIG_PROC_FS *         Stephen Rothwell *    1.9: Fix small typo.  <laslo@wodip.opole.pl> *         Try to cope with BIOS's that need to have all display *         devices blanked and not just the first one. *         Ross Paterson <ross@soi.city.ac.uk> *         Fix segment limit setting it has always been wrong as *         the segments needed to have byte granularity. *         Mark a few things __init. *         Add hack to allow power off of SMP systems by popular request. *         Use CONFIG_SMP instead of __SMP__ *         Ignore BOUNCES for three seconds. *         Stephen Rothwell *   1.10: Fix for Thinkpad return code. *         Merge 2.2 and 2.3 drivers. *         Remove APM dependencies in arch/i386/kernel/process.c *         Remove APM dependencies in drivers/char/sysrq.c *         Reset time across standby. *         Allow more inititialisation on SMP. *         Remove CONFIG_APM_POWER_OFF and make it boot time *         configurable (default on). *         Make debug only a boot time parameter (remove APM_DEBUG). *         Try to blank all devices on any error. *   1.11: Remove APM dependencies in drivers/char/console.c *         Check nr_running to detect if we are idle (from *         Borislav Deianov <borislav@lix.polytechnique.fr>) *         Fix for bioses that don't zero the top part of the *         entrypoint offset (Mario Sitta <sitta@al.unipmn.it>) *         (reported by Panos Katsaloulis <teras@writeme.com>). *         Real mode power off patch (Walter Hofmann *         <Walter.Hofmann@physik.stud.uni-erlangen.de>). *   1.12: Remove CONFIG_SMP as the compiler will optimize *         the code away anyway (smp_num_cpus == 1 in UP) *         noted by Artur Skawina <skawina@geocities.com>. *         Make power off under SMP work again. *         Fix thinko with initial engaging of BIOS. *         Make sure power off only happens on CPU 0 *         (Paul "Rusty" Russell <rusty@rustcorp.com.au>). *         Do error notification to user mode if BIOS calls fail. *         Move entrypoint offset fix to ...boot/setup.S *         where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>). *         Remove smp-power-off. SMP users must now specify *         "apm=power-off" on the kernel command line. Suggested *         by Jim Avera <jima@hal.com>, modified by Alan Cox *         <alan@lxorguk.ukuu.org.uk>. *         Register the /proc/apm entry even on SMP so that *         scripts that check for it before doing power off *         work (Jim Avera <jima@hal.com>). *   1.13: Changes for new pm_ interfaces (Andy Henroid *         <andy_henroid@yahoo.com>). *         Modularize the code. *         Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS *         is now the way life works). *         Fix thinko in suspend() (wrong return). *         Notify drivers on critical suspend. *         Make kapmd absorb more idle time (Pavel Machek <pavel@suse.cz> *         modified by sfr). *         Disable interrupts while we are suspended (Andy Henroid *         <andy_henroid@yahoo.com> fixed by sfr). *         Make power off work on SMP again (Tony Hoyle *         <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr. *         Remove CONFIG_APM_SUSPEND_BOUNCE.  The bounce ignore *         interval is now configurable. *   1.14: Make connection version persist across module unload/load. *         Enable and engage power management earlier. *         Disengage power management on module unload. *         Changed to use the sysrq-register hack for registering the *         power off function called by magic sysrq based upon discussions *         in irc://irc.openprojects.net/#kernelnewbies *         (Crutcher Dunnavant <crutcher+kernel@datastacks.com>). *         Make CONFIG_APM_REAL_MODE_POWER_OFF run time configurable. *         (Arjan van de Ven <arjanv@redhat.com>) modified by sfr. *         Work around byte swap bug in one of the Vaio's BIOS's *         (Marc Boucher <marc@mbsi.ca>). *         Exposed the disable flag to dmi so that we can handle known *         broken APM (Alan Cox <alan@redhat.com>). *   1.14ac: If the BIOS says "I slowed the CPU down" then don't spin *         calling it - instead idle. (Alan Cox <alan@redhat.com>) *         If an APM idle fails log it and idle sensibly *   1.15: Don't queue events to clients who open the device O_WRONLY. *         Don't expect replies from clients who open the device O_RDONLY. *         (Idea from Thomas Hood <jdthood@mail.com>) *         Minor waitqueue cleanups. (John Fremlin <chief@bandits.org>) *   1.16: Fix idle calling. (Andreas Steinmetz <ast@domdv.de> et al.) *         Notify listeners of standby or suspend events before notifying *         drivers. Return EBUSY to ioctl() if suspend is rejected. *         (Russell King <rmk@arm.linux.org.uk> and Thomas Hood) *         Ignore first resume after we generate our own resume event *         after a suspend (Thomas Hood <jdthood@mail.com>) *         Daemonize now gets rid of our controlling terminal (sfr). *         CONFIG_APM_CPU_IDLE now just affects the default value of *         idle_threshold (sfr). *         Change name of kernel apm daemon (as it no longer idles) (sfr). * * APM 1.1 Reference: * *   Intel Corporation, Microsoft Corporation. Advanced Power Management *   (APM) BIOS Interface Specification, Revision 1.1, September 1993. *   Intel Order Number 241704-001.  Microsoft Part Number 781-110-X01. * * [This document is available free from Intel by calling 800.628.8686 (fax * 916.356.6100) or 800.548.4725; or via anonymous ftp from * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc.  It is also * available from Microsoft by calling 206.882.8080.] * * APM 1.2 Reference: *   Intel Corporation, Microsoft Corporation. Advanced Power Management *   (APM) BIOS Interface Specification, Revision 1.2, February 1996. * * [This document is available from Microsoft at: *    http://www.microsoft.com/hwdev/busbios/amp_12.htm] */#include <linux/config.h>#include <linux/module.h>#include <linux/poll.h>#include <linux/types.h>#include <linux/stddef.h>#include <linux/timer.h>#include <linux/fcntl.h>#include <linux/slab.h>#include <linux/stat.h>#include <linux/proc_fs.h>#include <linux/miscdevice.h>#include <linux/apm_bios.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/pm.h>#include <linux/kernel.h>#include <linux/smp_lock.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/desc.h>#include <linux/sysrq.h>extern unsigned long get_cmos_time(void);extern void machine_real_restart(unsigned char *, int);#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)extern int (*console_blank_hook)(int);#endif/* * The apm_bios device is one of the misc char devices. * This is its minor number. */#define	APM_MINOR_DEV	134/* * See Documentation/Config.help for the configuration options. * * Various options can be changed at boot time as follows: * (We allow underscores for compatibility with the modules code) *	apm=on/off			enable/disable APM *	    [no-]allow[-_]ints		allow interrupts during BIOS calls *	    [no-]broken[-_]psr		BIOS has a broken GetPowerStatus call *	    [no-]realmode[-_]power[-_]off	switch to real mode before *	    					powering off *	    [no-]debug			log some debugging messages *	    [no-]power[-_]off		power off on shutdown *	    bounce[-_]interval=<n>	number of ticks to ignore suspend *	    				bounces *          idle[-_]threshold=<n>       System idle percentage above which to *                                      make APM BIOS idle calls. Set it to *                                      100 to disable. *          idle[-_]period=<n>          Period (in 1/100s of a second) over *                                      which the idle percentage is *                                      calculated. *//* KNOWN PROBLEM MACHINES: * * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant *                         [Confirmed by TI representative] * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification *                    [Confirmed by BIOS disassembly] *                    [This may work now ...] * P: Toshiba 1950S: battery life information only gets updated after resume * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking * 	broken in BIOS [Reported by Garst R. Reese <reese@isn.net>] * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP * 	Neale Banks <neale@lowendale.com.au> December 2000 * * Legend: U = unusable with APM patches *         P = partially usable with APM patches *//* * Define as 1 to make the driver always call the APM BIOS busy * routine even if the clock was not reported as slowed by the * idle routine.  Otherwise, define as 0. */#define ALWAYS_CALL_BUSY   1/* * Define to make the APM BIOS calls zero all data segment registers (so * that an incorrect BIOS implementation will cause a kernel panic if it * tries to write to arbitrary memory). */#define APM_ZERO_SEGS/* * Define to make all _set_limit calls use 64k limits.  The APM 1.1 BIOS is * supposed to provide limit information that it recognizes.  Many machines * do this correctly, but many others do not restrict themselves to their * claimed limit.  When this happens, they will cause a segmentation * violation in the kernel at boot time.  Most BIOS's, however, will * respect a 64k limit, so we use that.  If you want to be pedantic and * hold your BIOS to its claims, then undefine this. */#define APM_RELAX_SEGMENTS/* * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. * This patched by Chad Miller <cmiller@surfsouth.com>, original code by * David Chen <chen@ctpa04.mit.edu> */#undef INIT_TIMER_AFTER_SUSPEND#ifdef INIT_TIMER_AFTER_SUSPEND#include <linux/timex.h>#include <asm/io.h>#include <linux/delay.h>#endif/* * Need to poll the APM BIOS every second */#define APM_CHECK_TIMEOUT	(HZ)/* * Ignore suspend events for this amount of time after a resume */#define DEFAULT_BOUNCE_INTERVAL		(3 * HZ)/* * Save a segment register away */#define savesegment(seg, where) \		__asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))/* * Maximum number of events stored */#define APM_MAX_EVENTS		20/* * The per-file APM data */struct apm_user {	int		magic;	struct apm_user *	next;	int		suser: 1;	int		writer: 1;	int		reader: 1;	int		suspend_wait: 1;	int		suspend_result;	int		suspends_pending;	int		standbys_pending;	int		suspends_read;	int		standbys_read;	int		event_head;	int		event_tail;	apm_event_t	events[APM_MAX_EVENTS];};/* * The magic number in apm_user */#define APM_BIOS_MAGIC		0x4101/* * idle percentage above which bios idle calls are done */#ifdef CONFIG_APM_CPU_IDLE#define DEFAULT_IDLE_THRESHOLD	95#else#define DEFAULT_IDLE_THRESHOLD	100#endif#define DEFAULT_IDLE_PERIOD	(100 / 3)/* * Local variables */static struct {	unsigned long	offset;	unsigned short	segment;}				apm_bios_entry;static int			clock_slowed;static int			idle_threshold = DEFAULT_IDLE_THRESHOLD;static int			idle_period = DEFAULT_IDLE_PERIOD;static int			set_pm_idle;static int			suspends_pending;static int			standbys_pending;static int			ignore_sys_suspend;static int			ignore_normal_resume;static int			bounce_interval = DEFAULT_BOUNCE_INTERVAL;#ifdef CONFIG_APM_RTC_IS_GMT#	define	clock_cmos_diff	0#	define	got_clock_diff	1#elsestatic long			clock_cmos_diff;static int			got_clock_diff;#endifstatic int			debug;static int			apm_disabled = -1;#ifdef CONFIG_SMPstatic int			power_off;#elsestatic int			power_off = 1;#endif#ifdef CONFIG_APM_REAL_MODE_POWER_OFFstatic int			realmode_power_off = 1;#elsestatic int			realmode_power_off;#endifstatic int			exit_kapmd;static int			kapmd_running;#ifdef CONFIG_APM_ALLOW_INTSstatic int			allow_ints = 1;#elsestatic int			allow_ints;#endifstatic int			broken_psr;static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);static struct apm_user *	user_list;static char			driver_version[] = "1.16";	/* no spaces *//* *	APM event names taken from the APM 1.2 specification. These are *	the message codes that the BIOS uses to tell us about events */static char *	apm_event_name[] = {	"system standby",	"system suspend",	"normal resume",	"critical resume",	"low battery",	"power status change",	"update time",	"critical suspend",	"user standby",	"user suspend",	"system standby resume",	"capabilities change"};#define NR_APM_EVENT_NAME	\		(sizeof(apm_event_name) / sizeof(apm_event_name[0]))typedef struct lookup_t {	int	key;	char *	msg;} lookup_t;/* *	The BIOS returns a set of standard error codes in AX when the *	carry flag is set. */ static const lookup_t error_table[] = {/* N/A	{ APM_SUCCESS,		"Operation succeeded" }, */	{ APM_DISABLED,		"Power management disabled" },	{ APM_CONNECTED,	"Real mode interface already connected" },	{ APM_NOT_CONNECTED,	"Interface not connected" },	{ APM_16_CONNECTED,	"16 bit interface already connected" },/* N/A	{ APM_16_UNSUPPORTED,	"16 bit interface not supported" }, */	{ APM_32_CONNECTED,	"32 bit interface already connected" },	{ APM_32_UNSUPPORTED,	"32 bit interface not supported" },	{ APM_BAD_DEVICE,	"Unrecognized device ID" },	{ APM_BAD_PARAM,	"Parameter out of range" },	{ APM_NOT_ENGAGED,	"Interface not engaged" },	{ APM_BAD_FUNCTION,     "Function not supported" },	{ APM_RESUME_DISABLED,	"Resume timer disabled" },	{ APM_BAD_STATE,	"Unable to enter requested state" },/* N/A	{ APM_NO_EVENTS,	"No events pending" }, */	{ APM_NO_ERROR,		"BIOS did not set a return code" },	{ APM_NOT_PRESENT,	"No APM present" }};#define ERROR_COUNT	(sizeof(error_table)/sizeof(lookup_t))/** *	apm_error	-	display an APM error *	@str: information string *	@err: APM BIOS return code * *	Write a meaningful log entry to the kernel log in the event of *	an APM error. */ static void apm_error(char *str, int err){	int	i;	for (i = 0; i < ERROR_COUNT; i++)		if (error_table[i].key == err) break;	if (i < ERROR_COUNT)		printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);	else		printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",			str, err);}/* * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and * apm_info.allow_ints, we are being really paranoid here!  Not only * are interrupts disabled, but all the segment registers (except SS) * are saved and zeroed this means that if the BIOS tries to reference * any data without explicitly loading the segment registers, the kernel * will fault immediately rather than have some unforeseen circumstances * for the rest of the kernel.  And it will be very obvious!  :-) Doing * this depends on CS referring to the same physical memory as DS so that * DS can be zeroed before the call. Unfortunately, we can't do anything * about the stack segment/pointer.  Also, we tell the compiler that * everything could change. *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -