diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index e3410e6bef9c..ff3fc73e87b2 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi.c,v 1.34 2003/04/17 01:22:21 thorpej Exp $ */ +/* $NetBSD: acpi.c,v 1.35 2003/04/18 01:31:34 thorpej Exp $ */ /* * Copyright 2001, 2003 Wasabi Systems, Inc. @@ -41,7 +41,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.34 2003/04/17 01:22:21 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.35 2003/04/18 01:31:34 thorpej Exp $"); #include "opt_acpi.h" @@ -225,6 +225,8 @@ acpi_attach(struct device *parent, struct device *self, void *aux) if (acpi_softc != NULL) panic("acpi_attach: ACPI has already been attached"); + sysmon_power_settype("acpi"); + printf("%s: X/RSDT: OemId <%6.6s,%8.8s,%08x>, AslId <%4.4s,%08x>\n", sc->sc_dev.dv_xname, ap->OemId, ap->OemTableId, ap->OemRevision, @@ -653,7 +655,7 @@ acpi_enable_fixed_events(struct acpi_softc *sc) printf("%s: fixed-feature power button present\n", sc->sc_dev.dv_xname); sc->sc_smpsw_power.smpsw_name = sc->sc_dev.dv_xname; - sc->sc_smpsw_power.smpsw_type = SMPSW_TYPE_POWER; + sc->sc_smpsw_power.smpsw_type = PSWITCH_TYPE_POWER; if (sysmon_pswitch_register(&sc->sc_smpsw_power) != 0) { printf("%s: unable to register fixed power button " "with sysmon\n", sc->sc_dev.dv_xname); @@ -673,7 +675,7 @@ acpi_enable_fixed_events(struct acpi_softc *sc) printf("%s: fixed-feature sleep button present\n", sc->sc_dev.dv_xname); sc->sc_smpsw_sleep.smpsw_name = sc->sc_dev.dv_xname; - sc->sc_smpsw_sleep.smpsw_type = SMPSW_TYPE_SLEEP; + sc->sc_smpsw_sleep.smpsw_type = PSWITCH_TYPE_SLEEP; if (sysmon_pswitch_register(&sc->sc_smpsw_power) != 0) { printf("%s: unable to register fixed sleep button " "with sysmon\n", sc->sc_dev.dv_xname); @@ -729,7 +731,7 @@ acpi_fixed_button_pressed(void *context) smpsw->smpsw_name); #endif - sysmon_pswitch_event(smpsw, SMPSW_EVENT_PRESSED); + sysmon_pswitch_event(smpsw, PSWITCH_EVENT_PRESSED); } /***************************************************************************** diff --git a/sys/dev/acpi/acpi_button.c b/sys/dev/acpi/acpi_button.c index 56db56b16879..c2c3a73c61e8 100644 --- a/sys/dev/acpi/acpi_button.c +++ b/sys/dev/acpi/acpi_button.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_button.c,v 1.8 2003/04/17 01:26:41 thorpej Exp $ */ +/* $NetBSD: acpi_button.c,v 1.9 2003/04/18 01:31:34 thorpej Exp $ */ /* * Copyright 2001, 2003 Wasabi Systems, Inc. @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: acpi_button.c,v 1.8 2003/04/17 01:26:41 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_button.c,v 1.9 2003/04/18 01:31:34 thorpej Exp $"); #include #include @@ -106,10 +106,10 @@ acpibut_attach(struct device *parent, struct device *self, void *aux) sc->sc_smpsw.smpsw_name = sc->sc_dev.dv_xname; if (strcmp(aa->aa_node->ad_devinfo.HardwareId, "PNP0C0C") == 0) { - sc->sc_smpsw.smpsw_type = SMPSW_TYPE_POWER; + sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_POWER; desc = "Power"; } else if (strcmp(aa->aa_node->ad_devinfo.HardwareId, "PNP0C0E") == 0) { - sc->sc_smpsw.smpsw_type = SMPSW_TYPE_SLEEP; + sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_SLEEP; desc = "Sleep"; } else { printf("\n"); @@ -153,7 +153,7 @@ acpibut_pressed_event(void *arg) if (sc->sc_flags & ACPIBUT_F_VERBOSE) printf("%s: button pressed\n", sc->sc_dev.dv_xname); - sysmon_pswitch_event(&sc->sc_smpsw, SMPSW_EVENT_PRESSED); + sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED); } /* diff --git a/sys/dev/acpi/acpi_lid.c b/sys/dev/acpi/acpi_lid.c index 89aa81057f6c..e0ddf70f6cbd 100644 --- a/sys/dev/acpi/acpi_lid.c +++ b/sys/dev/acpi/acpi_lid.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_lid.c,v 1.7 2003/04/17 01:34:14 thorpej Exp $ */ +/* $NetBSD: acpi_lid.c,v 1.8 2003/04/18 01:31:34 thorpej Exp $ */ /* * Copyright 2001, 2003 Wasabi Systems, Inc. @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: acpi_lid.c,v 1.7 2003/04/17 01:34:14 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_lid.c,v 1.8 2003/04/18 01:31:34 thorpej Exp $"); #include #include @@ -103,7 +103,7 @@ acpilid_attach(struct device *parent, struct device *self, void *aux) sc->sc_node = aa->aa_node; sc->sc_smpsw.smpsw_name = sc->sc_dev.dv_xname; - sc->sc_smpsw.smpsw_type = SMPSW_TYPE_LID; + sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_LID; if (sysmon_pswitch_register(&sc->sc_smpsw) != 0) { printf("%s: unable to register with sysmon\n", sc->sc_dev.dv_xname); @@ -135,7 +135,7 @@ acpilid_status_changed(void *arg) return; sysmon_pswitch_event(&sc->sc_smpsw, status == 0 ? - SMPSW_EVENT_PRESSED : SMPSW_EVENT_RELEASED); + PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED); } /* diff --git a/sys/dev/sysmon/sysmon.c b/sys/dev/sysmon/sysmon.c index e98ee255e5e3..bc5e3ca7ee7e 100644 --- a/sys/dev/sysmon/sysmon.c +++ b/sys/dev/sysmon/sysmon.c @@ -1,4 +1,4 @@ -/* $NetBSD: sysmon.c,v 1.7 2002/10/23 09:13:57 jdolecek Exp $ */ +/* $NetBSD: sysmon.c,v 1.8 2003/04/18 01:31:35 thorpej Exp $ */ /*- * Copyright (c) 2000 Zembu Labs, Inc. @@ -35,11 +35,11 @@ /* * Clearing house for system monitoring hardware. We currently - * handle environmental sensors and watchdog timers. + * handle environmental sensors, watchdog timers, and power management. */ #include -__KERNEL_RCSID(0, "$NetBSD: sysmon.c,v 1.7 2002/10/23 09:13:57 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sysmon.c,v 1.8 2003/04/18 01:31:35 thorpej Exp $"); #include #include @@ -57,10 +57,13 @@ __KERNEL_RCSID(0, "$NetBSD: sysmon.c,v 1.7 2002/10/23 09:13:57 jdolecek Exp $"); dev_type_open(sysmonopen); dev_type_close(sysmonclose); dev_type_ioctl(sysmonioctl); +dev_type_read(sysmonread); +dev_type_poll(sysmonpoll); +dev_type_kqfilter(sysmonkqfilter); const struct cdevsw sysmon_cdevsw = { - sysmonopen, sysmonclose, noread, nowrite, sysmonioctl, - nostop, notty, nopoll, nommap, nokqfilter, + sysmonopen, sysmonclose, sysmonread, nowrite, sysmonioctl, + nostop, notty, sysmonpoll, nommap, sysmonkqfilter, }; /* @@ -83,6 +86,11 @@ sysmonopen(dev_t dev, int flag, int mode, struct proc *p) case SYSMON_MINOR_WDOG: error = sysmonopen_wdog(dev, flag, mode, p); break; +#endif +#if NSYSMON_POWER > 0 + case SYSMON_MINOR_POWER: + error = sysmonopen_power(dev, flag, mode, p); + break; #endif default: error = ENODEV; @@ -111,6 +119,11 @@ sysmonclose(dev_t dev, int flag, int mode, struct proc *p) case SYSMON_MINOR_WDOG: error = sysmonclose_wdog(dev, flag, mode, p); break; +#endif +#if NSYSMON_POWER > 0 + case SYSMON_MINOR_POWER: + error = sysmonclose_power(dev, flag, mode, p); + break; #endif default: error = ENODEV; @@ -139,6 +152,11 @@ sysmonioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) case SYSMON_MINOR_WDOG: error = sysmonioctl_wdog(dev, cmd, data, flag, p); break; +#endif +#if NSYSMON_POWER > 0 + case SYSMON_MINOR_POWER: + error = sysmonioctl_power(dev, cmd, data, flag, p); + break; #endif default: error = ENODEV; @@ -146,3 +164,72 @@ sysmonioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) return (error); } + +/* + * sysmonread: + * + * Perform a read request. + */ +int +sysmonread(dev_t dev, struct uio *uio, int flags) +{ + int error; + + switch (minor(dev)) { +#if NSYSMON_POWER > 0 + case SYSMON_MINOR_POWER: + error = sysmonread_power(dev, uio, flags); + break; +#endif + default: + error = ENODEV; + } + + return (error); +} + +/* + * sysmonpoll: + * + * Poll the system monitor device. + */ +int +sysmonpoll(dev_t dev, int events, struct proc *p) +{ + int rv; + + switch (minor(dev)) { +#if NSYSMON_POWER > 0 + case SYSMON_MINOR_POWER: + rv = sysmonpoll_power(dev, events, p); + break; +#endif + default: + rv = events; + } + + return (rv); +} + +/* + * sysmonkqfilter: + * + * Kqueue filter for the system monitor device. + */ +int +sysmonkqfilter(dev_t dev, struct knote *kn) +{ + int error; + + switch (minor(dev)) { +#if NSYSMON_POWER > 0 + case SYSMON_MINOR_POWER: + error = sysmonkqfilter_power(dev, kn); + break; +#endif + default: + error = 1; + } + + return (error); +} diff --git a/sys/dev/sysmon/sysmon_power.c b/sys/dev/sysmon/sysmon_power.c index 7eceae583626..57501b73b91d 100644 --- a/sys/dev/sysmon/sysmon_power.c +++ b/sys/dev/sysmon/sysmon_power.c @@ -1,4 +1,4 @@ -/* $NetBSD: sysmon_power.c,v 1.1 2003/04/17 01:02:21 thorpej Exp $ */ +/* $NetBSD: sysmon_power.c,v 1.2 2003/04/18 01:31:35 thorpej Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. @@ -46,6 +46,9 @@ #include #include #include +#include +#include +#include #include @@ -56,6 +59,300 @@ static struct simplelock sysmon_pswitch_list_slock = static struct proc *sysmon_power_daemon; +#define SYSMON_MAX_POWER_EVENTS 32 + +static struct simplelock sysmon_power_event_queue_slock = + SIMPLELOCK_INITIALIZER; +static power_event_t sysmon_power_event_queue[SYSMON_MAX_POWER_EVENTS]; +static int sysmon_power_event_queue_head; +static int sysmon_power_event_queue_tail; +static int sysmon_power_event_queue_count; +static int sysmon_power_event_queue_flags; +static struct selinfo sysmon_power_event_queue_selinfo; + +static char sysmon_power_type[32]; + +#define PEVQ_F_WAITING 0x01 /* daemon waiting for event */ + +#define SYSMON_NEXT_EVENT(x) (((x) + 1) / SYSMON_MAX_POWER_EVENTS) + +/* + * sysmon_queue_power_event: + * + * Enqueue a power event for the power mangement daemon. Returns + * non-zero if we were able to enqueue a power event. + */ +static int +sysmon_queue_power_event(power_event_t *pev) +{ + + LOCK_ASSERT(simple_lock_held(&sysmon_power_event_queue_slock)); + + if (sysmon_power_event_queue_count == SYSMON_MAX_POWER_EVENTS) + return (0); + + sysmon_power_event_queue[sysmon_power_event_queue_head] = *pev; + sysmon_power_event_queue_head = + SYSMON_NEXT_EVENT(sysmon_power_event_queue_head); + sysmon_power_event_queue_count++; + + if (sysmon_power_event_queue_flags & PEVQ_F_WAITING) { + sysmon_power_event_queue_flags &= ~PEVQ_F_WAITING; + wakeup(&sysmon_power_event_queue_count); + } + selnotify(&sysmon_power_event_queue_selinfo, 0); + + return (1); +} + +/* + * sysmon_get_power_event: + * + * Get a power event from the queue. Returns non-zero if there + * is an event available. + */ +static int +sysmon_get_power_event(power_event_t *pev) +{ + + LOCK_ASSERT(simple_lock_held(&sysmon_power_event_queue_slock)); + + if (sysmon_power_event_queue_count == 0) + return (0); + + *pev = sysmon_power_event_queue[sysmon_power_event_queue_tail]; + sysmon_power_event_queue_tail = + SYSMON_NEXT_EVENT(sysmon_power_event_queue_tail); + sysmon_power_event_queue_count--; + + return (1); +} + +/* + * sysmon_power_event_queue_flush: + * + * Flush the event queue, and reset all state. + */ +static void +sysmon_power_event_queue_flush(void) +{ + + sysmon_power_event_queue_head = 0; + sysmon_power_event_queue_tail = 0; + sysmon_power_event_queue_count = 0; + sysmon_power_event_queue_flags = 0; +} + +/* + * sysmonopen_power: + * + * Open the system monitor device. + */ +int +sysmonopen_power(dev_t dev, int flag, int mode, struct proc *p) +{ + int error = 0; + + simple_lock(&sysmon_power_event_queue_slock); + if (sysmon_power_daemon != NULL) + error = EBUSY; + else { + sysmon_power_daemon = p; + sysmon_power_event_queue_flush(); + } + simple_unlock(&sysmon_power_event_queue_slock); + + return (error); +} + +/* + * sysmonclose_power: + * + * Close the system monitor device. + */ +int +sysmonclose_power(dev_t dev, int flag, int mode, struct proc *p) +{ + int count; + + simple_lock(&sysmon_power_event_queue_slock); + count = sysmon_power_event_queue_count; + sysmon_power_daemon = NULL; + sysmon_power_event_queue_flush(); + simple_unlock(&sysmon_power_event_queue_slock); + + if (count) + printf("WARNING: %d power events lost by exiting daemon\n", + count); + + return (0); +} + +/* + * sysmonread_power: + * + * Read the system monitor device. + */ +int +sysmonread_power(dev_t dev, struct uio *uio, int flags) +{ + power_event_t pev; + int error; + + /* We only allow one event to be read at a time. */ + if (uio->uio_resid != POWER_EVENT_MSG_SIZE) + return (EINVAL); + + simple_lock(&sysmon_power_event_queue_slock); + again: + if (sysmon_get_power_event(&pev)) { + simple_unlock(&sysmon_power_event_queue_slock); + return (uiomove(&pev, POWER_EVENT_MSG_SIZE, uio)); + } + + if (flags & IO_NDELAY) { + simple_unlock(&sysmon_power_event_queue_slock); + return (EWOULDBLOCK); + } + + sysmon_power_event_queue_flags |= PEVQ_F_WAITING; + error = ltsleep(&sysmon_power_event_queue_count, + PRIBIO|PCATCH, "smpower", 0, &sysmon_power_event_queue_slock); + if (error) { + simple_unlock(&sysmon_power_event_queue_slock); + return (error); + } + goto again; +} + +/* + * sysmonpoll_power: + * + * Poll the system monitor device. + */ +int +sysmonpoll_power(dev_t dev, int events, struct proc *p) +{ + int revents; + + revents = events & (POLLOUT | POLLWRNORM); + + /* Attempt to save some work. */ + if ((events & (POLLIN | POLLRDNORM)) == 0) + return (revents); + + simple_lock(&sysmon_power_event_queue_slock); + if (sysmon_power_event_queue_count) + revents |= events & (POLLIN | POLLRDNORM); + else + selrecord(p, &sysmon_power_event_queue_selinfo); + simple_unlock(&sysmon_power_event_queue_slock); + + return (revents); +} + +static void +filt_sysmon_power_rdetach(struct knote *kn) +{ + + simple_lock(&sysmon_power_event_queue_slock); + SLIST_REMOVE(&sysmon_power_event_queue_selinfo.sel_klist, + kn, knote, kn_selnext); + simple_unlock(&sysmon_power_event_queue_slock); +} + +static int +filt_sysmon_power_read(struct knote *kn, long hint) +{ + + simple_lock(&sysmon_power_event_queue_slock); + kn->kn_data = sysmon_power_event_queue_count; + simple_unlock(&sysmon_power_event_queue_slock); + + return (kn->kn_data > 0); +} + +static const struct filterops sysmon_power_read_filtops = + { 1, NULL, filt_sysmon_power_rdetach, filt_sysmon_power_read }; + +static const struct filterops sysmon_power_write_filtops = + { 1, NULL, filt_sysmon_power_rdetach, filt_seltrue }; + +/* + * sysmonkqfilter_power: + * + * Kqueue filter for the system monitor device. + */ +int +sysmonkqfilter_power(dev_t dev, struct knote *kn) +{ + struct klist *klist; + + switch (kn->kn_filter) { + case EVFILT_READ: + klist = &sysmon_power_event_queue_selinfo.sel_klist; + kn->kn_fop = &sysmon_power_read_filtops; + break; + + case EVFILT_WRITE: + klist = &sysmon_power_event_queue_selinfo.sel_klist; + kn->kn_fop = &sysmon_power_write_filtops; + break; + + default: + return (1); + } + + simple_lock(&sysmon_power_event_queue_slock); + SLIST_INSERT_HEAD(klist, kn, kn_selnext); + simple_unlock(&sysmon_power_event_queue_slock); + + return (0); +} + +/* + * sysmonioctl_power: + * + * Perform a power managmenet control request. + */ +int +sysmonioctl_power(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + int error = 0; + + switch (cmd) { + case POWER_IOC_GET_TYPE: + { + struct power_type *power_type = (void *) data; + + strcpy(power_type->power_type, sysmon_power_type); + break; + } + default: + error = ENOTTY; + } + + return (error); +} + +/* + * sysmon_power_settype: + * + * Sets the back-end power management type. This information can + * be used by the power management daemon. + */ +void +sysmon_power_settype(const char *type) +{ + + /* + * Don't bother locking this; it's going to be set + * during autoconfiguration, and then only read from + * then on. + */ + strcpy(sysmon_power_type, type); +} + /* * sysmon_pswitch_register: * @@ -100,14 +397,29 @@ sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event) * deliver the event to them. If not, we need to try to * do something reasonable ourselves. */ + simple_lock(&sysmon_power_event_queue_slock); if (sysmon_power_daemon != NULL) { - /* XXX */ + power_event_t pev; + int rv; + + pev.pev_type = POWER_EVENT_SWITCH_STATE_CHANGE; + pev.pev_switch.psws_state = event; + pev.pev_switch.psws_type = smpsw->smpsw_type; + strcpy(pev.pev_switch.psws_name, smpsw->smpsw_name); + + rv = sysmon_queue_power_event(&pev); + simple_unlock(&sysmon_power_event_queue_slock); + if (rv == 0) + printf("%s: WARNING: state change event lost; " + "queue full\n", smpsw->smpsw_name, + pev.pev_type); return; } + simple_unlock(&sysmon_power_event_queue_slock); switch (smpsw->smpsw_type) { - case SMPSW_TYPE_POWER: - if (event != SMPSW_EVENT_PRESSED) { + case PSWITCH_TYPE_POWER: + if (event != PSWITCH_EVENT_PRESSED) { /* just ignore it */ return; } @@ -122,8 +434,8 @@ sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event) cpu_reboot(RB_POWERDOWN, NULL); break; - case SMPSW_TYPE_SLEEP: - if (event != SMPSW_EVENT_PRESSED) { + case PSWITCH_TYPE_SLEEP: + if (event != PSWITCH_EVENT_PRESSED) { /* just ignore it */ return; } @@ -135,9 +447,9 @@ sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event) printf("%s: sleep button pressed.\n", smpsw->smpsw_name); break; - case SMPSW_TYPE_LID: + case PSWITCH_TYPE_LID: switch (event) { - case SMPSW_EVENT_PRESSED: + case PSWITCH_EVENT_PRESSED: /* * Try to enter a "standby" state. */ @@ -145,7 +457,7 @@ sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event) printf("%s: lid closed.\n", smpsw->smpsw_name); break; - case SMPSW_EVENT_RELEASED: + case PSWITCH_EVENT_RELEASED: /* * Come out of "standby" state. */ diff --git a/sys/dev/sysmon/sysmonconf.h b/sys/dev/sysmon/sysmonconf.h index 471f04f242d1..f9d4a57608b5 100644 --- a/sys/dev/sysmon/sysmonconf.h +++ b/sys/dev/sysmon/sysmonconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: sysmonconf.h,v 1.2 2002/12/31 22:47:48 thorpej Exp $ */ +/* $NetBSD: sysmonconf.h,v 1.3 2003/04/18 01:31:35 thorpej Exp $ */ /*- * Copyright (c) 2000 Zembu Labs, Inc. @@ -38,5 +38,6 @@ #include "sysmon_envsys.h" #include "sysmon_wdog.h" +#include "sysmon_power.h" #endif /* _DEV_SYSMON_SYSMONCONF_H_ */ diff --git a/sys/dev/sysmon/sysmonvar.h b/sys/dev/sysmon/sysmonvar.h index abf915cfc5ca..539b741f9f8b 100644 --- a/sys/dev/sysmon/sysmonvar.h +++ b/sys/dev/sysmon/sysmonvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: sysmonvar.h,v 1.5 2003/04/17 01:02:21 thorpej Exp $ */ +/* $NetBSD: sysmonvar.h,v 1.6 2003/04/18 01:31:35 thorpej Exp $ */ /*- * Copyright (c) 2000 Zembu Labs, Inc. @@ -38,12 +38,16 @@ #include #include +#include #include struct proc; +struct knote; +struct uio; #define SYSMON_MINOR_ENVSYS 0 #define SYSMON_MINOR_WDOG 1 +#define SYSMON_MINOR_POWER 2 /***************************************************************************** * Environmental sensor support @@ -112,12 +116,14 @@ struct sysmon_pswitch { LIST_ENTRY(sysmon_pswitch) smpsw_list; }; -#define SMPSW_TYPE_POWER 0 /* power button */ -#define SMPSW_TYPE_SLEEP 1 /* sleep button */ -#define SMPSW_TYPE_LID 2 /* lid switch */ +int sysmonopen_power(dev_t, int, int, struct proc *); +int sysmonclose_power(dev_t, int, int, struct proc *); +int sysmonread_power(dev_t, struct uio *, int); +int sysmonpoll_power(dev_t, int, struct proc *); +int sysmonkqfilter_power(dev_t, struct knote *); +int sysmonioctl_power(dev_t, u_long, caddr_t, int, struct proc *); -#define SMPSW_EVENT_PRESSED 0 /* button pressed/lid closed */ -#define SMPSW_EVENT_RELEASED 1 /* button released/lid opened */ +void sysmon_power_settype(const char *); int sysmon_pswitch_register(struct sysmon_pswitch *); void sysmon_pswitch_unregister(struct sysmon_pswitch *); diff --git a/sys/sys/Makefile b/sys/sys/Makefile index 7903572a5c7a..8c30185409ff 100644 --- a/sys/sys/Makefile +++ b/sys/sys/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.53 2003/03/10 07:55:14 lukem Exp $ +# $NetBSD: Makefile,v 1.54 2003/04/18 01:31:35 thorpej Exp $ INCSDIR= /usr/include/sys @@ -18,7 +18,7 @@ INCS= acct.h agpio.h ansi.h ataio.h audioio.h \ malloc.h mallocvar.h mbuf.h md4.h \ md5.h midiio.h mman.h mount.h msg.h msgbuf.h mtio.h \ namei.h null.h \ - param.h pipe.h pmc.h poll.h pool.h proc.h properties.h \ + param.h pipe.h pmc.h poll.h pool.h power.h proc.h properties.h \ protosw.h ptrace.h queue.h \ ras.h reboot.h radioio.h resource.h resourcevar.h rnd.h \ sa.h scanio.h sched.h scsiio.h select.h sem.h sha1.h shm.h \ diff --git a/sys/sys/power.h b/sys/sys/power.h new file mode 100644 index 000000000000..e8f248e3e439 --- /dev/null +++ b/sys/sys/power.h @@ -0,0 +1,134 @@ +/* $NetBSD: power.h,v 1.1 2003/04/18 01:31:35 thorpej Exp $ */ + +/* + * Copyright (c) 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Definitions for power management. + */ + +#ifndef _SYS_POWER_H_ +#define _SYS_POWER_H_ + +#include + +/* + * Power Switches: + * + * Power switches are devices on the system that are used by the system + * operator to cause certain types of power management events to happen. + * This may be the closing of a laptop lid, the pressing of a power button, + * or some other type of user-initiated hardware event. + * + * We define the following types of power switches: + * + * Power button This is the "on/off" button on a system, + * or another button which provides a similar + * function. If there is no power management + * daemon present, an event on this button will + * cause a semi-graceful shutdown of the system + * to occur. This kind of button doesn't keep + * state; we only know (care) if an event occurrs. + * + * Sleep button This is a button which is dedicated to a + * "sleep" function. This kind of button doesn't + * keep state; we only know (care) if an event + * occurs. + * + * Lid switch This is e.g. the lid of a laptop. This kind + * of switch has state. We know if it is open + * or closed. + */ + +#define PSWITCH_TYPE_POWER 0 /* power button */ +#define PSWITCH_TYPE_SLEEP 1 /* sleep button */ +#define PSWITCH_TYPE_LID 2 /* lid switch */ + +#define PSWITCH_EVENT_PRESSED 0 /* button pressed */ +#define PSWITCH_EVENT_RELEASED 1 /* button released */ + +#define PSWITCH_STATE_PRESSED 0 /* button pressed/lid closed */ +#define PSWITCH_STATE_RELEASED 1 /* button released/lid open */ +#define PSWITCH_STATE_UNKNOWN -1 + +/* + * This structure describes the state of a power switch. It is used + * by the POWER_IOC_GET_SWSTATE ioctl, as well as in power mangement + * event messages. + */ +struct pswitch_state { + char psws_name[16]; /* power switch name */ + int32_t psws_type; /* type of switch (qualifier) */ + int32_t psws_state; /* state of the switch/event */ +}; + +/* + * Power management event messages: + * + * We ensure that a message is always exactly 32 bytes long, so that + * userland doesn't need to issue multiple reads to get a single event. + */ +#define POWER_EVENT_MSG_SIZE 32 + +#define POWER_EVENT_SWITCH_STATE_CHANGE 0 + +typedef struct { + int32_t pev_type; /* power event type */ + union { + int32_t _pev_d_space[(POWER_EVENT_MSG_SIZE / + sizeof(int32_t)) - 1]; + + /* + * This field is used for: + * + * POWER_EVENT_SWITCH_STATE_CHANGE + */ + struct pswitch_state _pev_d_switch; + } _pev_data; +} power_event_t; + +#define pev_switch _pev_data._pev_d_switch + +/* + * POWER_IOC_GET_TYPE: + * + * Get the power management back-end type. + */ +struct power_type { + char power_type[32]; +}; +#define POWER_IOC_GET_TYPE _IOR('P', 0, sizeof(struct power_type)) + +#endif /* _SYS_POWER_H_ */