diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sparc/dev/tctrl.c | 340 | ||||
-rw-r--r-- | sys/arch/sparc/dev/ts102reg.h | 3 | ||||
-rw-r--r-- | sys/arch/sparc/include/apmvar.h | 124 | ||||
-rw-r--r-- | sys/arch/sparc/include/conf.h | 10 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/conf.c | 6 |
5 files changed, 472 insertions, 11 deletions
diff --git a/sys/arch/sparc/dev/tctrl.c b/sys/arch/sparc/dev/tctrl.c index 6409aaca8c7..3f76cf2660c 100644 --- a/sys/arch/sparc/dev/tctrl.c +++ b/sys/arch/sparc/dev/tctrl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tctrl.c,v 1.9 2005/03/29 12:55:55 miod Exp $ */ +/* $OpenBSD: tctrl.c,v 1.10 2005/03/29 16:26:44 miod Exp $ */ /* $NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt Exp $ */ /*- @@ -36,20 +36,75 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/* + * The /dev/apm{,ctl} interface code falls under the following license + * terms: + * + * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved. + * Copyright (c) 1995 John T. Kohl. All rights reserved. + * + * 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 by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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 MIND, 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. + */ #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/device.h> +#include <sys/event.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/proc.h> #include <sys/timeout.h> +#include <machine/apmvar.h> #include <machine/autoconf.h> +#include <machine/conf.h> #include <machine/cpu.h> #include <sparc/dev/ts102reg.h> #include <sparc/dev/tctrlvar.h> +/* + * Flags to control kernel display + * SCFLAG_NOPRINT: do not output APM power messages due to + * a power change event. + * + * SCFLAG_PCTPRINT: do not output APM power messages due to + * to a power change event unless the battery + * percentage changes. + */ + +#define SCFLAG_NOPRINT 0x0008000 +#define SCFLAG_PCTPRINT 0x0004000 +#define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT) + const char *tctrl_ext_statuses[16] = { "main power available", "internal battery attached", @@ -96,6 +151,10 @@ struct tctrl_softc { u_int sc_bellvol; struct timeout sc_tmo; + + /* /dev/apm{,ctl} fields */ + struct klist sc_note; + u_int sc_apmflags; }; int tctrl_match(struct device *, void *, void *); @@ -113,6 +172,8 @@ void tctrl_request(struct tctrl_softc *, struct tctrl_req *); void tctrl_tft(struct tctrl_softc *); void tctrl_write_data(struct tctrl_softc *, u_int8_t); +int apm_record_event(struct tctrl_softc *, u_int); + struct cfattach tctrl_ca = { sizeof(struct tctrl_softc), tctrl_match, tctrl_attach }; @@ -425,17 +486,23 @@ tctrl_read_event_status(void *arg) #ifdef TCTRLDEBUG /* Obviously status change */ if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { - printf("%s: Battery level change\n", sc->sc_dev.dv_xname); + if (sc->sc_apmflags & SCFLAG_PCTPRINT) + printf("%s: Battery level change\n", + sc->sc_dev.dv_xname); } #endif if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { - printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); + if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0) + printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); + apm_record_event(sc, APM_BATTERY_LOW); } if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { tctrl_read_ext_status(sc); - printf("%s: main power %s\n", sc->sc_dev.dv_xname, - (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? - "restored" : "removed"); + if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0) + printf("%s: main power %s\n", sc->sc_dev.dv_xname, + (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? + "restored" : "removed"); + apm_record_event(sc, APM_POWER_CHANGE); #if 0 /* automatically done for us */ tctrl_lcd(sc, ~TS102_LCD_DC_OK, sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE ? @@ -788,3 +855,264 @@ tadpole_bell(u_int duration, u_int freq, u_int volume) return (1); } + +/* + * /dev/apm{,ctl} interface code + */ + +#define APMUNIT(dev) (minor(dev)&0xf0) +#define APMDEV(dev) (minor(dev)&0x0f) +#define APMDEV_NORMAL 0 +#define APMDEV_CTL 8 + +int apmkqfilter(dev_t dev, struct knote *kn); +void filt_apmrdetach(struct knote *kn); +int filt_apmread(struct knote *kn, long hint); + +struct filterops apmread_filtops = + { 1, NULL, filt_apmrdetach, filt_apmread}; + +#define SCFLAG_OREAD (1 << 0) +#define SCFLAG_OWRITE (1 << 1) +#define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE) + +int +apmopen(dev_t dev, int flag, int mode, struct proc *p) +{ + struct tctrl_softc *sc; + int error = 0; + + if (tctrl_cd.cd_devs == NULL + || tctrl_cd.cd_ndevs == 0 + || tctrl_cd.cd_devs[0] == NULL) { + return (ENXIO); + } + + /* apm0 only */ + if (APMUNIT(dev) != 0) + return (ENODEV); + + sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0]; + + switch (APMDEV(dev)) { + case APMDEV_CTL: + if (!(flag & FWRITE)) { + error = EINVAL; + break; + } + if (sc->sc_apmflags & SCFLAG_OWRITE) { + error = EBUSY; + break; + } + sc->sc_apmflags |= SCFLAG_OWRITE; + break; + case APMDEV_NORMAL: + if (!(flag & FREAD) || (flag & FWRITE)) { + error = EINVAL; + break; + } + sc->sc_apmflags |= SCFLAG_OREAD; + break; + default: + error = ENXIO; + break; + } + return (error); +} + +int +apmclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct tctrl_softc *sc; + + if (tctrl_cd.cd_devs == NULL + || tctrl_cd.cd_ndevs == 0 + || tctrl_cd.cd_devs[0] == NULL) { + return (ENXIO); + } + + /* apm0 only */ + if (APMUNIT(dev) != 0) + return (ENODEV); + + sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0]; + + switch (APMDEV(dev)) { + case APMDEV_CTL: + sc->sc_apmflags &= ~SCFLAG_OWRITE; + break; + case APMDEV_NORMAL: + sc->sc_apmflags &= ~SCFLAG_OREAD; + break; + } + return (0); +} + +int +apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct tctrl_softc *sc; + struct tctrl_req req; + struct apm_power_info *power; + u_int8_t c; + int error = 0; + + if (tctrl_cd.cd_devs == NULL + || tctrl_cd.cd_ndevs == 0 + || tctrl_cd.cd_devs[0] == NULL) { + return (ENXIO); + } + + /* apm0 only */ + if (APMUNIT(dev) != 0) + return (ENODEV); + + sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0]; + + switch (cmd) { + /* some ioctl names from linux */ + case APM_IOC_STANDBY: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + case APM_IOC_SUSPEND: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + case APM_IOC_PRN_CTL: + if ((flag & FWRITE) == 0) + error = EBADF; + else { + int flag = *(int *)data; + switch (flag) { + case APM_PRINT_ON: /* enable printing */ + sc->sc_apmflags &= ~SCFLAG_PRINT; + break; + case APM_PRINT_OFF: /* disable printing */ + sc->sc_apmflags &= ~SCFLAG_PRINT; + sc->sc_apmflags |= SCFLAG_NOPRINT; + break; + case APM_PRINT_PCT: /* disable some printing */ + sc->sc_apmflags &= ~SCFLAG_PRINT; + sc->sc_apmflags |= SCFLAG_PCTPRINT; + break; + default: + error = EINVAL; + break; + } + } + break; + case APM_IOC_GETPOWER: + power = (struct apm_power_info *)data; + + req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE; + req.cmdlen = 1; + req.rsplen = 2; + tctrl_request(sc, &req); + if (req.rspbuf[0] != 0) + power->battery_state = APM_BATT_CHARGING; + else + power->battery_state = APM_BATT_UNKNOWN; + + req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL; + req.cmdlen = 1; + req.rsplen = 3; + tctrl_request(sc, &req); + + c = req.rspbuf[0]; + if (c == TS102_CHARGE_UNKNOWN) + c = 0; + power->battery_life = c; + power->minutes_left = (u_int)-1; /* unknown */ + if (power->battery_state != APM_BATT_CHARGING) { + if (c < 0x20) + power->battery_state = APM_BATT_CRITICAL; + else if (c < 0x40) + power->battery_state = APM_BATT_HIGH; + else if (c < 0x66) + power->battery_state = APM_BATT_HIGH; + } + +#if 0 + tctrl_read_ext_status(sc); +#endif + if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) + power->ac_state = APM_AC_ON; + else + power->ac_state = APM_AC_OFF; + break; + + default: + error = ENOTTY; + } + + return (error); +} + +int +apm_record_event(struct tctrl_softc *sc, u_int type) +{ + static int apm_evindex; + + /* skip if no user waiting */ + if ((sc->sc_apmflags & SCFLAG_OPEN) == 0) + return (1); + + apm_evindex++; + KNOTE(&sc->sc_note, APM_EVENT_COMPOSE(type, apm_evindex)); + + return (0); +} + +void +filt_apmrdetach(struct knote *kn) +{ + struct tctrl_softc *sc = (struct tctrl_softc *)kn->kn_hook; + + SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext); +} + +int +filt_apmread(struct knote *kn, long hint) +{ + /* XXX weird kqueue_scan() semantics */ + if (hint && !kn->kn_data) + kn->kn_data = (int)hint; + + return (1); +} + +int +apmkqfilter(dev_t dev, struct knote *kn) +{ + struct tctrl_softc *sc; + + if (tctrl_cd.cd_devs == NULL + || tctrl_cd.cd_ndevs == 0 + || tctrl_cd.cd_devs[0] == NULL) { + return (ENXIO); + } + + /* apm0 only */ + if (APMUNIT(dev) != 0) + return (ENODEV); + + sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0]; + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &apmread_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)sc; + SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext); + + return (0); +} diff --git a/sys/arch/sparc/dev/ts102reg.h b/sys/arch/sparc/dev/ts102reg.h index e03b6954214..e42a2ecf4e0 100644 --- a/sys/arch/sparc/dev/ts102reg.h +++ b/sys/arch/sparc/dev/ts102reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ts102reg.h,v 1.3 2003/06/18 17:50:23 miod Exp $ */ +/* $OpenBSD: ts102reg.h,v 1.4 2005/03/29 16:26:44 miod Exp $ */ /* $NetBSD: ts102reg.h,v 1.7 2002/09/29 23:23:58 wiz Exp $ */ /*- @@ -348,6 +348,7 @@ enum ts102_opcode { /* Argument Returned */ TS102_OP_ADMIN_VRFY_SYSTEM_PASS=0x73, /* len <pass> ack + status */ TS102_OP_RD_INT_CHARGE_LEVEL=0x7a, /* ack + 2 byte */ TS102_OP_RD_EXT_CHARGE_LEVEL=0x7b, /* ack + 2 byte */ +#define TS102_CHARGE_UNKNOWN 0xfa TS102_OP_SLEEP=0x80, /* supposedly sleeps, not sure */ TS102_OP_ADMIN_POWER_OFF=0x82, /* len <pass> none */ TS102_OP_ADMIN_POWER_RESTART=0x83, /* msb,xx,lsb none */ diff --git a/sys/arch/sparc/include/apmvar.h b/sys/arch/sparc/include/apmvar.h new file mode 100644 index 00000000000..44404357b8f --- /dev/null +++ b/sys/arch/sparc/include/apmvar.h @@ -0,0 +1,124 @@ +/* $OpenBSD: apmvar.h,v 1.1 2005/03/29 16:26:44 miod Exp $ */ + +/* + * Copyright (c) 1995 John T. Kohl + * All rights reserved. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 THE AUTHOR 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. + * + */ +#ifndef _MACHINE_APMVAR_H_ +#define _MACHINE_APMVAR_H_ + +#include <sys/ioccom.h> + +/* + * This is a subset of the Advanced Power Management (v1.0 and v1.1 + * specification) functions/defines/etc, covering the abilities of + * the tctrl driver. + */ + +#define APM_POWER_STATUS 0x530a +#define APM_AC_OFF 0x00 +#define APM_AC_ON 0x01 +#define APM_AC_BACKUP 0x02 +#define APM_AC_UNKNOWN 0xff +#define APM_BATT_HIGH 0x00 +#define APM_BATT_LOW 0x01 +#define APM_BATT_CRITICAL 0x02 +#define APM_BATT_CHARGING 0x03 +#define APM_BATT_UNKNOWN 0xff +#define APM_BATT_FLAG_HIGH 0x01 +#define APM_BATT_FLAG_LOW 0x02 +#define APM_BATT_FLAG_CRITICAL 0x04 +#define APM_BATT_FLAG_CHARGING 0x08 +#define APM_BATT_FLAG_NOBATTERY 0x10 +#define APM_BATT_FLAG_NOSYSBATT 0x80 +#define APM_BATT_LIFE_UNKNOWN 0xff + +#define APM_GET_PM_EVENT 0x530b +#define APM_NOEVENT 0x0000 +#define APM_STANDBY_REQ 0x0001 /* %bx on return */ +#define APM_SUSPEND_REQ 0x0002 +#define APM_NORMAL_RESUME 0x0003 +#define APM_CRIT_RESUME 0x0004 /* suspend/resume happened + without us */ +#define APM_BATTERY_LOW 0x0005 +#define APM_POWER_CHANGE 0x0006 +#define APM_UPDATE_TIME 0x0007 +#define APM_CRIT_SUSPEND_REQ 0x0008 +#define APM_USER_STANDBY_REQ 0x0009 +#define APM_USER_SUSPEND_REQ 0x000A +#define APM_SYS_STANDBY_RESUME 0x000B +#define APM_CAPABILITY_CHANGE 0x000C /* apm v1.2 */ + +#define APM_EVENT_MASK 0xffff + +#define APM_EVENT_COMPOSE(t,i) ((((i) & 0x7fff) << 16)|((t) & APM_EVENT_MASK)) +#define APM_EVENT_TYPE(e) ((e) & APM_EVENT_MASK) +#define APM_EVENT_INDEX(e) ((e) >> 16) + +#define APM_GET_POWER_STATE 0x530c + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#define APM_BATTERY_ABSENT 4 + +struct apm_power_info { + u_char battery_state; + u_char ac_state; + u_char battery_life; + u_char spare1; + u_int minutes_left; /* estimate */ + u_int spare2[6]; +}; + +struct apm_ctl { + u_int dev; + u_int mode; +}; + +#define APM_IOC_STANDBY _IO('A', 1) /* put system into standby */ +#define APM_IOC_SUSPEND _IO('A', 2) /* put system into suspend */ +#define APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */ +#define APM_IOC_PRN_CTL _IOW('A', 6, int) /* driver power status msg */ +#define APM_PRINT_ON 0 /* driver power status displayed */ +#define APM_PRINT_OFF 1 /* driver power status not displayed */ +#define APM_PRINT_PCT 2 /* driver power status only displayed + if the percentage changes */ + +#endif /* _MACHINE_APMVAR_H_ */ diff --git a/sys/arch/sparc/include/conf.h b/sys/arch/sparc/include/conf.h index ee7e8d4298c..ca6a9d746b3 100644 --- a/sys/arch/sparc/include/conf.h +++ b/sys/arch/sparc/include/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.18 2003/09/23 16:51:11 millert Exp $ */ +/* $OpenBSD: conf.h,v 1.19 2005/03/29 16:26:44 miod Exp $ */ /* $NetBSD: conf.h,v 1.8 1996/12/31 07:12:43 mrg Exp $ */ /* @@ -105,3 +105,11 @@ cdev_decl(fga); (dev_type_stop((*))) nullop, 0, seltrue, \ (dev_type_mmap((*))) enodev } cdev_decl(daadio); + +/* open, close, write, ioctl, kqueue */ +#define cdev_apm_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } +cdev_decl(apm); diff --git a/sys/arch/sparc/sparc/conf.c b/sys/arch/sparc/sparc/conf.c index d31d1b9ef47..b28d6eb002e 100644 --- a/sys/arch/sparc/sparc/conf.c +++ b/sys/arch/sparc/sparc/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.39 2004/02/10 01:31:21 millert Exp $ */ +/* $OpenBSD: conf.c,v 1.40 2005/03/29 16:26:45 miod Exp $ */ /* $NetBSD: conf.c,v 1.40 1996/04/11 19:20:03 thorpej Exp $ */ /* @@ -125,8 +125,8 @@ struct bdevsw bdevsw[] = int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]); #include "pf.h" - #include "systrace.h" +#include "tctrl.h" struct cdevsw cdevsw[] = { @@ -160,7 +160,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 27: was /dev/bwtwo */ cdev_notdef(), /* 28 */ cdev_notdef(), /* 29: was /dev/kbd */ - cdev_notdef(), /* 30 */ + cdev_apm_init(NTCTRL,apm), /* 30: tctrl APM interface */ cdev_notdef(), /* 31: was /dev/cgtwo */ cdev_notdef(), /* 32: should be /dev/gpone */ cdev_notdef(), /* 33 */ |