summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2001-10-24 14:46:40 +0000
committernyan <nyan@FreeBSD.org>2001-10-24 14:46:40 +0000
commitd59e014361f325e7c0136da5ec4b6a6575b2aa32 (patch)
tree7b65b1700e65f469476812a1f2bd54cb0ee86d9d
parentdb9a37a27ac55295c0d14f5f452955bfc74b1cef (diff)
downloadFreeBSD-src-d59e014361f325e7c0136da5ec4b6a6575b2aa32.zip
FreeBSD-src-d59e014361f325e7c0136da5ec4b6a6575b2aa32.tar.gz
Added the pmc driver which supports power management controller of
old NEC PC-98NOTE. Submitted by: chi@bd.mbn.or.jp (Chiharu Shibata) MFC after: 1 week
-rw-r--r--sys/conf/files.pc981
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/pmc/Makefile13
-rw-r--r--sys/pc98/cbus/pmc.c257
-rw-r--r--sys/pc98/conf/GENERIC1
-rw-r--r--sys/pc98/conf/GENERIC.hints3
-rw-r--r--sys/pc98/pc98/pmc.c257
7 files changed, 533 insertions, 0 deletions
diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98
index ba9b63c..3751430 100644
--- a/sys/conf/files.pc98
+++ b/sys/conf/files.pc98
@@ -395,6 +395,7 @@ pc98/pc98/pc98gdc.c optional gdc
pc98/pc98/pc98kbd.c optional pckbd
pc98/pc98/pc98_machdep.c standard
pc98/pc98/pcaudio.c optional pca
+pc98/pc98/pmc.c optional pmc
pc98/pc98/ppc.c optional ppc
pc98/pc98/scgdcrndr.c optional sc gdc
pc98/pc98/scterm-sck.c optional sc
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index c07fb37..d0c965f 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -136,6 +136,7 @@ SUBDIR+=aac \
# smbfs \
.if ${MACHINE} == "pc98"
+SUBDIR+=pmc
SUBDIR+=snc
.endif
diff --git a/sys/modules/pmc/Makefile b/sys/modules/pmc/Makefile
new file mode 100644
index 0000000..59994a0
--- /dev/null
+++ b/sys/modules/pmc/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../pc98/pc98
+
+KMOD= pmc
+SRCS= pmc.c
+SRCS+= bus_if.h device_if.h isa_if.h
+
+.if ${MACHINE} == "pc98"
+CFLAGS+= -DPC98
+.endif
+
+.include <bsd.kmod.mk>
diff --git a/sys/pc98/cbus/pmc.c b/sys/pc98/cbus/pmc.c
new file mode 100644
index 0000000..fe201e9
--- /dev/null
+++ b/sys/pc98/cbus/pmc.c
@@ -0,0 +1,257 @@
+/*-
+ * PMC (Power Management Controller of NEC PC-98Note) Driver
+ *
+ * Copyright (c) 2001 Chiharu Shibata.
+ * 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 withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/reboot.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <isa/isavar.h>
+
+struct pmc_isa_softc {
+ struct resource *port_res;
+ eventhandler_tag evt;
+ int flags;
+};
+
+static int pmc_isa_alloc_resources __P((device_t));
+static void pmc_isa_release_resources __P((device_t));
+static int pmc_isa_probe __P((device_t));
+static int pmc_isa_attach __P((device_t));
+static int pmc_isa_detach __P((device_t));
+
+#define PMC_ISA_PORT 0x8f0
+#define PMC_ISA_PORTSIZE 4
+
+#define sc_inw(sc, port) \
+ bus_space_read_2(rman_get_bustag((sc)->port_res), \
+ rman_get_bushandle((sc)->port_res), (port))
+
+#define sc_outw(sc, port, value) \
+ bus_space_write_2(rman_get_bustag((sc)->port_res), \
+ rman_get_bushandle((sc)->port_res), (port), (value))
+
+static void
+pmc_poweroff(void *arg, int howto)
+{
+ struct pmc_isa_softc *sc = (struct pmc_isa_softc *)arg;
+
+ if (!sc->flags) {
+ outb(0x5e8e, inb(0x5e8e) & ~0x11); /* FDD LED off */
+ }
+
+ if (!(howto & RB_POWEROFF)) {
+ return;
+ }
+
+ sc_outw(sc, 0, 0x0044);
+ sc_outw(sc, 2, 1 << 10);
+#if 1
+ /* for 9801NS/T */
+ sc_outw(sc, 0, 0xf00a);
+ sc_outw(sc, 2, 1 << 9);
+#endif
+}
+
+static int
+pmc_isa_alloc_resources(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+ int rid;
+
+ bzero(sc, sizeof(*sc));
+
+ rid = 0;
+ sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0ul, ~0ul, PMC_ISA_PORTSIZE,
+ RF_ACTIVE);
+ if (sc->port_res == NULL) {
+ return (ENOMEM);
+ }
+
+ return 0;
+}
+
+static void
+pmc_isa_release_resources(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+
+ if (sc->port_res != NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res);
+ }
+ sc->port_res = NULL;
+}
+
+static int
+pmc_isa_probe(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+ u_int port;
+ u_int16_t save, tmp;
+
+#if 0
+ if (isa_get_vendorid(dev)) {
+ return ENXIO;
+ }
+ if (device_get_unit(dev) > 0) {
+ printf("pmc: Only one PMC driver supported.\n");
+ return ENXIO;
+ }
+#endif
+ port = isa_get_port(dev);
+ if (port == -1) {
+ port = PMC_ISA_PORT;
+ }
+ if (bootverbose) {
+ device_printf(dev, "port = 0x%x\n", port);
+ }
+
+ if (bus_set_resource(dev, SYS_RES_IOPORT, 0, port, PMC_ISA_PORTSIZE)) {
+ if (bootverbose) {
+ device_printf(dev, "bus_set_resource failed\n");
+ }
+ return ENXIO;
+ }
+ if (pmc_isa_alloc_resources(dev)) {
+ if (bootverbose) {
+ device_printf(dev, "pmc_isa_alloc_resources failed\n");
+ }
+ return ENXIO;
+ }
+
+ /* Check the existence of PMC */
+ sc_outw(sc, 0, 0x0052);
+ save = sc_inw(sc, 2);
+ tmp = save & ~0x3f;
+ sc_outw(sc, 2, tmp);
+ if (sc_inw(sc, 2) != tmp) {
+ if (bootverbose) {
+ device_printf(dev, "failed to clear index(0x0052)\n");
+ }
+
+ pmc_isa_release_resources(dev);
+ return ENXIO;
+ }
+
+ tmp |= 0x3e;
+ sc_outw(sc, 2, tmp);
+ if (sc_inw(sc, 2) != tmp) {
+ if (bootverbose) {
+ device_printf(dev, "failed to set index(0x0052)\n");
+ }
+
+ pmc_isa_release_resources(dev);
+ return ENXIO;
+ }
+ sc_outw(sc, 2, save);
+
+ pmc_isa_release_resources(dev);
+
+ device_set_desc(dev, "Power Management Controller");
+ return 0;
+}
+
+static int
+pmc_isa_attach(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = pmc_isa_alloc_resources(dev);
+ if (error) {
+ device_printf(dev, "resource allocation failed\n");
+ return error;
+ }
+
+ /* Power the system off using PMC */
+ sc->evt = EVENTHANDLER_REGISTER(shutdown_final, pmc_poweroff, sc,
+ SHUTDOWN_PRI_LAST);
+ sc->flags = device_get_flags(dev);
+ return 0;
+}
+
+static int
+pmc_isa_detach(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+
+ if (bootverbose) {
+ device_printf(dev, "pmc_isa_detach called\n");
+ }
+
+ if (sc->evt != NULL) {
+ EVENTHANDLER_DEREGISTER(shutdown_final, sc->evt);
+ }
+ sc->evt = NULL;
+
+ pmc_isa_release_resources(dev);
+ return 0;
+}
+
+#ifdef KLD_MODULE
+static void
+pmc_isa_identify(driver_t *drv, device_t dev)
+{
+ if (BUS_ADD_CHILD(dev, ISA_ORDER_SPECULATIVE, "pmc", 0) == NULL) {
+ printf("failed to add pmc driver\n");
+ }
+}
+#endif
+
+static device_method_t pmc_isa_methods[] = {
+ /* Device interface */
+#ifdef KLD_MODULE
+ DEVMETHOD(device_identify, pmc_isa_identify),
+#endif
+ DEVMETHOD(device_probe, pmc_isa_probe),
+ DEVMETHOD(device_attach, pmc_isa_attach),
+ DEVMETHOD(device_detach, pmc_isa_detach),
+ {0, 0}
+};
+
+static driver_t pmc_isa_driver = {
+ "pmc",
+ pmc_isa_methods, sizeof(struct pmc_isa_softc),
+};
+
+devclass_t pmc_devclass;
+
+DRIVER_MODULE(pmc, isa, pmc_isa_driver, pmc_devclass, 0, 0);
diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC
index f1c93ad..c79c743 100644
--- a/sys/pc98/conf/GENERIC
+++ b/sys/pc98/conf/GENERIC
@@ -126,6 +126,7 @@ device npx
# Power management support (see NOTES for more options)
#device apm
+#device pmc
# Add suspend/resume support for the i8254.
#device pmtimer
diff --git a/sys/pc98/conf/GENERIC.hints b/sys/pc98/conf/GENERIC.hints
index 4f64788..76f2817 100644
--- a/sys/pc98/conf/GENERIC.hints
+++ b/sys/pc98/conf/GENERIC.hints
@@ -103,6 +103,9 @@ hint.npx.0.irq="8"
#hint.apm.0.flags="0x20"
#hint.pmtimer.0.at="isa"
+#hint.pmc.0.at="isa"
+#hint.pmc.0.port="0x8f0"
+
hint.pcic.0.at="isa"
#hint.pcic.0.irq="6" # Default to polling
hint.pcic.0.port="0x3e0"
diff --git a/sys/pc98/pc98/pmc.c b/sys/pc98/pc98/pmc.c
new file mode 100644
index 0000000..fe201e9
--- /dev/null
+++ b/sys/pc98/pc98/pmc.c
@@ -0,0 +1,257 @@
+/*-
+ * PMC (Power Management Controller of NEC PC-98Note) Driver
+ *
+ * Copyright (c) 2001 Chiharu Shibata.
+ * 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 withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/reboot.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <isa/isavar.h>
+
+struct pmc_isa_softc {
+ struct resource *port_res;
+ eventhandler_tag evt;
+ int flags;
+};
+
+static int pmc_isa_alloc_resources __P((device_t));
+static void pmc_isa_release_resources __P((device_t));
+static int pmc_isa_probe __P((device_t));
+static int pmc_isa_attach __P((device_t));
+static int pmc_isa_detach __P((device_t));
+
+#define PMC_ISA_PORT 0x8f0
+#define PMC_ISA_PORTSIZE 4
+
+#define sc_inw(sc, port) \
+ bus_space_read_2(rman_get_bustag((sc)->port_res), \
+ rman_get_bushandle((sc)->port_res), (port))
+
+#define sc_outw(sc, port, value) \
+ bus_space_write_2(rman_get_bustag((sc)->port_res), \
+ rman_get_bushandle((sc)->port_res), (port), (value))
+
+static void
+pmc_poweroff(void *arg, int howto)
+{
+ struct pmc_isa_softc *sc = (struct pmc_isa_softc *)arg;
+
+ if (!sc->flags) {
+ outb(0x5e8e, inb(0x5e8e) & ~0x11); /* FDD LED off */
+ }
+
+ if (!(howto & RB_POWEROFF)) {
+ return;
+ }
+
+ sc_outw(sc, 0, 0x0044);
+ sc_outw(sc, 2, 1 << 10);
+#if 1
+ /* for 9801NS/T */
+ sc_outw(sc, 0, 0xf00a);
+ sc_outw(sc, 2, 1 << 9);
+#endif
+}
+
+static int
+pmc_isa_alloc_resources(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+ int rid;
+
+ bzero(sc, sizeof(*sc));
+
+ rid = 0;
+ sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0ul, ~0ul, PMC_ISA_PORTSIZE,
+ RF_ACTIVE);
+ if (sc->port_res == NULL) {
+ return (ENOMEM);
+ }
+
+ return 0;
+}
+
+static void
+pmc_isa_release_resources(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+
+ if (sc->port_res != NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res);
+ }
+ sc->port_res = NULL;
+}
+
+static int
+pmc_isa_probe(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+ u_int port;
+ u_int16_t save, tmp;
+
+#if 0
+ if (isa_get_vendorid(dev)) {
+ return ENXIO;
+ }
+ if (device_get_unit(dev) > 0) {
+ printf("pmc: Only one PMC driver supported.\n");
+ return ENXIO;
+ }
+#endif
+ port = isa_get_port(dev);
+ if (port == -1) {
+ port = PMC_ISA_PORT;
+ }
+ if (bootverbose) {
+ device_printf(dev, "port = 0x%x\n", port);
+ }
+
+ if (bus_set_resource(dev, SYS_RES_IOPORT, 0, port, PMC_ISA_PORTSIZE)) {
+ if (bootverbose) {
+ device_printf(dev, "bus_set_resource failed\n");
+ }
+ return ENXIO;
+ }
+ if (pmc_isa_alloc_resources(dev)) {
+ if (bootverbose) {
+ device_printf(dev, "pmc_isa_alloc_resources failed\n");
+ }
+ return ENXIO;
+ }
+
+ /* Check the existence of PMC */
+ sc_outw(sc, 0, 0x0052);
+ save = sc_inw(sc, 2);
+ tmp = save & ~0x3f;
+ sc_outw(sc, 2, tmp);
+ if (sc_inw(sc, 2) != tmp) {
+ if (bootverbose) {
+ device_printf(dev, "failed to clear index(0x0052)\n");
+ }
+
+ pmc_isa_release_resources(dev);
+ return ENXIO;
+ }
+
+ tmp |= 0x3e;
+ sc_outw(sc, 2, tmp);
+ if (sc_inw(sc, 2) != tmp) {
+ if (bootverbose) {
+ device_printf(dev, "failed to set index(0x0052)\n");
+ }
+
+ pmc_isa_release_resources(dev);
+ return ENXIO;
+ }
+ sc_outw(sc, 2, save);
+
+ pmc_isa_release_resources(dev);
+
+ device_set_desc(dev, "Power Management Controller");
+ return 0;
+}
+
+static int
+pmc_isa_attach(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = pmc_isa_alloc_resources(dev);
+ if (error) {
+ device_printf(dev, "resource allocation failed\n");
+ return error;
+ }
+
+ /* Power the system off using PMC */
+ sc->evt = EVENTHANDLER_REGISTER(shutdown_final, pmc_poweroff, sc,
+ SHUTDOWN_PRI_LAST);
+ sc->flags = device_get_flags(dev);
+ return 0;
+}
+
+static int
+pmc_isa_detach(device_t dev)
+{
+ struct pmc_isa_softc *sc = device_get_softc(dev);
+
+ if (bootverbose) {
+ device_printf(dev, "pmc_isa_detach called\n");
+ }
+
+ if (sc->evt != NULL) {
+ EVENTHANDLER_DEREGISTER(shutdown_final, sc->evt);
+ }
+ sc->evt = NULL;
+
+ pmc_isa_release_resources(dev);
+ return 0;
+}
+
+#ifdef KLD_MODULE
+static void
+pmc_isa_identify(driver_t *drv, device_t dev)
+{
+ if (BUS_ADD_CHILD(dev, ISA_ORDER_SPECULATIVE, "pmc", 0) == NULL) {
+ printf("failed to add pmc driver\n");
+ }
+}
+#endif
+
+static device_method_t pmc_isa_methods[] = {
+ /* Device interface */
+#ifdef KLD_MODULE
+ DEVMETHOD(device_identify, pmc_isa_identify),
+#endif
+ DEVMETHOD(device_probe, pmc_isa_probe),
+ DEVMETHOD(device_attach, pmc_isa_attach),
+ DEVMETHOD(device_detach, pmc_isa_detach),
+ {0, 0}
+};
+
+static driver_t pmc_isa_driver = {
+ "pmc",
+ pmc_isa_methods, sizeof(struct pmc_isa_softc),
+};
+
+devclass_t pmc_devclass;
+
+DRIVER_MODULE(pmc, isa, pmc_isa_driver, pmc_devclass, 0, 0);
OpenPOWER on IntegriCloud