summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/pc98/apm/apm.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/sys/pc98/apm/apm.c b/sys/pc98/apm/apm.c
index 0ad8df5..925d616 100644
--- a/sys/pc98/apm/apm.c
+++ b/sys/pc98/apm/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>
@@ -58,6 +60,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;
@@ -802,6 +806,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
@@ -809,6 +837,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");
@@ -840,6 +873,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;
@@ -1154,10 +1193,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;
}
@@ -1431,4 +1473,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