summaryrefslogtreecommitdiffstats
path: root/sys/i386/bios
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2001-11-01 16:34:07 +0000
committeriwasaki <iwasaki@FreeBSD.org>2001-11-01 16:34:07 +0000
commitf1842a13d838c3a94044961bbf70910f54a49956 (patch)
tree386182cbb6b07e9a3fa20ca8415118c34d61ecae /sys/i386/bios
parent9440591aaa9e7f2d8ef542a245eb93b2c2547844 (diff)
downloadFreeBSD-src-f1842a13d838c3a94044961bbf70910f54a49956.zip
FreeBSD-src-f1842a13d838c3a94044961bbf70910f54a49956.tar.gz
Some fix for the recent apm module changes.
- Now that apm loadable module can inform its existence to other kernel components (e.g. i386/isa/clock.c:startrtclock()'s TCS hack). - Exchange priority of SI_SUB_CPU and SI_SUB_KLD for above purpose. - Add simple arbitration mechanism for APM vs. ACPI. This prevents the kernel enables both of them. - Remove obsolete `#ifdef DEV_APM' related code. - Add abstracted interface for Powermanagement operations. Public apm(4) functions, such as apm_suspend(), should be replaced new interfaces. Currently only power_pm_suspend (successor of apm_suspend) is implemented. Reviewed by: peter, arch@ and audit@
Diffstat (limited to 'sys/i386/bios')
-rw-r--r--sys/i386/bios/apm.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/sys/i386/bios/apm.c b/sys/i386/bios/apm.c
index 1b7cbc5..85d4bd2 100644
--- a/sys/i386/bios/apm.c
+++ b/sys/i386/bios/apm.c
@@ -32,9 +32,11 @@
#include <sys/uio.h>
#include <sys/signalvar.h>
#include <sys/sysctl.h>
+#include <sys/power.h>
#include <machine/apm_bios.h>
#include <machine/segments.h>
#include <machine/clock.h>
+#include <machine/stdarg.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
@@ -53,6 +55,8 @@ static void apm_resume __P((void));
static int apm_bioscall(void);
static int apm_check_function_supported __P((u_int version, u_int func));
+static int apm_pm_func(u_long, void*, ...);
+
static u_long apm_version;
int apm_evindex;
@@ -742,6 +746,30 @@ apm_not_halt_cpu(void)
/* device driver definitions */
/*
+ * Module event
+ */
+
+static int
+apm_modevent(struct module *mod, int event, void *junk)
+{
+
+ switch (event) {
+ case MOD_LOAD:
+ if (!cold)
+ return (EPERM);
+ break;
+ case MOD_UNLOAD:
+ if (!cold && power_pm_get_type() == POWER_PM_TYPE_APM)
+ return (EBUSY);
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+/*
* Create "connection point"
*/
static void
@@ -749,6 +777,11 @@ apm_identify(driver_t *driver, device_t parent)
{
device_t child;
+ if (!cold) {
+ printf("Don't load this driver from userland!!\n");
+ return;
+ }
+
child = BUS_ADD_CHILD(parent, 0, "apm", 0);
if (child == NULL)
panic("apm_identify");
@@ -777,6 +810,12 @@ apm_probe(device_t dev)
return ENXIO;
}
+ if (power_pm_get_type() != POWER_PM_TYPE_NONE &&
+ power_pm_get_type() != POWER_PM_TYPE_APM) {
+ printf("apm: Other PM system enabled.\n");
+ return ENXIO;
+ }
+
if (resource_int_value("apm", 0, "flags", &flags) != 0)
flags = 0;
@@ -1038,10 +1077,13 @@ apm_attach(device_t dev)
EVENTHANDLER_REGISTER(shutdown_final, apm_power_off, NULL,
SHUTDOWN_PRI_LAST);
+ /* Register APM again to pass the correct argument of pm_func. */
+ power_pm_register(POWER_PM_TYPE_APM, apm_pm_func, sc);
+
sc->initialized = 1;
sc->suspending = 0;
- make_dev(&apm_cdevsw, 0, 0, 5, 0660, "apm");
+ make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm");
make_dev(&apm_cdevsw, 8, 0, 5, 0660, "apmctl");
return 0;
}
@@ -1315,4 +1357,56 @@ static driver_t apm_driver = {
static devclass_t apm_devclass;
-DRIVER_MODULE(apm, nexus, apm_driver, apm_devclass, 0, 0);
+DRIVER_MODULE(apm, nexus, apm_driver, apm_devclass, apm_modevent, 0);
+MODULE_VERSION(apm, 1);
+
+static int
+apm_pm_func(u_long cmd, void *arg, ...)
+{
+ int state, apm_state;
+ int error;
+ va_list ap;
+
+ error = 0;
+ switch (cmd) {
+ case POWER_CMD_SUSPEND:
+ va_start(ap, arg);
+ state = va_arg(ap, int);
+ va_end(ap);
+
+ switch (state) {
+ case POWER_SLEEP_STATE_STANDBY:
+ apm_state = PMST_STANDBY;
+ break;
+ case POWER_SLEEP_STATE_SUSPEND:
+ case POWER_SLEEP_STATE_HIBERNATE:
+ apm_state = PMST_SUSPEND;
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ apm_suspend(apm_state);
+ break;
+
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+out:
+ return (error);
+}
+
+static void
+apm_pm_register(void *arg)
+{
+ int disabled = 0;
+
+ resource_int_value("apm", 0, "disabled", &disabled);
+ if (disabled == 0)
+ power_pm_register(POWER_PM_TYPE_APM, apm_pm_func, NULL);
+}
+
+SYSINIT(power, SI_SUB_KLD, SI_ORDER_ANY, apm_pm_register, 0);
OpenPOWER on IntegriCloud