summaryrefslogtreecommitdiffstats
path: root/sys/dev/ppc
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2006-04-24 23:31:51 +0000
committermarcel <marcel@FreeBSD.org>2006-04-24 23:31:51 +0000
commitdeb16135f3fca75d654b5678f9f331af783b6d6b (patch)
tree4c14a9bedc4bcdbb3fbd46089cf47c3af3cc2de1 /sys/dev/ppc
parenteefd58df920bd36d125e2f8e0db44d74e8859b3a (diff)
downloadFreeBSD-src-deb16135f3fca75d654b5678f9f331af783b6d6b.zip
FreeBSD-src-deb16135f3fca75d654b5678f9f331af783b6d6b.tar.gz
o Move ISA specific code from ppc.c to ppc_isa.c -- a bus front-
end for isa(4). o Add a seperate bus frontend for acpi(4) and allow ISA DMA for it when ISA is configured in the kernel. This allows acpi(4) attachments in non-ISA configurations, as is possible for ia64. o Add a seperate bus frontend for pci(4) and detect known single port parallel cards. o Merge PC98 specific changes under pc98/cbus into the MI driver. The changes are minor enough for conditional compilation and in this form invites better abstraction. o Have ppc(4) usabled on all platforms, now that ISA specifics are untangled enough.
Diffstat (limited to 'sys/dev/ppc')
-rw-r--r--sys/dev/ppc/ppc.c302
-rw-r--r--sys/dev/ppc/ppc_acpi.c114
-rw-r--r--sys/dev/ppc/ppc_isa.c281
-rw-r--r--sys/dev/ppc/ppc_pci.c110
-rw-r--r--sys/dev/ppc/ppc_puc.c4
-rw-r--r--sys/dev/ppc/ppcreg.h9
-rw-r--r--sys/dev/ppc/ppcvar.h5
7 files changed, 585 insertions, 240 deletions
diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c
index 7e1ed40..48a9889 100644
--- a/sys/dev/ppc/ppc.c
+++ b/sys/dev/ppc/ppc.c
@@ -36,18 +36,16 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/malloc.h>
-#include <sys/kdb.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/clock.h>
#include <machine/bus.h>
#include <machine/resource.h>
-#include <machine/vmparam.h>
#include <sys/rman.h>
-#include <isa/isareg.h>
-#include <isa/isavar.h>
+#ifdef __i386__
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/vmparam.h>
+#endif
#include <dev/ppbus/ppbconf.h>
#include <dev/ppbus/ppb_msq.h>
@@ -57,47 +55,23 @@ __FBSDID("$FreeBSD$");
#include "ppbus_if.h"
-static int ppc_isa_probe(device_t dev);
-
static void ppcintr(void *arg);
+#define IO_LPTSIZE_EXTENDED 8 /* "Extended" LPT controllers */
+#define IO_LPTSIZE_NORMAL 4 /* "Normal" LPT controllers */
+
#define LOG_PPC(function, ppc, string) \
if (bootverbose) printf("%s: %s\n", function, string)
+#if defined(__i386__) && defined(PC98)
+#define PC98_IEEE_1284_DISABLE 0x100
+#define PC98_IEEE_1284_PORT 0x140
+#endif
#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev))
devclass_t ppc_devclass;
-
-static device_method_t ppc_methods[] = {
- /* device interface */
- DEVMETHOD(device_probe, ppc_isa_probe),
- DEVMETHOD(device_attach, ppc_attach),
- DEVMETHOD(device_detach, ppc_detach),
-
- /* bus interface */
- DEVMETHOD(bus_read_ivar, ppc_read_ivar),
- DEVMETHOD(bus_setup_intr, ppc_setup_intr),
- DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
- DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
-
- /* ppbus interface */
- DEVMETHOD(ppbus_io, ppc_io),
- DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq),
- DEVMETHOD(ppbus_reset_epp, ppc_reset_epp),
- DEVMETHOD(ppbus_setmode, ppc_setmode),
- DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync),
- DEVMETHOD(ppbus_read, ppc_read),
- DEVMETHOD(ppbus_write, ppc_write),
-
- { 0, 0 }
- };
-
-static driver_t ppc_driver = {
- "ppc",
- ppc_methods,
- sizeof(struct ppc_data),
-};
+const char ppc_driver_name[] = "ppc";
static char *ppc_models[] = {
"SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
@@ -1593,12 +1567,7 @@ ppcintr(void *arg)
#ifdef PPC_DEBUG
printf("d");
#endif
- isa_dmadone(
- ppc->ppc_dmaflags,
- ppc->ppc_dmaddr,
- ppc->ppc_dmacnt,
- ppc->ppc_dmachan);
-
+ ppc->ppc_dmadone(ppc);
ppc->ppc_dmastat = PPC_DMA_COMPLETE;
/* wakeup the waiting process */
@@ -1620,163 +1589,10 @@ ppc_read(device_t dev, char *buf, int len, int mode)
return (EINVAL);
}
-/*
- * Call this function if you want to send data in any advanced mode
- * of your parallel port: FIFO, DMA
- *
- * If what you want is not possible (no ECP, no DMA...),
- * EINVAL is returned
- */
int
ppc_write(device_t dev, char *buf, int len, int how)
{
- struct ppc_data *ppc = DEVTOSOFTC(dev);
- char ecr, ecr_sav, ctr, ctr_sav;
- int s, error = 0;
- int spin;
-
-#ifdef PPC_DEBUG
- printf("w");
-#endif
-
- ecr_sav = r_ecr(ppc);
- ctr_sav = r_ctr(ppc);
-
- /*
- * Send buffer with DMA, FIFO and interrupts
- */
- if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) {
-
- if (ppc->ppc_dmachan > 0) {
-
- /* byte mode, no intr, no DMA, dir=0, flush fifo
- */
- ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
- w_ecr(ppc, ecr);
-
- /* disable nAck interrupts */
- ctr = r_ctr(ppc);
- ctr &= ~IRQENABLE;
- w_ctr(ppc, ctr);
-
- ppc->ppc_dmaflags = 0;
- ppc->ppc_dmaddr = (caddr_t)buf;
- ppc->ppc_dmacnt = (u_int)len;
-
- switch (ppc->ppc_mode) {
- case PPB_COMPATIBLE:
- /* compatible mode with FIFO, no intr, DMA, dir=0 */
- ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
- break;
- case PPB_ECP:
- ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
- break;
- default:
- error = EINVAL;
- goto error;
- }
-
- w_ecr(ppc, ecr);
- ecr = r_ecr(ppc);
-
- /* enter splhigh() not to be preempted
- * by the dma interrupt, we may miss
- * the wakeup otherwise
- */
- s = splhigh();
-
- ppc->ppc_dmastat = PPC_DMA_INIT;
-
- /* enable interrupts */
- ecr &= ~PPC_SERVICE_INTR;
- ppc->ppc_irqstat = PPC_IRQ_DMA;
- w_ecr(ppc, ecr);
-
- isa_dmastart(
- ppc->ppc_dmaflags,
- ppc->ppc_dmaddr,
- ppc->ppc_dmacnt,
- ppc->ppc_dmachan);
-#ifdef PPC_DEBUG
- printf("s%d", ppc->ppc_dmacnt);
-#endif
- ppc->ppc_dmastat = PPC_DMA_STARTED;
-
- /* Wait for the DMA completed interrupt. We hope we won't
- * miss it, otherwise a signal will be necessary to unlock the
- * process.
- */
- do {
- /* release CPU */
- error = tsleep(ppc,
- PPBPRI | PCATCH, "ppcdma", 0);
-
- } while (error == EWOULDBLOCK);
-
- splx(s);
-
- if (error) {
-#ifdef PPC_DEBUG
- printf("i");
-#endif
- /* stop DMA */
- isa_dmadone(
- ppc->ppc_dmaflags, ppc->ppc_dmaddr,
- ppc->ppc_dmacnt, ppc->ppc_dmachan);
-
- /* no dma, no interrupt, flush the fifo */
- w_ecr(ppc, PPC_ECR_RESET);
-
- ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
- goto error;
- }
-
- /* wait for an empty fifo */
- while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
-
- for (spin=100; spin; spin--)
- if (r_ecr(ppc) & PPC_FIFO_EMPTY)
- goto fifo_empty;
-#ifdef PPC_DEBUG
- printf("Z");
-#endif
- error = tsleep(ppc, PPBPRI | PCATCH, "ppcfifo", hz/100);
- if (error != EWOULDBLOCK) {
-#ifdef PPC_DEBUG
- printf("I");
-#endif
- /* no dma, no interrupt, flush the fifo */
- w_ecr(ppc, PPC_ECR_RESET);
-
- ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
- error = EINTR;
- goto error;
- }
- }
-
-fifo_empty:
- /* no dma, no interrupt, flush the fifo */
- w_ecr(ppc, PPC_ECR_RESET);
-
- } else
- error = EINVAL; /* XXX we should FIFO and
- * interrupts */
- } else
- error = EINVAL;
-
-error:
-
- /* PDRQ must be kept unasserted until nPDACK is
- * deasserted for a minimum of 350ns (SMC datasheet)
- *
- * Consequence may be a FIFO that never empty
- */
- DELAY(1);
-
- w_ecr(ppc, ecr_sav);
- w_ctr(ppc, ctr_sav);
-
- return (error);
+ return (EINVAL);
}
void
@@ -1809,34 +1625,15 @@ ppc_setmode(device_t dev, int mode)
return (ENXIO);
}
-static struct isa_pnp_id lpc_ids[] = {
- { 0x0004d041, "Standard parallel printer port" }, /* PNP0400 */
- { 0x0104d041, "ECP parallel printer port" }, /* PNP0401 */
- { 0 }
-};
-
-static int
-ppc_isa_probe(device_t dev)
-{
- device_t parent;
- int error;
-
- parent = device_get_parent(dev);
-
- error = ISA_PNP_PROBE(parent, dev, lpc_ids);
- if (error == ENXIO)
- return (ENXIO);
- else if (error != 0) /* XXX shall be set after detection */
- device_set_desc(dev, "Parallel port");
-
- return(ppc_probe(dev));
-}
-
int
-ppc_probe(device_t dev)
+ppc_probe(device_t dev, int rid)
{
#ifdef __i386__
static short next_bios_ppc = 0;
+#ifdef PC98
+ unsigned int pc98_ieee_mode = 0x00;
+ unsigned int tmp;
+#endif
#endif
struct ppc_data *ppc;
int error;
@@ -1848,17 +1645,27 @@ ppc_probe(device_t dev)
ppc = DEVTOSOFTC(dev);
bzero(ppc, sizeof(struct ppc_data));
- ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0;
- ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0;
+ ppc->rid_ioport = rid;
/* retrieve ISA parameters */
- error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, NULL);
+ error = bus_get_resource(dev, SYS_RES_IOPORT, rid, &port, NULL);
#ifdef __i386__
/*
* If port not specified, use bios list.
*/
if (error) {
+#ifdef PC98
+ if (next_bios_ppc == 0) {
+ /* Use default IEEE-1284 port of NEC PC-98x1 */
+ port = PC98_IEEE_1284_PORT;
+ next_bios_ppc += 1;
+ if (bootverbose)
+ device_printf(dev,
+ "parallel port found at 0x%x\n",
+ (int) port);
+ }
+#else
if((next_bios_ppc < BIOS_MAX_PPC) &&
(*(BIOS_PORTS+next_bios_ppc) != 0) ) {
port = *(BIOS_PORTS+next_bios_ppc++);
@@ -1869,7 +1676,8 @@ ppc_probe(device_t dev)
device_printf(dev, "parallel port not found.\n");
return ENXIO;
}
- bus_set_resource(dev, SYS_RES_IOPORT, 0, port,
+#endif /* PC98 */
+ bus_set_resource(dev, SYS_RES_IOPORT, rid, port,
IO_LPTSIZE_EXTENDED);
}
#endif
@@ -1878,7 +1686,7 @@ ppc_probe(device_t dev)
* There isn't a bios list on alpha. Put it in the usual place.
*/
if (error) {
- bus_set_resource(dev, SYS_RES_IOPORT, 0, 0x3bc,
+ bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x3bc,
IO_LPTSIZE_NORMAL);
}
#endif
@@ -1937,6 +1745,30 @@ ppc_probe(device_t dev)
ppc->ppc_type = PPC_TYPE_GENERIC;
+#if defined(__i386__) && defined(PC98)
+ /*
+ * IEEE STD 1284 Function Check and Enable
+ * for default IEEE-1284 port of NEC PC-98x1
+ */
+ if (ppc->ppc_base == PC98_IEEE_1284_PORT &&
+ !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) {
+ tmp = inb(ppc->ppc_base + PPC_1284_ENABLE);
+ pc98_ieee_mode = tmp;
+ if ((tmp & 0x10) == 0x10) {
+ outb(ppc->ppc_base + PPC_1284_ENABLE, tmp & ~0x10);
+ tmp = inb(ppc->ppc_base + PPC_1284_ENABLE);
+ if ((tmp & 0x10) == 0x10)
+ goto error;
+ } else {
+ outb(ppc->ppc_base + PPC_1284_ENABLE, tmp | 0x10);
+ tmp = inb(ppc->ppc_base + PPC_1284_ENABLE);
+ if ((tmp & 0x10) != 0x10)
+ goto error;
+ }
+ outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode | 0x10);
+ }
+#endif
+
/*
* Try to detect the chipset and its mode.
*/
@@ -1946,6 +1778,12 @@ ppc_probe(device_t dev)
return (0);
error:
+#if defined(__i386__) && defined(PC98)
+ if (ppc->ppc_base == PC98_IEEE_1284_PORT &&
+ !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) {
+ outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode);
+ }
+#endif
if (ppc->res_irq != 0) {
bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq,
ppc->res_irq);
@@ -1981,12 +1819,6 @@ ppc_attach(device_t dev)
device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n",
ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr);
- if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) {
- /* acquire the DMA channel forever */ /* XXX */
- isa_dma_acquire(ppc->ppc_dmachan);
- isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
- }
-
/* add ppbus as a child of this isa to parallel bridge */
ppbus = device_add_child(dev, "ppbus", -1);
@@ -2192,6 +2024,4 @@ ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
return (error);
}
-DRIVER_MODULE(ppc, isa, ppc_driver, ppc_devclass, 0, 0);
-DRIVER_MODULE(ppc, acpi, ppc_driver, ppc_devclass, 0, 0);
MODULE_DEPEND(ppc, ppbus, 1, 1, 1);
diff --git a/sys/dev/ppc/ppc_acpi.c b/sys/dev/ppc/ppc_acpi.c
new file mode 100644
index 0000000..c3a42fe
--- /dev/null
+++ b/sys/dev/ppc/ppc_acpi.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_isa.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <isa/isareg.h>
+#include <isa/isavar.h>
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_msq.h>
+#include <dev/ppc/ppcvar.h>
+#include <dev/ppc/ppcreg.h>
+
+#include "ppbus_if.h"
+
+static int ppc_acpi_probe(device_t dev);
+
+int ppc_isa_attach(device_t dev);
+int ppc_isa_write(device_t, char *, int, int);
+
+static device_method_t ppc_acpi_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ppc_acpi_probe),
+#ifdef DEV_ISA
+ DEVMETHOD(device_attach, ppc_isa_attach),
+#else
+ DEVMETHOD(device_attach, ppc_attach),
+#endif
+ DEVMETHOD(device_detach, ppc_attach),
+
+ /* bus interface */
+ DEVMETHOD(bus_read_ivar, ppc_read_ivar),
+ DEVMETHOD(bus_setup_intr, ppc_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+
+ /* ppbus interface */
+ DEVMETHOD(ppbus_io, ppc_io),
+ DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq),
+ DEVMETHOD(ppbus_reset_epp, ppc_reset_epp),
+ DEVMETHOD(ppbus_setmode, ppc_setmode),
+ DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync),
+ DEVMETHOD(ppbus_read, ppc_read),
+#ifdef DEV_ISA
+ DEVMETHOD(ppbus_write, ppc_isa_write),
+#else
+ DEVMETHOD(ppbus_write, ppc_write),
+#endif
+
+ { 0, 0 }
+};
+
+static driver_t ppc_acpi_driver = {
+ ppc_driver_name,
+ ppc_acpi_methods,
+ sizeof(struct ppc_data),
+};
+
+static struct isa_pnp_id lpc_ids[] = {
+ { 0x0004d041, "Standard parallel printer port" }, /* PNP0400 */
+ { 0x0104d041, "ECP parallel printer port" }, /* PNP0401 */
+ { 0 }
+};
+
+static int
+ppc_acpi_probe(device_t dev)
+{
+ device_t parent;
+ int error;
+
+ parent = device_get_parent(dev);
+
+ error = ISA_PNP_PROBE(parent, dev, lpc_ids);
+ if (error)
+ return (ENXIO);
+
+ device_set_desc(dev, "Parallel port");
+ return (ppc_probe(dev, 0));
+}
+
+DRIVER_MODULE(ppc, acpi, ppc_acpi_driver, ppc_devclass, 0, 0);
diff --git a/sys/dev/ppc/ppc_isa.c b/sys/dev/ppc/ppc_isa.c
new file mode 100644
index 0000000..0324a49
--- /dev/null
+++ b/sys/dev/ppc/ppc_isa.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright (c) 1997-2000 Nicolas Souchu
+ * Copyright (c) 2001 Alcove - Nicolas Souchu
+ * Copyright (c) 2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/malloc.h>
+
+#if defined(__i386__) && defined(PC98)
+#include <pc98/cbus/cbus.h>
+#else
+#include <isa/isareg.h>
+#endif
+#include <isa/isavar.h>
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_msq.h>
+#include <dev/ppc/ppcvar.h>
+#include <dev/ppc/ppcreg.h>
+
+#include "ppbus_if.h"
+
+static int ppc_isa_probe(device_t dev);
+
+int ppc_isa_attach(device_t dev);
+int ppc_isa_write(device_t, char *, int, int);
+
+static device_method_t ppc_isa_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ppc_isa_probe),
+ DEVMETHOD(device_attach, ppc_isa_attach),
+ DEVMETHOD(device_detach, ppc_attach),
+
+ /* bus interface */
+ DEVMETHOD(bus_read_ivar, ppc_read_ivar),
+ DEVMETHOD(bus_setup_intr, ppc_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+
+ /* ppbus interface */
+ DEVMETHOD(ppbus_io, ppc_io),
+ DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq),
+ DEVMETHOD(ppbus_reset_epp, ppc_reset_epp),
+ DEVMETHOD(ppbus_setmode, ppc_setmode),
+ DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync),
+ DEVMETHOD(ppbus_read, ppc_read),
+ DEVMETHOD(ppbus_write, ppc_isa_write),
+
+ { 0, 0 }
+};
+
+static driver_t ppc_isa_driver = {
+ ppc_driver_name,
+ ppc_isa_methods,
+ sizeof(struct ppc_data),
+};
+
+static struct isa_pnp_id lpc_ids[] = {
+ { 0x0004d041, "Standard parallel printer port" }, /* PNP0400 */
+ { 0x0104d041, "ECP parallel printer port" }, /* PNP0401 */
+ { 0 }
+};
+
+static void
+ppc_isa_dmadone(struct ppc_data *ppc)
+{
+ isa_dmadone(ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt,
+ ppc->ppc_dmachan);
+}
+
+int
+ppc_isa_attach(device_t dev)
+{
+ struct ppc_data *ppc = device_get_softc(dev);
+
+ if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) {
+ /* acquire the DMA channel forever */ /* XXX */
+ isa_dma_acquire(ppc->ppc_dmachan);
+ isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
+ ppc->ppc_dmadone = ppc_isa_dmadone;
+ }
+
+ return (ppc_attach(dev));
+}
+
+static int
+ppc_isa_probe(device_t dev)
+{
+ device_t parent;
+ int error;
+
+ parent = device_get_parent(dev);
+
+ error = ISA_PNP_PROBE(parent, dev, lpc_ids);
+ if (error == ENXIO)
+ return (ENXIO);
+ if (error != 0) /* XXX shall be set after detection */
+ device_set_desc(dev, "Parallel port");
+
+ return (ppc_probe(dev, 0));
+}
+
+/*
+ * Call this function if you want to send data in any advanced mode
+ * of your parallel port: FIFO, DMA
+ *
+ * If what you want is not possible (no ECP, no DMA...),
+ * EINVAL is returned
+ */
+int
+ppc_isa_write(device_t dev, char *buf, int len, int how)
+{
+ struct ppc_data *ppc = device_get_softc(dev);
+ char ecr, ecr_sav, ctr, ctr_sav;
+ int s, error = 0;
+ int spin;
+
+ if (!(ppc->ppc_avm & PPB_ECP) || !ppc->ppc_registered)
+ return (EINVAL);
+ if (ppc->ppc_dmachan == 0)
+ return (EINVAL);
+
+#ifdef PPC_DEBUG
+ printf("w");
+#endif
+
+ ecr_sav = r_ecr(ppc);
+ ctr_sav = r_ctr(ppc);
+
+ /*
+ * Send buffer with DMA, FIFO and interrupts
+ */
+
+ /* byte mode, no intr, no DMA, dir=0, flush fifo */
+ ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
+ w_ecr(ppc, ecr);
+
+ /* disable nAck interrupts */
+ ctr = r_ctr(ppc);
+ ctr &= ~IRQENABLE;
+ w_ctr(ppc, ctr);
+
+ ppc->ppc_dmaflags = 0;
+ ppc->ppc_dmaddr = (caddr_t)buf;
+ ppc->ppc_dmacnt = (u_int)len;
+
+ switch (ppc->ppc_mode) {
+ case PPB_COMPATIBLE:
+ /* compatible mode with FIFO, no intr, DMA, dir=0 */
+ ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
+ break;
+ case PPB_ECP:
+ ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
+ break;
+ default:
+ error = EINVAL;
+ goto error;
+ }
+
+ w_ecr(ppc, ecr);
+ ecr = r_ecr(ppc);
+
+ /* enter splhigh() not to be preempted
+ * by the dma interrupt, we may miss
+ * the wakeup otherwise
+ */
+ s = splhigh();
+
+ ppc->ppc_dmastat = PPC_DMA_INIT;
+
+ /* enable interrupts */
+ ecr &= ~PPC_SERVICE_INTR;
+ ppc->ppc_irqstat = PPC_IRQ_DMA;
+ w_ecr(ppc, ecr);
+
+ isa_dmastart(ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt,
+ ppc->ppc_dmachan);
+ ppc->ppc_dmastat = PPC_DMA_STARTED;
+
+#ifdef PPC_DEBUG
+ printf("s%d", ppc->ppc_dmacnt);
+#endif
+
+ /* Wait for the DMA completed interrupt. We hope we won't
+ * miss it, otherwise a signal will be necessary to unlock the
+ * process.
+ */
+ do {
+ /* release CPU */
+ error = tsleep(ppc, PPBPRI | PCATCH, "ppcdma", 0);
+ } while (error == EWOULDBLOCK);
+
+ splx(s);
+
+ if (error) {
+#ifdef PPC_DEBUG
+ printf("i");
+#endif
+ /* stop DMA */
+ isa_dmadone(ppc->ppc_dmaflags, ppc->ppc_dmaddr,
+ ppc->ppc_dmacnt, ppc->ppc_dmachan);
+
+ /* no dma, no interrupt, flush the fifo */
+ w_ecr(ppc, PPC_ECR_RESET);
+
+ ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
+ goto error;
+ }
+
+ /* wait for an empty fifo */
+ while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
+
+ for (spin=100; spin; spin--)
+ if (r_ecr(ppc) & PPC_FIFO_EMPTY)
+ goto fifo_empty;
+#ifdef PPC_DEBUG
+ printf("Z");
+#endif
+ error = tsleep(ppc, PPBPRI | PCATCH, "ppcfifo", hz/100);
+ if (error != EWOULDBLOCK) {
+#ifdef PPC_DEBUG
+ printf("I");
+#endif
+ /* no dma, no interrupt, flush the fifo */
+ w_ecr(ppc, PPC_ECR_RESET);
+
+ ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
+ error = EINTR;
+ goto error;
+ }
+ }
+
+fifo_empty:
+ /* no dma, no interrupt, flush the fifo */
+ w_ecr(ppc, PPC_ECR_RESET);
+
+error:
+ /* PDRQ must be kept unasserted until nPDACK is
+ * deasserted for a minimum of 350ns (SMC datasheet)
+ *
+ * Consequence may be a FIFO that never empty
+ */
+ DELAY(1);
+
+ w_ecr(ppc, ecr_sav);
+ w_ctr(ppc, ctr_sav);
+ return (error);
+}
+
+DRIVER_MODULE(ppc, isa, ppc_isa_driver, ppc_devclass, 0, 0);
diff --git a/sys/dev/ppc/ppc_pci.c b/sys/dev/ppc/ppc_pci.c
new file mode 100644
index 0000000..77331e2
--- /dev/null
+++ b/sys/dev/ppc/ppc_pci.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_msq.h>
+#include <dev/ppc/ppcvar.h>
+#include <dev/ppc/ppcreg.h>
+
+#include "ppbus_if.h"
+
+static int ppc_pci_probe(device_t dev);
+
+static device_method_t ppc_pci_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ppc_pci_probe),
+ DEVMETHOD(device_attach, ppc_attach),
+ DEVMETHOD(device_detach, ppc_detach),
+
+ /* bus interface */
+ DEVMETHOD(bus_read_ivar, ppc_read_ivar),
+ DEVMETHOD(bus_setup_intr, ppc_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+
+ /* ppbus interface */
+ DEVMETHOD(ppbus_io, ppc_io),
+ DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq),
+ DEVMETHOD(ppbus_reset_epp, ppc_reset_epp),
+ DEVMETHOD(ppbus_setmode, ppc_setmode),
+ DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync),
+ DEVMETHOD(ppbus_read, ppc_read),
+ DEVMETHOD(ppbus_write, ppc_write),
+
+ { 0, 0 }
+};
+
+static driver_t ppc_pci_driver = {
+ ppc_driver_name,
+ ppc_pci_methods,
+ sizeof(struct ppc_data),
+};
+
+struct pci_id {
+ uint32_t type;
+ const char *desc;
+ int rid;
+};
+
+static struct pci_id pci_ids[] = {
+ { 0x1020131f, "SIIG Cyber Parallel PCI (10x family)", 0x18 },
+ { 0x2020131f, "SIIG Cyber Parallel PCI (20x family)", 0x10 },
+ { 0x80001407, "Lava Computers 2SP-PCI parallel port", 0x10 },
+ { 0x84031415, "Oxford Semiconductor OX12PCI840 Parallel port", 0x10 },
+ { 0x95131415, "Oxford Semiconductor OX16PCI954 Parallel port", 0x10 },
+ { 0x98059710, "NetMos NM9805 1284 Printer port", 0x10 },
+ { 0xffff }
+};
+
+static int
+ppc_pci_probe(device_t dev)
+{
+ struct pci_id *id;
+ uint32_t type;
+
+ type = pci_get_devid(dev);
+ id = pci_ids;
+ while (id->type != 0xffff && id->type != type)
+ id++;
+ if (id->type == 0xffff)
+ return (ENXIO);
+ device_set_desc(dev, id->desc);
+ return (ppc_probe(dev, id->rid));
+}
+
+DRIVER_MODULE(ppc, pci, ppc_pci_driver, ppc_devclass, 0, 0);
diff --git a/sys/dev/ppc/ppc_puc.c b/sys/dev/ppc/ppc_puc.c
index 2b41bfe..760b1ce 100644
--- a/sys/dev/ppc/ppc_puc.c
+++ b/sys/dev/ppc/ppc_puc.c
@@ -68,7 +68,7 @@ static device_method_t ppc_puc_methods[] = {
};
static driver_t ppc_puc_driver = {
- "ppc",
+ ppc_driver_name,
ppc_puc_methods,
sizeof(struct ppc_data),
};
@@ -78,7 +78,7 @@ ppc_puc_probe(dev)
device_t dev;
{
device_set_desc(dev, "Parallel port");
- return (ppc_probe(dev));
+ return (ppc_probe(dev, 0));
}
DRIVER_MODULE(ppc, puc, ppc_puc_driver, ppc_devclass, 0, 0);
diff --git a/sys/dev/ppc/ppcreg.h b/sys/dev/ppc/ppcreg.h
index ea12ead..6b26ed9 100644
--- a/sys/dev/ppc/ppcreg.h
+++ b/sys/dev/ppc/ppcreg.h
@@ -82,6 +82,7 @@ struct ppc_data {
int ppc_dmaflags; /* dma transfer flags */
caddr_t ppc_dmaddr; /* buffer address */
u_int ppc_dmacnt; /* count of bytes sent with dma */
+ void (*ppc_dmadone)(struct ppc_data*);
#define PPC_PWORD_MASK 0x30
#define PPC_PWORD_16 0x00
@@ -123,10 +124,18 @@ struct ppc_data {
#define PPC_SPP_CTR 2 /* SPP control register */
#define PPC_EPP_ADDR 3 /* EPP address register (8 bit) */
#define PPC_EPP_DATA 4 /* EPP data register (8, 16 or 32 bit) */
+#if defined(__i386__) && defined(PC98)
+#define PPC_1284_ENABLE 0x09 /* IEEE STD 1284 Enable register */
+#define PPC_ECP_D_FIFO 0x0c /* ECP Data fifo register */
+#define PPC_ECP_CNFGA 0x0c /* Configuration register A */
+#define PPC_ECP_CNFGB 0x0d /* Configuration register B */
+#define PPC_ECP_ECR 0x0e /* ECP extended control register */
+#else
#define PPC_ECP_D_FIFO 0x400 /* ECP Data fifo register */
#define PPC_ECP_CNFGA 0x400 /* Configuration register A */
#define PPC_ECP_CNFGB 0x401 /* Configuration register B */
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
+#endif
#define PPC_FIFO_EMPTY 0x1 /* ecr register - bit 0 */
#define PPC_FIFO_FULL 0x2 /* ecr register - bit 1 */
diff --git a/sys/dev/ppc/ppcvar.h b/sys/dev/ppc/ppcvar.h
index 98bc022..b7d1643 100644
--- a/sys/dev/ppc/ppcvar.h
+++ b/sys/dev/ppc/ppcvar.h
@@ -28,7 +28,7 @@
*
*/
-int ppc_probe(device_t dev);
+int ppc_probe(device_t dev, int rid);
int ppc_attach(device_t dev);
int ppc_detach(device_t dev);
int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val);
@@ -46,4 +46,5 @@ void ppc_reset_epp(device_t);
void ppc_ecp_sync(device_t);
int ppc_setmode(device_t, int);
-extern devclass_t ppc_devclass;
+extern devclass_t ppc_devclass;
+extern const char ppc_driver_name[];
OpenPOWER on IntegriCloud