Some enhancements for the apm driver

Swen Thuemmler (swen@uni-paderborn.de)
Wed, 23 Jul 1997 22:32:14 +0200 (MET DST)


Hi,

after nearly being bored to death while waiting for the kernel to
recompile, because I wanted to test some APM options, I decided, it would
be a GoodThing(tm) to be able to select the APM features on the boot
prompt. Here are my patches, hope you like it. Now it is possible to say

boot: linux apm=display-blank,apm-enable,no-cpu-idle,no-ignore-user-suspend
or
boot: linux apm=off

The flags diplay-blank, apm-enable, cpu-idle, ignore-user-suspend mimic the
former compile time options, they can be prefixed with no- to turn the
feature off. The compile time flags now just select the defaults.
With apm=off you may disable apm support in the kernel. BEWARE, this is not
the same as disabling APM at compile time, since the BIOS probe can not be
disabled this way. But you still might find it useful.

Greetings, Swen
-------------------------------+------------------------------------
Swen Thuemmler | Telefon : +49 5251 603325
Universitaet Paderborn, FB 17 | Telefax : +49 5251 603530
Warburger Str. 100 | email : swen@uni-paderborn.de
D-33095 Paderborn | Raum : E3.128
-------- pgp public key at pgp-public-keys@uni-paderborn.de --------
Unix _IS_ user friendly - it's just selective about who its friends are.

---------8< if you cut here, you will probably damage your screen >8--------

diff -ur kernel-source-2.0.30.orig/drivers/char/apm_bios.c kernel-source-2.0.30/drivers/char/apm_bios.c
--- kernel-source-2.0.30.orig/drivers/char/apm_bios.c Sun May 25 13:50:17 1997
+++ kernel-source-2.0.30/drivers/char/apm_bios.c Mon Jul 21 13:28:30 1997
@@ -89,15 +89,18 @@
#define APM_MINOR_DEV 134

/* Configurable options:
- *
- * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests.
+ *
+ * apm=off: no apm calls will be made (the BIOS is still queried, since this
+ * has to be in setup.S and cannot be turned off with a boot option).
+ *
+ * apm=[no-]ignore-user-suspend: boot option to ignore USER SUSPEND requests.
* This is necessary on the NEC Versa M series, which generates these when
* resuming from SYSTEM SUSPEND. However, enabling this on other laptops
* will cause the laptop to generate a CRITICAL SUSPEND when an appropriate
* USER SUSPEND is ignored -- this may prevent the APM driver from updating
* the system time on a RESUME.
*
- * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of
+ * apm=[no-]apm-enable: enable APM features at boot time. From page 36 of
* the specification: "When disabled, the APM BIOS does not automatically
* power manage devices, enter the Standby State, enter the Suspend State,
* or take power saving steps in response to CPU Idle calls." This driver
@@ -110,24 +113,20 @@
* 33/C or a Toshiba T400CDT. This is off by default since most machines
* do fine without this feature.
*
- * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the
+ * apm=[no-]cpu-idle: enable calls to APM CPU Idle/CPU Busy inside the
* idle loop. On some machines, this can activate improved power savings,
* such as a slowed CPU clock rate, when the machine is idle. These idle
* call is made after the idle loop has run for some length of time (e.g.,
* 333 mS). On some machines, this will cause a hang at boot time or
* whenever the CPU becomes idle.
*
- * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some
+ * apm=[no-]display-blank: enable console blanking using the APM. Some
* laptops can use this to turn of the LCD backlight when the VC screen
* blanker blanks the screen. Note that this is only used by the VC screen
* blanker, and probably won't turn off the backlight when using X11. Some
* problems have been reported when using this option with gpm (if you'd
* like to debug this, please do so).
*
- * If you are debugging the APM support for your laptop, note that code for
- * all of these options is contained in this file, so you can #define or
- * #undef these on the next line to avoid recompiling the whole kernel.
- *
*/

