Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-1-5]: src/sys/arch/i386/i386 Pull up revision 1.58 (via patch, re...
details: https://anonhg.NetBSD.org/src/rev/ff79bc456674
branches: netbsd-1-5
changeset: 490571:ff79bc456674
user: he <he%NetBSD.org@localhost>
date: Sat Feb 03 17:42:23 2001 +0000
description:
Pull up revision 1.58 (via patch, requested by chuck):
Fix problem detected on IBM thinkpads causing it to suspend
shortly after resume. This is caused by duplicate events filling
the event queue, so improve detection of duplicates. Also cleanup
and add some APMDEBUG code.
diffstat:
sys/arch/i386/i386/apm.c | 252 +++++++++++++++++++++++++++++++++-------------
1 files changed, 181 insertions(+), 71 deletions(-)
diffs (truncated from 381 to 300 lines):
diff -r b83221e070fa -r ff79bc456674 sys/arch/i386/i386/apm.c
--- a/sys/arch/i386/i386/apm.c Sat Feb 03 17:36:37 2001 +0000
+++ b/sys/arch/i386/i386/apm.c Sat Feb 03 17:42:23 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: apm.c,v 1.50.2.1 2000/08/04 05:34:29 enami Exp $ */
+/* $NetBSD: apm.c,v 1.50.2.2 2001/02/03 17:42:23 he Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -98,16 +98,16 @@
#else
int apmdebug = 0;
#endif
-#else
+
+#else /* APMDEBUG */
#define DPRINTF(f, x) /**/
-#endif
+#endif /* APMDEBUG */
#define APM_NEVENTS 16
struct apm_softc {
struct device sc_dev;
struct selinfo sc_rsel;
- struct selinfo sc_xsel;
int sc_flags;
int event_count;
int event_ptr;
@@ -143,7 +143,7 @@
static void apm_devpowmgt_enable __P((int, u_int));
static void apm_disconnect __P((void *));
#endif
-static void apm_event_handle __P((struct apm_softc *, struct bioscallregs *));
+static int apm_event_handle __P((struct apm_softc *, struct bioscallregs *));
static int apm_get_event __P((struct bioscallregs *));
static int apm_get_powstat __P((struct bioscallregs *));
#if 0
@@ -217,12 +217,98 @@
struct apm_connect_info apminfo;
u_char apm_majver, apm_minver;
int apm_inited;
-int apm_standbys, apm_userstandbys, apm_suspends, apm_battlow;
-int apm_damn_fool_bios, apm_op_inprog;
int apm_evindex;
+/* set if we should standby/suspend at the end of next periodic event */
+int apm_standby_now, apm_suspend_now;
+
+/*
+ * set if kernel is planning on doing a standby/suspend, or if we are
+ * waiting for an external program to process a standby/suspend event.
+ */
+int apm_standby_pending, apm_suspend_pending;
+
#ifdef APMDEBUG
int apmcall_debug(int, struct bioscallregs *, int);
+static void acallpr(int, char *, struct bioscallregs *);
+
+/* bitmask defns for printing apm call args/results */
+#define ACPF_AX 0x00000001
+#define ACPF_AX_HI 0x00000002
+#define ACPF_EAX 0x00000004
+#define ACPF_BX 0x00000008
+#define ACPF_BX_HI 0x00000010
+#define ACPF_EBX 0x00000020
+#define ACPF_CX 0x00000040
+#define ACPF_CX_HI 0x00000080
+#define ACPF_ECX 0x00000100
+#define ACPF_DX 0x00000200
+#define ACPF_DX_HI 0x00000400
+#define ACPF_EDX 0x00000800
+#define ACPF_SI 0x00001000
+#define ACPF_SI_HI 0x00002000
+#define ACPF_ESI 0x00004000
+#define ACPF_DI 0x00008000
+#define ACPF_DI_HI 0x00010000
+#define ACPF_EDI 0x00020000
+#define ACPF_FLAGS 0x00040000
+#define ACPF_FLAGS_HI 0x00080000
+#define ACPF_EFLAGS 0x00100000
+
+struct acallinfo {
+ char *name;
+ int inflag;
+ int outflag;
+};
+
+static struct acallinfo aci[] = {
+ { "install_check", ACPF_BX, ACPF_AX|ACPF_BX|ACPF_CX },
+ { "connectreal", ACPF_BX, 0 },
+ { "connect16", ACPF_BX, ACPF_AX|ACPF_BX|ACPF_CX|ACPF_SI|ACPF_DI },
+ { "connect32", ACPF_BX, ACPF_AX|ACPF_EBX|ACPF_CX|ACPF_DX|ACPF_ESI|ACPF_DI },
+ { "disconnect", ACPF_BX, 0 },
+ { "cpu_idle", 0, 0 },
+ { "cpu_busy", 0, 0 },
+ { "set_power_state", ACPF_BX|ACPF_CX, 0 },
+ { "enable_power_state", ACPF_BX|ACPF_CX, 0 },
+ { "restore_defaults", ACPF_BX, 0 },
+ { "get_power_status", ACPF_BX, ACPF_BX|ACPF_CX|ACPF_DX|ACPF_SI },
+ { "get_event", 0, ACPF_BX|ACPF_CX },
+ { "get_power_state" , ACPF_BX, ACPF_CX },
+ { "enable_dev_power_mgt", ACPF_BX|ACPF_CX, 0 },
+ { "driver_version", ACPF_BX|ACPF_CX, ACPF_AX },
+ { "engage_power_mgt", ACPF_BX|ACPF_CX, 0 },
+ { "get_caps", ACPF_BX, ACPF_BX|ACPF_CX },
+ { "resume_timer", ACPF_BX|ACPF_CX|ACPF_SI|ACPF_DI, ACPF_CX|ACPF_SI|ACPF_DI },
+ { "resume_ring", ACPF_BX|ACPF_CX, ACPF_CX },
+ { "timer_reqs", ACPF_BX|ACPF_CX, ACPF_CX },
+};
+
+static void acallpr(int flag, char *tag, struct bioscallregs *b) {
+ if (!flag) return;
+ printf("%s ", tag);
+ if (flag & ACPF_AX) printf("ax=%#x ", b->AX);
+ if (flag & ACPF_AX_HI) printf("ax_hi=%#x ", b->AX_HI);
+ if (flag & ACPF_EAX) printf("eax=%#x ", b->EAX);
+ if (flag & ACPF_BX ) printf("bx=%#x ", b->BX);
+ if (flag & ACPF_BX_HI ) printf("bx_hi=%#x ", b->BX_HI);
+ if (flag & ACPF_EBX ) printf("ebx=%#x ", b->EBX);
+ if (flag & ACPF_CX ) printf("cx=%#x ", b->CX);
+ if (flag & ACPF_CX_HI ) printf("cx_hi=%#x ", b->CX_HI);
+ if (flag & ACPF_ECX ) printf("ecx=%#x ", b->ECX);
+ if (flag & ACPF_DX ) printf("dx=%#x ", b->DX);
+ if (flag & ACPF_DX_HI ) printf("dx_hi=%#x ", b->DX_HI);
+ if (flag & ACPF_EDX ) printf("edx=%#x ", b->EDX);
+ if (flag & ACPF_SI ) printf("si=%#x ", b->SI);
+ if (flag & ACPF_SI_HI ) printf("si_hi=%#x ", b->SI_HI);
+ if (flag & ACPF_ESI ) printf("esi=%#x ", b->ESI);
+ if (flag & ACPF_DI ) printf("di=%#x ", b->DI);
+ if (flag & ACPF_DI_HI ) printf("di_hi=%#x ", b->DI_HI);
+ if (flag & ACPF_EDI ) printf("edi=%#x ", b->EDI);
+ if (flag & ACPF_FLAGS ) printf("flags=%#x ", b->FLAGS);
+ if (flag & ACPF_FLAGS_HI) printf("flags_hi=%#x ", b->FLAGS_HI);
+ if (flag & ACPF_EFLAGS ) printf("eflags=%#x ", b->EFLAGS);
+}
int
apmcall_debug(func, regs, line)
@@ -231,16 +317,44 @@
int line;
{
int rv;
-
- DPRINTF(APMDEBUG_APMCALLS, ("apmcall: func %d from line %d",
- func, line));
+ int print = (apmdebug & APMDEBUG_APMCALLS) != 0;
+ char *name;
+ int inf, outf;
+
+ if (print) {
+ if (func >= sizeof(aci) / sizeof(aci[0])) {
+ name = 0;
+ inf = outf = 0;
+ } else {
+ name = aci[func].name;
+ inf = aci[func].inflag;
+ outf = aci[func].outflag;
+ }
+ inittodr(time.tv_sec); /* update timestamp */
+ if (name)
+ printf("apmcall@%03ld: %s/%#x (line=%d) ",
+ time.tv_sec % 1000, name, func, line);
+ else
+ printf("apmcall@%03ld: %#x (line=%d) ",
+ time.tv_sec % 1000, func, line);
+ acallpr(inf, "in:", regs);
+ }
rv = apmcall(func, regs);
- DPRINTF(APMDEBUG_APMCALLS, (" -> 0x%x\n", rv));
+ if (print) {
+ if (rv) {
+ printf(" => error %#x (%s)\n", regs->AX >> 8,
+ apm_strerror(regs->AX >> 8));
+ } else {
+ printf(" => ");
+ acallpr(outf, "out:", regs);
+ printf("\n");
+ }
+ }
return (rv);
}
#define apmcall(f, r) apmcall_debug((f), (r), __LINE__)
-#endif
+#endif /* APMDEBUG */
static const char *
@@ -461,8 +575,10 @@
if ((sc->sc_flags & SCFLAG_OPEN) == 0)
return 1; /* no user waiting */
- if (sc->event_count == APM_NEVENTS)
+ if (sc->event_count == APM_NEVENTS) {
+ DPRINTF(APMDEBUG_ANOM, ("apm_record_event: queue full!\n"));
return 1; /* overflow */
+ }
evp = &sc->event_list[sc->event_ptr];
sc->event_count++;
sc->event_ptr++;
@@ -473,44 +589,34 @@
return (sc->sc_flags & SCFLAG_OWRITE) ? 0 : 1; /* user may handle */
}
-static void
+/*
+ * apm_event_handle: handle an event. returns 1 if event handled, 0 if
+ * event is a duplicate of an event we are already handling.
+ */
+static int
apm_event_handle(sc, regs)
struct apm_softc *sc;
struct bioscallregs *regs;
{
- int error;
+ int error, retval;
struct bioscallregs nregs;
char *code;
+ retval = 1; /* assume we are going to make progress */
+
switch (regs->BX) {
case APM_USER_STANDBY_REQ:
- DPRINTF(APMDEBUG_EVENTS, ("apmev: user standby request\n"));
+ case APM_STANDBY_REQ:
+ DPRINTF(APMDEBUG_EVENTS, ("apmev: %s standby request\n",
+ (regs->BX == APM_STANDBY_REQ) ? "system" : "user"));
if (apm_do_standby) {
- if (apm_record_event(sc, regs->BX))
- apm_userstandbys++;
- apm_op_inprog++;
- (void)apm_set_powstate(APM_DEV_ALLDEVS,
- APM_LASTREQ_INPROG);
- } else {
- (void)apm_set_powstate(APM_DEV_ALLDEVS,
- APM_LASTREQ_REJECTED);
- /* in case BIOS hates being spurned */
- apm_powmgt_enable(1);
- }
- break;
-
- case APM_STANDBY_REQ:
- DPRINTF(APMDEBUG_EVENTS, ("apmev: system standby request\n"));
- if (apm_standbys || apm_suspends) {
- DPRINTF(APMDEBUG_EVENTS | APMDEBUG_ANOM,
- ("damn fool BIOS did not wait for answer\n"));
- /* just give up the fight */
- apm_damn_fool_bios = 1;
- }
- if (apm_do_standby) {
- if (apm_record_event(sc, regs->BX))
- apm_standbys++;
- apm_op_inprog++;
+ if (apm_standby_pending)
+ retval = 0; /* duplicate request */
+ else {
+ if (apm_record_event(sc, regs->BX))
+ apm_standby_now++; /* kernel handles */
+ apm_standby_pending++;
+ }
(void)apm_set_powstate(APM_DEV_ALLDEVS,
APM_LASTREQ_INPROG);
} else {
@@ -522,24 +628,16 @@
break;
case APM_USER_SUSPEND_REQ:
- DPRINTF(APMDEBUG_EVENTS, ("apmev: user suspend request\n"));
- if (apm_record_event(sc, regs->BX))
- apm_suspends++;
- apm_op_inprog++;
- (void)apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG);
- break;
-
case APM_SUSPEND_REQ:
- DPRINTF(APMDEBUG_EVENTS, ("apmev: system suspend request\n"));
- if (apm_standbys || apm_suspends) {
- DPRINTF(APMDEBUG_EVENTS | APMDEBUG_ANOM,
- ("damn fool BIOS did not wait for answer\n"));
- /* just give up the fight */
- apm_damn_fool_bios = 1;
+ DPRINTF(APMDEBUG_EVENTS, ("apmev: %s suspend request\n",
+ (regs->BX == APM_SUSPEND_REQ) ? "system" : "user"));
+ if (apm_suspend_pending)
+ retval = 0; /* duplicate request */
+ else {
+ if (apm_record_event(sc, regs->BX))
+ apm_suspend_now++; /* kernel handles */
+ apm_suspend_pending++;
}
- if (apm_record_event(sc, regs->BX))
- apm_suspends++;
- apm_op_inprog++;
(void)apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG);
break;
@@ -583,7 +681,6 @@
case APM_BATTERY_LOW:
Home |
Main Index |
Thread Index |
Old Index