diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-02-21 17:09:09 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-02-21 17:09:09 +0000 |
commit | 021c7d76099397dc741ceddd3927981f3b13b7b7 (patch) | |
tree | bf059b1b4d85246b4ad2d5e874c28633d88963df /sys | |
parent | ec50561cbc3916c5a415a251577c7ba50ca1da6e (diff) |
separate assembly thing into an own file to avoid compiler-deps.
ignore suspend reqs while suspending.
ignore suspend requests for 3 seconds holdoff period once awaken.
protect event queue manipulations w/ splhigh's.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/arch/i386/i386/apm.c | 168 | ||||
-rw-r--r-- | sys/arch/i386/i386/apmcall.S | 110 |
3 files changed, 197 insertions, 84 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 85379746a39..8c17435b5cd 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.61 1999/11/20 11:18:59 matthieu Exp $ +# $OpenBSD: files.i386,v 1.62 2000/02/21 17:09:08 mickey Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -242,6 +242,7 @@ file arch/i386/i386/bios.c bios needs-count device apm attach apm at bios file arch/i386/i386/apm.c apm needs-count +file arch/i386/i386/apmcall.S apm # XXXX pcic here because it needs to be late. The catch: pcic needs # to be late, so devices which attach to it are attached late. But it diff --git a/sys/arch/i386/i386/apm.c b/sys/arch/i386/i386/apm.c index 9fc494f388f..92e7cba90b9 100644 --- a/sys/arch/i386/i386/apm.c +++ b/sys/arch/i386/i386/apm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apm.c,v 1.33 2000/02/01 01:33:45 mickey Exp $ */ +/* $OpenBSD: apm.c,v 1.34 2000/02/21 17:09:01 mickey Exp $ */ /*- * Copyright (c) 1998-2000 Michael Shalayeff. All rights reserved. @@ -81,12 +81,12 @@ void apmattach __P((struct device *, struct device *, void *)); Setting it to zero kills all warnings */ int cpu_apmwarn = 10; -#define APM_NEVENTS 16 +#define APM_NEVENTS 16 +#define APM_RESUME_HOLDOFF 3 struct apm_softc { struct device sc_dev; struct selinfo sc_rsel; - struct selinfo sc_xsel; int sc_flags; int batt_life; int event_count; @@ -126,6 +126,7 @@ struct cfdriver apm_cd = { int apm_standbys; int apm_userstandbys; int apm_suspends; +int apm_resumes; int apm_battlow; int apm_evindex; int apm_error; @@ -150,7 +151,7 @@ struct apmregs { int apmcall __P((u_int, u_int, struct apmregs *)); void apm_power_print __P((struct apm_softc *, struct apmregs *)); -void apm_event_handle __P((struct apm_softc *, struct apmregs *)); +void apm_handle_event __P((struct apm_softc *, struct apmregs *)); void apm_set_ver __P((struct apm_softc *)); void apm_periodic_check __P((void *)); /* void apm_disconnect __P((void *)); */ @@ -172,10 +173,6 @@ apm_get_event(struct apmregs *r) int rv; bzero(r, sizeof(*r)); rv = apmcall(APM_GET_PM_EVENT, 0, r); -#ifdef APMDEBUG - if (r->bx) - printf("apm_get_event: %x\n", r->bx); -#endif return rv; } @@ -330,55 +327,20 @@ apm_resume(sc, regs) struct apm_softc *sc; struct apmregs *regs; { + apm_resumes = APM_RESUME_HOLDOFF; + + /* flush the event queue */ + sc->event_count = 0; + /* they say that some machines may require reinititalizing the clock */ initrtclock(); inittodr(time.tv_sec); + /* lower bit in cx means pccard was powered down */ dopowerhooks(PWR_RESUME); apm_record_event(sc, regs->bx); } -/* - * call the APM protected mode bios function FUNCTION for BIOS selection - * WHICHBIOS. - * Fills in *regs with registers as returned by APM. - * returns nonzero if error returned by APM. - */ -int -apmcall(f, dev, r) - u_int f, dev; - struct apmregs *r; -{ - register int rv; - - /* todo: do something with %edi? */ - __asm __volatile( -#if defined(DEBUG) || defined(DIAGNOSTIC) - "pushl %%ds; pushl %%es; pushl %%fs; pushl %%gs\n\t" - "pushfl\n\t" - "xorl %0, %0\n\t" - "movl %0, %%ds\n\t" - "movl %0, %%es\n\t" - "movl %0, %%fs\n\t" - "movl %0, %%gs\n\t" -#endif - "movl %5, %%eax\n\t" - "clc\n\t" - "sti\n\t" - "lcall %%cs:(%7)\n\t" - "pushl %1; setc %b1; movzbl %b1, %0; popl %1\n\t" - -#if defined(DEBUG) || defined(DIAGNOSTIC) - "popfl; popl %%gs; popl %%fs; popl %%es; popl %%ds" -#endif - : "=r" (rv), - "=a" (r->ax), "=b" (r->bx), "+c" (r->cx), "+d" (r->dx) - : "m" (f), "2" (dev), "m" (apm_ep) - : "edi", "ebp", "cc", "memory"); - return rv; -} - - int apm_record_event(sc, event_type) struct apm_softc *sc; @@ -389,25 +351,29 @@ apm_record_event(sc, event_type) if (!apm_error && (sc->sc_flags & SCFLAG_OPEN) == 0) { DPRINTF(("apm_record_event: no user waiting\n")); apm_error++; - return 1; /* no user waiting */ + return 1; } - if (!apm_error && sc->event_count == APM_NEVENTS) { + + if (sc->event_count >= APM_NEVENTS) { DPRINTF(("apm_record_event: overflow\n")); apm_error++; - return 1; /* overflow */ + } else { + int s = splhigh(); + evp = &sc->event_list[sc->event_ptr]; + sc->event_count++; + sc->event_ptr++; + sc->event_ptr %= APM_NEVENTS; + evp->type = event_type; + evp->index = ++apm_evindex; + splx(s); } - evp = &sc->event_list[sc->event_ptr]; - sc->event_count++; - sc->event_ptr++; - sc->event_ptr %= APM_NEVENTS; - evp->type = event_type; - evp->index = ++apm_evindex; selwakeup(&sc->sc_rsel); + return (sc->sc_flags & SCFLAG_OWRITE) ? 0 : 1; /* user may handle */ } void -apm_event_handle(sc, regs) +apm_handle_event(sc, regs) struct apm_softc *sc; struct apmregs *regs; { @@ -417,40 +383,52 @@ apm_event_handle(sc, regs) switch(regs->bx) { case APM_USER_STANDBY_REQ: + if (apm_resumes || apm_op_inprog) + break; DPRINTF(("user wants STANDBY--fat chance\n")); - if (apm_record_event(sc, regs->bx)) - apm_userstandbys++; - apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); apm_op_inprog++; + if (apm_record_event(sc, regs->bx)) { + DPRINTF(("standby ourselves\n")); + apm_userstandbys++; + } break; case APM_STANDBY_REQ: + if (apm_resumes || apm_op_inprog) + break; DPRINTF(("standby requested\n")); if (apm_standbys || apm_suspends) { DPRINTF(("premature standby\n")); apm_error++; } - if (apm_record_event(sc, regs->bx)) - apm_standbys++; - apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); apm_op_inprog++; + if (apm_record_event(sc, regs->bx)) { + DPRINTF(("standby ourselves\n")); + apm_standbys++; + } break; case APM_USER_SUSPEND_REQ: + if (apm_resumes || apm_op_inprog) + break; DPRINTF(("user wants suspend--fat chance!\n")); - if (apm_record_event(sc, regs->bx)) - apm_suspends++; - apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); apm_op_inprog++; + if (apm_record_event(sc, regs->bx)) { + DPRINTF(("suspend ourselves\n")); + apm_suspends++; + } break; case APM_SUSPEND_REQ: + if (apm_resumes || apm_op_inprog) + break; DPRINTF(("suspend requested\n")); if (apm_standbys || apm_suspends) { DPRINTF(("premature suspend\n")); apm_error++; } - if (apm_record_event(sc, regs->bx)) - apm_suspends++; - apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); apm_op_inprog++; + if (apm_record_event(sc, regs->bx)) { + DPRINTF(("suspend ourselves\n")); + apm_suspends++; + } break; case APM_POWER_CHANGE: DPRINTF(("power status change\n")); @@ -478,7 +456,8 @@ apm_event_handle(sc, regs) break; case APM_UPDATE_TIME: DPRINTF(("update time, please\n")); - apm_resume(sc, regs); + inittodr(time.tv_sec); + apm_record_event(sc, regs->bx); break; case APM_CRIT_SUSPEND_REQ: DPRINTF(("suspend required immediately\n")); @@ -525,14 +504,14 @@ apm_periodic_check(arg) apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); while (apm_get_event(®s) == 0 && !apm_error) - apm_event_handle(sc, ®s); + apm_handle_event(sc, ®s); - if (APM_ERR_CODE(®s) != APM_ERR_NOEVENTS) + /* i think some bioses actually combine the error codes */ + if (!(APM_ERR_CODE(®s) & APM_ERR_NOEVENTS)) apm_perror("get event", ®s); if (apm_suspends /*|| (apm_battlow && apm_userstandbys)*/) { apm_op_inprog = 0; - /* stupid TI TM5000! */ apm_suspend(); } else if (apm_standbys || apm_userstandbys) { apm_op_inprog = 0; @@ -541,6 +520,9 @@ apm_periodic_check(arg) apm_suspends = apm_standbys = apm_battlow = apm_userstandbys = 0; apm_error = 0; + if (apm_resumes) + apm_resumes--; + timeout(apm_periodic_check, sc, hz); } @@ -678,8 +660,9 @@ apm_set_ver(self) #ifdef APMDEBUG apm_perror("set version 1.1", ®s); #endif - apm_majver = 1; - apm_minver = 0; + /* stay w/ flags then */ + apm_majver = APM_MAJOR(apm_flags); + apm_minver = APM_MINOR(apm_flags); } } printf(": Power Management spec V%d.%d", apm_majver, apm_minver); @@ -870,7 +853,10 @@ apmopen(dev, flag, mode, p) if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || !(sc = apm_cd.cd_devs[APMUNIT(dev)])) return ENXIO; - + + DPRINTF(("apmopen: dev %d pid %d flag %x mode %x\n", + APMDEV(dev), p->p_pid, flag, mode)); + switch (APMDEV(dev)) { case APMDEV_CTL: if (!(flag & FWRITE)) @@ -898,6 +884,7 @@ apmclose(dev, flag, mode, p) struct proc *p; { struct apm_softc *sc; + int s; /* apm0 only */ if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || @@ -906,6 +893,7 @@ apmclose(dev, flag, mode, p) DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode)); + s = splhigh(); switch (APMDEV(dev)) { case APMDEV_CTL: sc->sc_flags &= ~SCFLAG_OWRITE; @@ -918,6 +906,7 @@ apmclose(dev, flag, mode, p) sc->event_count = 0; sc->event_ptr = 0; } + splx(s); return 0; } @@ -935,6 +924,7 @@ apmioctl(dev, cmd, data, flag, p) struct apmregs regs; register int i; struct apm_ctl *actl; + int s; /* apm0 only */ if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || @@ -959,17 +949,21 @@ apmioctl(dev, cmd, data, flag, p) { int flag = *(int*)data; DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag )); + s = splhigh(); switch (flag) { case APM_PRINT_ON: /* enable printing */ sc->sc_flags &= ~SCFLAG_PRINT; + splx(s); return 0; case APM_PRINT_OFF: /* disable printing */ sc->sc_flags &= ~SCFLAG_PRINT; sc->sc_flags |= SCFLAG_NOPRINT; + splx(s); return 0; case APM_PRINT_PCT: /* disable some printing */ sc->sc_flags &= ~SCFLAG_PRINT; sc->sc_flags |= SCFLAG_PCTPRINT; + splx(s); return 0; default: break; @@ -990,15 +984,19 @@ apmioctl(dev, cmd, data, flag, p) } return apm_set_powstate(actl->dev, actl->mode); case APM_IOC_NEXTEVENT: + s = splhigh(); if (sc->event_count) { evp = (struct apm_event_info *)data; i = sc->event_ptr + APM_NEVENTS - sc->event_count; i %= APM_NEVENTS; *evp = sc->event_list[i]; sc->event_count--; + splx(s); return 0; - } else + } else { + splx(s); return EAGAIN; + } case APM_IOC_GETPOWER: powerp = (struct apm_power_info *)data; if (apm_get_powstat(®s) == 0) { @@ -1048,6 +1046,7 @@ apmselect(dev, rw, p) struct proc *p; { struct apm_softc *sc; + int s, ret = 0; /* apm0 only */ if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || @@ -1056,13 +1055,16 @@ apmselect(dev, rw, p) switch (rw) { case FREAD: + s = splhigh(); if (sc->event_count) - return 1; - selrecord(p, &sc->sc_rsel); + ret++; + else + selrecord(p, &sc->sc_rsel); + splx(s); break; case FWRITE: case 0: - return 0; + break; } - return 0; + return ret; } diff --git a/sys/arch/i386/i386/apmcall.S b/sys/arch/i386/i386/apmcall.S new file mode 100644 index 00000000000..8599e7d32aa --- /dev/null +++ b/sys/arch/i386/i386/apmcall.S @@ -0,0 +1,110 @@ +/* $OpenBSD: apmcall.S,v 1.1 2000/02/21 17:09:01 mickey Exp $ */ + +/* + * Copyright (c) 2000 Michael Shalayeff + * 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 Michael Shalayeff. + * 4. 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 OR HIS RELATIVES 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 <machine/asm.h> + +#ifndef APM_DISABLE_INTERRUPTS +#define APM_DISABLE_INTERRUPTS 1 +#endif /* APM_DISABLE_INTERRUPTS */ + + .data + .globl _C_LABEL(apm_ep) + .globl _C_LABEL(apm_cli) +_C_LABEL(apm_cli): + .long APM_DISABLE_INTERRUPTS +/* + * int apmcall(u_int f, int dev, struct apmregs *r) + * + */ + .text +ENTRY(apmcall) + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %esi + pushl %edi + + movl 16(%ebp), %ebx + movl 8(%ebx), %ecx + movl 12(%ebx), %edx + movl 12(%ebp), %ebx + + pushfl + + cmp $0, _C_LABEL(apm_cli) + je 1f + cli +1: +#if defined(DEBUG) || defined(DIAGNOSTIC) + pushl %ds + pushl %es + pushl %fs + pushl %gs + xorl %eax, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs +#endif + movl 8(%ebp), %eax + + clc + lcall %cs:(_C_LABEL(apm_ep)) + pushl %eax + setc %al + movzbl %al, %esi + popl %eax + +#if defined(DEBUG) || defined(DIAGNOSTIC) + popl %gs + popl %fs + popl %es + popl %ds +#endif + popfl + + movl 16(%ebp), %edi + movl %eax, 0(%edi) + movl %ebx, 4(%edi) + movl %ecx, 8(%edi) + movl %edx, 12(%edi) + + movl %esi, %eax + + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + .end |