patch-2.1.125 linux/arch/i386/kernel/apm.c
Next file: linux/arch/i386/kernel/io_apic.c
Previous file: linux/arch/i386/defconfig
Back to the patch index
Back to the overall index
- Lines: 355
- Date:
Wed Oct 7 18:52:05 1998
- Orig file:
v2.1.124/linux/arch/i386/kernel/apm.c
- Orig date:
Thu Sep 17 17:53:34 1998
diff -u --recursive --new-file v2.1.124/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
@@ -2,6 +2,8 @@
* APM BIOS driver for Linux
* Copyright 1994-1998 Stephen Rothwell
* (Stephen.Rothwell@canb.auug.org.au)
+ * 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
@@ -27,6 +29,7 @@
* Feb 1998, Version 1.3
* Feb 1998, Version 1.4
* Aug 1998, Version 1.5
+ * Sep 1998, Version 1.6
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -51,7 +54,12 @@
* 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
+ * 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
*
* APM 1.1 Reference:
*
@@ -214,7 +222,8 @@
/*
* Save a segment register away
*/
-#define savesegment(seg, where) __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
+#define savesegment(seg, where) \
+ __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
/*
* Forward declarations
@@ -264,7 +273,7 @@
static struct timer_list apm_timer;
-static char driver_version[] = "1.5"; /* no spaces */
+static char driver_version[] = "1.6"; /* no spaces */
#ifdef APM_DEBUG
static char * apm_event_name[] = {
@@ -350,105 +359,95 @@
* 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.
+ *
+ * Also, we KNOW that for the non error case of apm_bios_call, there
+ * is no useful data returned in the low order 8 bits of eax.
*/
-
-static inline int apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in,
- u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
-{
- unsigned int old_fs, old_gs;
- int error;
-
-#ifdef APM_ZERO_SEGS
- savesegment(fs, old_fs);
- savesegment(gs, old_gs);
-#endif
- __asm__ __volatile__(
- "pushfl\n\t"
#ifdef APM_NOINTS
- "cli\n\t"
+# define APM_DO_CLI __cli()
+#else
+# define APM_DO_CLI
#endif
#ifdef APM_ZERO_SEGS
- "pushl %%ds\n\t"
- "pushl %%es\n\t"
- "movl %w9,%%ds\n\t"
- "movl %w9,%%es\n\t"
- "movl %w9,%%fs\n\t"
- "movl %w9,%%gs\n\t"
+# define APM_DO_SAVE_SEGS \
+ savesegment(fs, saved_fs); \
+ savesegment(gs, saved_gs)
+# define APM_DO_ZERO_SEGS \
+ "pushl %%ds\n\t" \
+ "pushl %%es\n\t" \
+ "xorl %%edx, %%edx\n\t" \
+ "mov %%dx, %%ds\n\t" \
+ "mov %%dx, %%es\n\t" \
+ "mov %%dx, %%fs\n\t" \
+ "mov %%dx, %%gs\n\t"
+# define APM_DO_POP_SEGS \
+ "popl %%es\n\t" \
+ "popl %%ds\n\t"
+# define APM_DO_RESTORE_SEGS \
+ loadsegment(fs, saved_fs); \
+ loadsegment(gs, saved_gs)
+#else
+# define APM_DO_SAVE_SEGS
+# define APM_DO_ZERO_SEGS
+# define APM_DO_POP_SEGS
+# define APM_DO_RESTORE_SEGS
#endif
+
+static inline u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in,
+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
+{
+ unsigned int saved_fs;
+ unsigned int saved_gs;
+ unsigned long flags;
+
+ __save_flags(flags);
+ APM_DO_CLI;
+ APM_DO_SAVE_SEGS;
+ __asm__ __volatile__(APM_DO_ZERO_SEGS
"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
- "movl $0, %%edi\n\t"
- "jnc 1f\n\t"
- "movl $1, %%edi\n"
- "1:\tpopl %%es\n\t"
- "popl %%ds\n\t"
- "popfl\n\t"
+ "setc %%al\n\t"
+ APM_DO_POP_SEGS
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
- "=S" (*esi), "=D" (error)
+ "=S" (*esi)
: "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
-#ifdef APM_ZERO_SEGS
- , "r" (0)
-#endif
- : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory");
-#ifdef APM_ZERO_SEGS
- loadsegment(fs, old_fs);
- loadsegment(gs, old_gs);
-#endif
- return error;
+ : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory", "cc");
+ APM_DO_RESTORE_SEGS;
+ __restore_flags(flags);
+ return *eax & 0xff;
}
/*
* This version only returns one value (usually an error code)
*/
-static inline int apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in, u32 *eax)
+static inline u8 apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in,
+ u32 *eax)
{
- unsigned int old_fs, old_gs;
- int error;
+ u8 error;
+ unsigned int saved_fs;
+ unsigned int saved_gs;
+ unsigned long flags;
-#ifdef APM_ZERO_SEGS
- savesegment(fs, old_fs);
- savesegment(gs, old_gs);
-#endif
- __asm__ __volatile__(
- "pushfl\n\t"
-#ifdef APM_NOINTS
- "cli\n\t"
-#endif
-#ifdef APM_ZERO_SEGS
- "pushl %%ds\n\t"
- "pushl %%es\n\t"
- "movl %w5,%%ds\n\t"
- "movl %w5,%%es\n\t"
- "movl %w5,%%fs\n\t"
- "movl %w5,%%gs\n\t"
-#endif
+ __save_flags(flags);
+ APM_DO_CLI;
+ APM_DO_SAVE_SEGS;
+ __asm__ __volatile__(APM_DO_ZERO_SEGS
"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
- "movl $0, %%edi\n\t"
- "jnc 1f\n\t"
- "movl $1, %%edi\n"
- "1:\tpopl %%es\n\t"
- "popl %%ds\n\t"
- "popfl\n\t"
- : "=a" (*eax), "=D" (error)
+ "setc %%bl\n\t"
+ APM_DO_POP_SEGS
+ : "=a" (*eax), "=b" (error)
: "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
-#ifdef APM_ZERO_SEGS
- , "r" (0)
-#endif
- : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory");
-#ifdef APM_ZERO_SEGS
- loadsegment(fs, old_fs);
- loadsegment(gs, old_gs);
-#endif
+ : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory", "cc");
+ APM_DO_RESTORE_SEGS;
+ __restore_flags(flags);
return error;
}
static int apm_driver_version(u_short *val)
{
- int error;
u32 eax;
- error = apm_bios_call_simple(0x530e, 0, *val, &eax);
- if (error)
+ if (apm_bios_call_simple(0x530e, 0, *val, &eax))
return (eax >> 8) & 0xff;
*val = eax;
return APM_SUCCESS;
@@ -456,14 +455,12 @@
static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
{
- int error;
u32 eax;
u32 ebx;
u32 ecx;
u32 dummy;
- error = apm_bios_call(0x530b, 0, 0, &eax, &ebx, &ecx, &dummy, &dummy);
- if (error)
+ if (apm_bios_call(0x530b, 0, 0, &eax, &ebx, &ecx, &dummy, &dummy))
return (eax >> 8) & 0xff;
*event = ebx;
if (apm_bios_info.version < 0x0102)
@@ -473,27 +470,31 @@
return APM_SUCCESS;
}
-static int set_power_state(u_short what, u_short state)
+static inline int set_power_state(u_short what, u_short state)
{
- int error;
u32 eax;
- error = apm_bios_call_simple(0x5307, what, state, &eax);
- if (error)
+ if (apm_bios_call_simple(0x5307, what, state, &eax))
return (eax >> 8) & 0xff;
return APM_SUCCESS;
}
-int apm_set_power_state(u_short state)
+static int apm_set_power_state(u_short state)
{
return set_power_state(0x0001, state);
}
+void apm_power_off(void)
+{
+ if (apm_enabled)
+ (void) apm_set_power_state(APM_STATE_OFF);
+}
+
#ifdef CONFIG_APM_DISPLAY_BLANK
/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
static int apm_set_display_power_state(u_short state)
{
- return set_power_state(0x01ff, state);
+ return set_power_state(0x0100, state);
}
#endif
@@ -501,12 +502,11 @@
/* Called by apm_setup if apm_enabled will be true. */
static int apm_enable_power_management(void)
{
- int error;
u32 eax;
- error = apm_bios_call_simple(0x5308,
- (apm_bios_info.version > 0x100) ? 0x0001 : 0xffff, 1, &eax);
- if (error)
+ if (apm_bios_call_simple(0x5308,
+ (apm_bios_info.version > 0x100) ? 0x0001 : 0xffff,
+ 1, &eax))
return (eax >> 8) & 0xff;
return APM_SUCCESS;
}
@@ -514,15 +514,13 @@
static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
{
- int error;
u32 eax;
u32 ebx;
u32 ecx;
u32 edx;
u32 dummy;
- error = apm_bios_call(0x530a, 1, 0, &eax, &ebx, &ecx, &edx, &dummy);
- if (error)
+ if (apm_bios_call(0x530a, 1, 0, &eax, &ebx, &ecx, &edx, &dummy))
return (eax >> 8) & 0xff;
*status = ebx;
*bat = ecx;
@@ -536,7 +534,6 @@
u_short *bat, u_short *life, u_short *nbat)
{
u_short status;
- int error;
u32 eax;
u32 ebx;
u32 ecx;
@@ -551,8 +548,8 @@
return apm_get_power_status(&status, bat, life);
}
- error = apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax, &ebx, &ecx, &edx, &esi);
- if (error)
+ if (apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax,
+ &ebx, &ecx, &edx, &esi))
return (eax >> 8) & 0xff;
*bat = ecx;
*life = edx;
@@ -563,11 +560,9 @@
static int apm_engage_power_management(u_short device)
{
- int error;
u32 eax;
- error = apm_bios_call_simple(0x530f, device, 1, &eax);
- if (error)
+ if (apm_bios_call_simple(0x530f, device, 1, &eax))
return (eax >> 8) & 0xff;
return APM_SUCCESS;
}
@@ -875,14 +870,12 @@
int apm_do_idle(void)
{
#ifdef CONFIG_APM_CPU_IDLE
- int error;
u32 dummy;
if (!apm_enabled)
return 0;
- error = apm_bios_call_simple(0x5305, 0, 0, &dummy);
- if (error)
+ if (apm_bios_call_simple(0x5305, 0, 0, &dummy))
return 0;
clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov