summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2000-02-21 17:09:09 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2000-02-21 17:09:09 +0000
commit021c7d76099397dc741ceddd3927981f3b13b7b7 (patch)
treebf059b1b4d85246b4ad2d5e874c28633d88963df /sys
parentec50561cbc3916c5a415a251577c7ba50ca1da6e (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.i3863
-rw-r--r--sys/arch/i386/i386/apm.c168
-rw-r--r--sys/arch/i386/i386/apmcall.S110
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(&regs) == 0 && !apm_error)
- apm_event_handle(sc, &regs);
+ apm_handle_event(sc, &regs);
- if (APM_ERR_CODE(&regs) != APM_ERR_NOEVENTS)
+ /* i think some bioses actually combine the error codes */
+ if (!(APM_ERR_CODE(&regs) & APM_ERR_NOEVENTS))
apm_perror("get event", &regs);
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", &regs);
#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(&regs) == 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