Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/i386/i386 Make APM use a kernel thread rather than ...
details: https://anonhg.NetBSD.org/src/rev/8ae44f275caa
branches: trunk
changeset: 481838:8ae44f275caa
user: thorpej <thorpej%NetBSD.org@localhost>
date: Mon Feb 07 17:36:59 2000 +0000
description:
Make APM use a kernel thread rather than a callout, and provide a
mutex between the thread and a user process attempting to do APM
operations.
diffstat:
sys/arch/i386/i386/apm.c | 159 +++++++++++++++++++++++++++++++++++++---------
1 files changed, 128 insertions(+), 31 deletions(-)
diffs (truncated from 325 to 300 lines):
diff -r 0a8786126997 -r 8ae44f275caa sys/arch/i386/i386/apm.c
--- a/sys/arch/i386/i386/apm.c Mon Feb 07 16:26:59 2000 +0000
+++ b/sys/arch/i386/i386/apm.c Mon Feb 07 17:36:59 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: apm.c,v 1.43 1999/11/10 16:55:25 drochner Exp $ */
+/* $NetBSD: apm.c,v 1.44 2000/02/07 17:36:59 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -57,6 +57,8 @@
#include <sys/kernel.h>
#include <sys/map.h>
#include <sys/proc.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
#include <sys/user.h>
#include <sys/malloc.h>
#include <sys/device.h>
@@ -109,6 +111,8 @@
int sc_flags;
int event_count;
int event_ptr;
+ struct proc *sc_thread;
+ struct lock sc_lock;
struct apm_event_info event_list[APM_NEVENTS];
};
#define SCFLAG_OREAD 0x0000001
@@ -120,6 +124,17 @@
#define APMDEV_NORMAL 0
#define APMDEV_CTL 8
+/*
+ * A brief note on the locking protocol: it's very simple; we
+ * assert an exclusive lock any time thread context enters the
+ * APM module. This is both the APM thread itself, as well as
+ * user context.
+ */
+#define APM_LOCK(apmsc) \
+ (void) lockmgr(&(apmsc)->sc_lock, LK_EXCLUSIVE, NULL)
+#define APM_UNLOCK(apmsc) \
+ (void) lockmgr(&(apmsc)->sc_lock, LK_RELEASE, NULL)
+
static void apmattach __P((struct device *, struct device *, void *));
static int apmmatch __P((struct device *, struct cfdata *, void *));
@@ -133,7 +148,9 @@
#if 0
static void apm_get_powstate __P((u_int));
#endif
-static void apm_periodic_check __P((void *));
+static void apm_periodic_check __P((struct apm_softc *));
+static void apm_create_thread __P((void *));
+static void apm_thread __P((void *));
static void apm_perror __P((const char *, struct bioscallregs *, ...))
__kprintf_attribute__((__format__(__printf__,1,3)));
static void apm_power_print __P((struct apm_softc *, struct bioscallregs *));
@@ -564,11 +581,10 @@
}
static void
-apm_periodic_check(arg)
- void *arg;
+apm_periodic_check(sc)
+ struct apm_softc *sc;
{
struct bioscallregs regs;
- struct apm_softc *sc = arg;
/*
* tell the BIOS we're working on it, if asked to do a
@@ -591,7 +607,6 @@
}
apm_suspends = apm_standbys = apm_battlow = apm_userstandbys = 0;
apm_damn_fool_bios = 0;
- timeout(apm_periodic_check, sc, hz);
}
static void
@@ -1237,8 +1252,18 @@
} else
apm_perror("get power status", ®s);
apm_cpu_busy();
+
+ lockinit(&apmsc->sc_lock, PWAIT, "apmlk", 0, 0);
+
+ /* Do an initial check. */
apm_periodic_check(apmsc);
+ /*
+ * Create a kernel thread to periodically check for APM events,
+ * and notify other subsystems when they occur.
+ */
+ kthread_create(apm_create_thread, apmsc);
+
return;
bail:
@@ -1255,8 +1280,52 @@
printf("\n%s: kernel APM support disabled\n", apmsc->sc_dev.dv_xname);
}
+void
+apm_create_thread(arg)
+ void *arg;
+{
+ struct apm_softc *apmsc = arg;
+ struct bioscallregs regs;
+#ifdef APMDEBUG
+ char bits[128];
+#endif
+
+ if (kthread_create1(apm_thread, apmsc, &apmsc->sc_thread,
+ "%s", apmsc->sc_dev.dv_xname) == 0)
+ return;
+
+ /*
+ * We were unable to create the APM thread; bail out.
+ */
+ regs.AX = APM_BIOS_FN(APM_DISCONNECT);
+ regs.BX = APM_DEV_APM_BIOS;
+ regs.CX = regs.DX = regs.SI = regs.DI = regs.FLAGS = 0;
+ bioscall(APM_SYSTEM_BIOS, ®s);
+ DPRINTF(APMDEBUG_ATTACH, ("\n%s: ", apmsc->sc_dev.dv_xname));
+ DPRINTF_BIOSRETURN(regs, bits);
+ printf("%s: unable to create thread, kernel APM support disabled\n",
+ apmsc->sc_dev.dv_xname);
+}
+
#undef DPRINTF_BIOSRETURN
+void
+apm_thread(arg)
+ void *arg;
+{
+ struct apm_softc *apmsc = arg;
+
+ /*
+ * Loop forever, doing a periodic check for APM events.
+ */
+ for (;;) {
+ APM_LOCK(apmsc);
+ apm_periodic_check(apmsc);
+ APM_UNLOCK(apmsc);
+ (void) tsleep(apmsc, PWAIT, "apmev", hz);
+ }
+}
+
int
apmopen(dev, flag, mode, p)
dev_t dev;
@@ -1265,6 +1334,7 @@
{
int unit = APMUNIT(dev);
int ctl = APMDEV(dev);
+ int error = 0;
struct apm_softc *sc;
if (unit >= apm_cd.cd_ndevs)
@@ -1279,24 +1349,33 @@
DPRINTF(APMDEBUG_DEVICE,
("apmopen: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
+ APM_LOCK(sc);
switch (ctl) {
case APMDEV_CTL:
- if (!(flag & FWRITE))
- return EINVAL;
- if (sc->sc_flags & SCFLAG_OWRITE)
- return EBUSY;
+ if (!(flag & FWRITE)) {
+ error = EINVAL;
+ break;
+ }
+ if (sc->sc_flags & SCFLAG_OWRITE) {
+ error = EBUSY;
+ break;
+ }
sc->sc_flags |= SCFLAG_OWRITE;
break;
case APMDEV_NORMAL:
- if (!(flag & FREAD) || (flag & FWRITE))
- return EINVAL;
+ if (!(flag & FREAD) || (flag & FWRITE)) {
+ error = EINVAL;
+ break;
+ }
sc->sc_flags |= SCFLAG_OREAD;
break;
default:
- return ENXIO;
+ error = ENXIO;
break;
}
- return 0;
+ APM_UNLOCK(sc);
+
+ return (error);
}
int
@@ -1311,6 +1390,7 @@
DPRINTF(APMDEBUG_DEVICE,
("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
+ APM_LOCK(sc);
switch (ctl) {
case APMDEV_CTL:
sc->sc_flags &= ~SCFLAG_OWRITE;
@@ -1323,6 +1403,7 @@
sc->event_count = 0;
sc->event_ptr = 0;
}
+ APM_UNLOCK(sc);
return 0;
}
@@ -1341,50 +1422,61 @@
#if 0
struct apm_ctl *actl;
#endif
- int i;
+ int i, error = 0;
+ APM_LOCK(sc);
switch (cmd) {
case APM_IOC_STANDBY:
- if (!apm_do_standby)
- return (EOPNOTSUPP);
+ if (!apm_do_standby) {
+ error = EOPNOTSUPP;
+ break;
+ }
- if ((flag & FWRITE) == 0)
- return (EBADF);
+ if ((flag & FWRITE) == 0) {
+ error = EBADF;
+ break;
+ }
apm_userstandbys++;
- return (0);
+ break;
case APM_IOC_SUSPEND:
- if ((flag & FWRITE) == 0)
- return (EBADF);
+ if ((flag & FWRITE) == 0) {
+ error = EBADF;
+ break;
+ }
apm_suspends++;
- return (0);
+ break;
#if 0 /* is this used at all? */
case APM_IOC_DEV_CTL:
actl = (struct apm_ctl *)data;
- if ((flag & FWRITE) == 0)
- return (EBADF);
+ if ((flag & FWRITE) == 0) {
+ error = EBADF;
+ break;
+ }
apm_get_powstate(actl->dev); /* XXX */
- return (apm_set_powstate(actl->dev, actl->mode));
+ error = apm_set_powstate(actl->dev, actl->mode);
+ break;
#endif
case APM_IOC_NEXTEVENT:
if (!sc->event_count)
- return (EAGAIN);
+ error = EAGAIN;
else {
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--;
- return (0);
}
+ break;
case APM_IOC_GETPOWER:
powerp = (struct apm_power_info *)data;
if (apm_get_powstat(®s)) {
apm_perror("ioctl get power status", ®s);
- return (EIO);
+ error = EIO;
+ break;
}
memset(powerp, 0, sizeof(*powerp));
@@ -1412,11 +1504,14 @@
powerp->minutes_left =
APM_BATT_REMAINING(®s);
}
- return (0);
+ break;
Home |
Main Index |
Thread Index |
Old Index