/* KNOWN PROBLEM MACHINES:
@@ -233,13 +232,11 @@
#define APM_BIOS_CALL_END \
: "ax", "bx", "cx", "dx", "si", "di", "bp", "memory")

-#ifdef CONFIG_APM_CPU_IDLE
#define APM_SET_CPU_IDLE(error) \
APM_BIOS_CALL(al) \
: "=a" (error) \
: "a" (0x5305) \
APM_BIOS_CALL_END
-#endif

#define APM_SET_CPU_BUSY(error) \
APM_BIOS_CALL(al) \
@@ -253,21 +250,17 @@
: "a" (0x5307), "b" (0x0001), "c" (state) \
APM_BIOS_CALL_END

-#ifdef CONFIG_APM_DISPLAY_BLANK
#define APM_SET_DISPLAY_POWER_STATE(state, error) \
APM_BIOS_CALL(al) \
: "=a" (error) \
: "a" (0x5307), "b" (0x01ff), "c" (state) \
APM_BIOS_CALL_END
-#endif

-#ifdef CONFIG_APM_DO_ENABLE
#define APM_ENABLE_POWER_MANAGEMENT(device, error) \
APM_BIOS_CALL(al) \
: "=a" (error) \
: "a" (0x5308), "b" (device), "c" (1) \
APM_BIOS_CALL_END
-#endif

#define APM_GET_POWER_STATUS(bx, cx, dx, error) \
APM_BIOS_CALL(al) \
@@ -325,9 +318,29 @@
unsigned short segment;
} apm_bios_entry;
static int apm_enabled = 0;
+static int apm_wanted = 1; /* set to zero by apm_setup, when
+ * APM disabled from commandline */
+#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
+static int apm_ignore_user_suspend = 1;
+#else
+static int apm_ignore_user_suspend = 0;
+#endif
+#ifdef CONFIG_APM_DO_ENABLE
+static int apm_do_enable = 1;
+#else
+static int apm_do_enable = 0;
+#endif
#ifdef CONFIG_APM_CPU_IDLE
-static int clock_slowed = 0;
+static int apm_cpu_idle = 1;
+#else
+static int apm_cpu_idle = 0;
+#endif
+#ifdef CONFIG_APM_DISPLAY_BLANK
+static int apm_do_display_blank = 1;
+#else
+static int apm_do_display_blank = 0;
#endif
+static int clock_slowed = 0;
static int suspends_pending = 0;
static int standbys_pending = 0;

@@ -446,7 +459,6 @@
return APM_SUCCESS;
}

-#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)
{
@@ -457,10 +469,8 @@
return (error >> 8);
return APM_SUCCESS;
}
-#endif

-#ifdef CONFIG_APM_DO_ENABLE
-/* Called by apm_setup if apm_enabled will be true. */
+/* Called by apm_bios_init if apm_enabled will be true. */
static int apm_enable_power_management(void)
{
u_short error;
@@ -472,7 +482,6 @@
return (error >> 8);
return APM_SUCCESS;
}
-#endif

static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
{
@@ -509,32 +518,28 @@
/* Called from console driver -- must make sure apm_enabled. */
int apm_display_blank(void)
{
-#ifdef CONFIG_APM_DISPLAY_BLANK
int error;

- if (!apm_enabled)
+ if (!apm_enabled || !apm_do_display_blank)
return 0;
error = apm_set_display_power_state(APM_STATE_STANDBY);
if (error == APM_SUCCESS)
return 1;
apm_error("set display standby", error);
-#endif
return 0;
}

/* Called from console driver -- must make sure apm_enabled. */
int apm_display_unblank(void)
{
-#ifdef CONFIG_APM_DISPLAY_BLANK
int error;

- if (!apm_enabled)
+ if (!apm_enabled || !apm_do_display_blank)
return 0;
error = apm_set_display_power_state(APM_STATE_READY);
if (error == APM_SUCCESS)
return 1;
apm_error("set display ready", error);
-#endif
return 0;
}

@@ -701,11 +706,9 @@
break;

case APM_USER_SUSPEND:
-#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
- if (apm_bios_info.version > 0x100)
+ if (apm_bios_info.version > 0x100 && apm_ignore_user_suspend)
apm_set_power_state(APM_STATE_REJECT);
break;
-#endif
case APM_SYS_SUSPEND:
send_event(event, APM_NORMAL_RESUME, NULL);
if (suspends_pending <= 0)
@@ -771,10 +774,9 @@
/* Called from sys_idle, must make sure apm_enabled. */
int apm_do_idle(void)
{
-#ifdef CONFIG_APM_CPU_IDLE
unsigned short error;

- if (!apm_enabled)
+ if (!apm_enabled || !apm_cpu_idle)
return 0;

APM_SET_CPU_IDLE(error);
@@ -783,18 +785,14 @@

clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
return 1;
-#else
- return 0;
-#endif
}

/* Called from sys_idle, must make sure apm_enabled. */
void apm_do_busy(void)
{
-#ifdef CONFIG_APM_CPU_IDLE
unsigned short error;

- if (!apm_enabled)
+ if (!apm_enabled || !apm_cpu_idle)
return;

#ifndef ALWAYS_CALL_BUSY
@@ -805,7 +803,6 @@
APM_SET_CPU_BUSY(error);

clock_slowed = 0;
-#endif
}

static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
@@ -1079,6 +1076,8 @@
char * power_stat;
char * bat_stat;

+ if (!apm_wanted)
+ return;
if (apm_bios_info.version == 0) {
printk("APM BIOS not found.\n");
return;
@@ -1183,18 +1182,18 @@
}
}

-#ifdef CONFIG_APM_DO_ENABLE
/*
* This call causes my NEC UltraLite Versa 33/C to hang if it is
* booted with PM disabled but not in the docking station.
* Unfortunate ...
*/
- error = apm_enable_power_management();
- if (error)
- apm_error("enable power management", error);
- if (error == APM_DISABLED)
- return;
-#endif
+ if (apm_do_enable) {
+ error = apm_enable_power_management();
+ if (error)
+ apm_error("enable power management", error);
+ if (error == APM_DISABLED)
+ return;
+ }

init_timer(&apm_timer);
apm_timer.function = do_apm_timer;
@@ -1210,4 +1209,36 @@
misc_register(&apm_device);

apm_enabled = 1;
+}
+
+void apm_setup(char *str, int *ints)
+{
+ while(1)
+ {
+ if (!strcmp(str, "cpu-idle"))
+ apm_cpu_idle = 1;
+ else if (!strcmp(str, "no-cpu-idle"))
+ apm_cpu_idle = 1;
+ else if (!strcmp(str, "apm-enable"))
+ apm_do_enable = 1;
+ else if (!strcmp(str, "no-apm-enable"))
+ apm_do_enable = 0;
+ else if (!strcmp(str, "display-blank"))
+ apm_do_display_blank = 1;
+ else if (!strcmp(str, "no-display-blank"))
+ apm_do_display_blank = 0;
+ else if (!strcmp(str, "ignore-user-suspend"))
+ apm_ignore_user_suspend = 1;
+ else if (!strcmp(str, "no-ignore-user-suspend"))
+ apm_ignore_user_suspend = 0;
+ else if (!strcmp(str, "off"))
+ apm_wanted = 0;
+ else
+ printk(KERN_WARNING "apm_setup: unknown parameter!\n");
+ if ((str = strchr(str, ',')) != NULL)
+ str++;
+ else
+ break;
+ }
+ return;
}
diff -ur kernel-source-2.0.30.orig/init/main.c kernel-source-2.0.30/init/main.c
--- kernel-source-2.0.30.orig/init/main.c Sat May 31 01:44:08 1997
+++ kernel-source-2.0.30/init/main.c Mon Jul 21 12:57:52 1997
@@ -191,6 +191,9 @@
#ifdef CONFIG_BIGPHYS_AREA
extern void bigphysarea_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_APM
+extern void apm_setup(char *str, int *ints);
+#endif

/*
* Boot command-line arguments
@@ -450,6 +453,9 @@
#endif
#ifdef CONFIG_BIGPHYS_AREA
{ "bigphysarea=", bigphysarea_setup },
+#endif
+#ifdef CONFIG_APM
+ { "apm=", apm_setup },
#endif
{ 0, 0 }
};