diff options
author | marcel <marcel@FreeBSD.org> | 2006-04-24 23:31:51 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2006-04-24 23:31:51 +0000 |
commit | deb16135f3fca75d654b5678f9f331af783b6d6b (patch) | |
tree | 4c14a9bedc4bcdbb3fbd46089cf47c3af3cc2de1 | |
parent | eefd58df920bd36d125e2f8e0db44d74e8859b3a (diff) | |
download | FreeBSD-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.
-rw-r--r-- | sys/conf/files | 5 | ||||
-rw-r--r-- | sys/conf/files.alpha | 2 | ||||
-rw-r--r-- | sys/conf/files.amd64 | 2 | ||||
-rw-r--r-- | sys/conf/files.i386 | 2 | ||||
-rw-r--r-- | sys/conf/files.ia64 | 2 | ||||
-rw-r--r-- | sys/conf/files.pc98 | 2 | ||||
-rw-r--r-- | sys/conf/files.powerpc | 1 | ||||
-rw-r--r-- | sys/conf/options | 2 | ||||
-rw-r--r-- | sys/conf/options.alpha | 3 | ||||
-rw-r--r-- | sys/conf/options.amd64 | 2 | ||||
-rw-r--r-- | sys/conf/options.i386 | 2 | ||||
-rw-r--r-- | sys/conf/options.ia64 | 3 | ||||
-rw-r--r-- | sys/conf/options.pc98 | 2 | ||||
-rw-r--r-- | sys/dev/ppc/ppc.c | 302 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_acpi.c | 114 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_isa.c | 281 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_pci.c | 110 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_puc.c | 4 | ||||
-rw-r--r-- | sys/dev/ppc/ppcreg.h | 9 | ||||
-rw-r--r-- | sys/dev/ppc/ppcvar.h | 5 | ||||
-rw-r--r-- | sys/pc98/cbus/ppc.c | 2211 | ||||
-rw-r--r-- | sys/pc98/cbus/ppcreg.h | 280 |
22 files changed, 593 insertions, 2753 deletions
diff --git a/sys/conf/files b/sys/conf/files index ecaa657..5b9c4a0 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -796,6 +796,11 @@ dev/ppbus/ppi.c optional ppi dev/ppbus/pps.c optional pps dev/ppbus/vpo.c optional vpo dev/ppbus/vpoio.c optional vpo +dev/ppc/ppc.c optional ppc +dev/ppc/ppc_acpi.c optional ppc acpi +dev/ppc/ppc_isa.c optional ppc isa +dev/ppc/ppc_pci.c optional ppc pci +dev/ppc/ppc_puc.c optional ppc puc dev/pst/pst-iop.c optional pst dev/pst/pst-pci.c optional pst pci dev/pst/pst-raid.c optional pst diff --git a/sys/conf/files.alpha b/sys/conf/files.alpha index 0ee8668..3913a07 100644 --- a/sys/conf/files.alpha +++ b/sys/conf/files.alpha @@ -179,8 +179,6 @@ dev/fdc/fdc.c optional fdc dev/fdc/fdc_isa.c optional fdc isa dev/hwpmc/hwpmc_alpha.c optional hwpmc dev/kbd/kbd.c optional atkbd | sc | ukbd -dev/ppc/ppc.c optional ppc -dev/ppc/ppc_puc.c optional ppc puc dev/sio/sio.c optional sio dev/sio/sio_isa.c optional sio isa dev/syscons/schistory.c optional sc diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index ffa6f74..6898140 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -174,8 +174,6 @@ dev/hwpmc/hwpmc_x86.c optional hwpmc dev/kbd/kbd.c optional atkbd | sc | ukbd dev/mem/memutil.c optional mem dev/nve/if_nve.c optional nve pci -dev/ppc/ppc.c optional ppc -dev/ppc/ppc_puc.c optional ppc puc dev/sio/sio.c optional sio dev/sio/sio_isa.c optional sio isa dev/speaker/spkr.c optional speaker diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index b51b2cd..5d09990 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -193,8 +193,6 @@ dev/mse/mse.c optional mse dev/mse/mse_isa.c optional mse isa dev/nve/if_nve.c optional nve pci dev/pcf/pcf_isa.c optional pcf -dev/ppc/ppc.c optional ppc -dev/ppc/ppc_puc.c optional ppc puc pci dev/random/nehemiah.c optional random dev/sbni/if_sbni.c optional sbni dev/sbni/if_sbni_isa.c optional sbni isa diff --git a/sys/conf/files.ia64 b/sys/conf/files.ia64 index 42285f9..9683af4 100644 --- a/sys/conf/files.ia64 +++ b/sys/conf/files.ia64 @@ -58,8 +58,6 @@ dev/fb/splash.c optional splash dev/fb/vga.c optional vga dev/hwpmc/hwpmc_ia64.c optional hwpmc dev/kbd/kbd.c optional atkbd | sc | ukbd -dev/ppc/ppc.c optional ppc isa -dev/ppc/ppc_puc.c optional ppc puc dev/syscons/schistory.c optional sc dev/syscons/scmouse.c optional sc dev/syscons/scterm-dumb.c optional sc diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 9dfbc6b..3d90ede 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -110,7 +110,6 @@ dev/lnc/if_lnc_cbus.c optional lnc isa dev/mem/memutil.c optional mem dev/mse/mse.c optional mse dev/mse/mse_cbus.c optional mse isa -dev/ppc/ppc_puc.c optional ppc puc pci dev/sbni/if_sbni.c optional sbni dev/sbni/if_sbni_pci.c optional sbni pci dev/snc/dp83932.c optional snc @@ -318,7 +317,6 @@ pc98/cbus/nmi.c standard pc98/cbus/olpt.c optional olpt pc98/cbus/pckbd.c optional pckbd pc98/cbus/pmc.c optional pmc -pc98/cbus/ppc.c optional ppc pc98/cbus/scgdcrndr.c optional sc gdc pc98/cbus/scterm-sck.c optional sc pc98/cbus/scvtb.c optional sc diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index ee0e0bb..b84aed8 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -41,6 +41,7 @@ powerpc/powerpc/cpu.c standard powerpc/powerpc/elf_machdep.c standard powerpc/powerpc/fpu.c standard powerpc/powerpc/fuswintr.c standard +powerpc/powerpc/gdb_machdep.c optional gdb powerpc/powerpc/in_cksum.c optional inet powerpc/powerpc/interrupt.c standard powerpc/powerpc/intr_machdep.c standard diff --git a/sys/conf/options b/sys/conf/options index dd264e8..ef1664d 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -121,6 +121,8 @@ MPROF_HASH_SIZE opt_mprof.h MUTEX_WAKE_ALL NSWBUF_MIN opt_swap.h PANIC_REBOOT_WAIT_TIME opt_panic.h +PPC_DEBUG opt_ppc.h +PPC_PROBE_CHIPSET opt_ppc.h PPS_SYNC opt_ntp.h PREEMPTION opt_sched.h PUC_FASTINTR opt_puc.h diff --git a/sys/conf/options.alpha b/sys/conf/options.alpha index d1aaf8d..1b5ea9c 100644 --- a/sys/conf/options.alpha +++ b/sys/conf/options.alpha @@ -18,9 +18,6 @@ API_UP1000 opt_cpu.h MAXMEM -PPC_PROBE_CHIPSET opt_ppc.h -PPC_DEBUG opt_ppc.h - VGA_ALT_SEQACCESS opt_vga.h VGA_DEBUG opt_vga.h VGA_NO_FONT_LOADING opt_vga.h diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64 index 14e3bc1..5415118 100644 --- a/sys/conf/options.amd64 +++ b/sys/conf/options.amd64 @@ -49,8 +49,6 @@ IPR_LOG opt_i4b.h # EOF # ------------------------------- HAMMER opt_cpu.h -PPC_PROBE_CHIPSET opt_ppc.h -PPC_DEBUG opt_ppc.h PSM_HOOKRESUME opt_psm.h PSM_RESETAFTERSUSPEND opt_psm.h PSM_DEBUG opt_psm.h diff --git a/sys/conf/options.i386 b/sys/conf/options.i386 index f21938d..4d2484b 100644 --- a/sys/conf/options.i386 +++ b/sys/conf/options.i386 @@ -15,8 +15,6 @@ MP_WATCHDOG PERFMON PMAP_SHPGPERPROC opt_pmap.h POWERFAIL_NMI opt_trap.h -PPC_DEBUG opt_ppc.h -PPC_PROBE_CHIPSET opt_ppc.h # Options for emulators. These should only be used at config time, so # they are handled like options for static filesystems diff --git a/sys/conf/options.ia64 b/sys/conf/options.ia64 index 8f4b2ac..4defd69 100644 --- a/sys/conf/options.ia64 +++ b/sys/conf/options.ia64 @@ -11,9 +11,6 @@ UWX_TRACE_ENABLE opt_global.h COMPAT_IA32 opt_compat.h -PPC_PROBE_CHIPSET opt_ppc.h -PPC_DEBUG opt_ppc.h - VGA_ALT_SEQACCESS opt_vga.h VGA_DEBUG opt_vga.h VGA_NO_FONT_LOADING opt_vga.h diff --git a/sys/conf/options.pc98 b/sys/conf/options.pc98 index 6134338..f6f6c95 100644 --- a/sys/conf/options.pc98 +++ b/sys/conf/options.pc98 @@ -14,8 +14,6 @@ MP_WATCHDOG PERFMON PMAP_SHPGPERPROC opt_pmap.h POWERFAIL_NMI opt_trap.h -PPC_DEBUG opt_ppc.h -PPC_PROBE_CHIPSET opt_ppc.h # Options for emulators. These should only be used at config time, so # they are handled like options for static filesystems 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[]; diff --git a/sys/pc98/cbus/ppc.c b/sys/pc98/cbus/ppc.c deleted file mode 100644 index 2989eed..0000000 --- a/sys/pc98/cbus/ppc.c +++ /dev/null @@ -1,2211 +0,0 @@ -/*- - * Copyright (c) 2001 Alcove - Nicolas Souchu - * 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. - * - * $FreeBSD$ - * - */ - -#include "opt_ppc.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> - -#include <vm/vm.h> -#include <vm/pmap.h> -#include <machine/bus.h> -#include <machine/resource.h> -#include <machine/vmparam.h> -#include <sys/rman.h> - -#ifdef 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> -#ifdef PC98 -#include <pc98/cbus/ppcreg.h> -#else -#include <dev/ppc/ppcreg.h> -#endif - -#include "ppbus_if.h" - -static int ppc_cbus_probe(device_t dev); - -static void ppcintr(void *arg); - -#define LOG_PPC(function, ppc, string) \ - if (bootverbose) printf("%s: %s\n", function, string) - - -#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_cbus_probe), - DEVMETHOD(device_attach, 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_write), - - { 0, 0 } - }; - -static driver_t ppc_driver = { - "ppc", - ppc_methods, - sizeof(struct ppc_data), -}; - -static char *ppc_models[] = { - "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", - "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", - "SMC FDC37C935", "PC87303", 0 -}; - -/* list of available modes */ -static char *ppc_avms[] = { - "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", - "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", - "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", - "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 -}; - -/* list of current executing modes - * Note that few modes do not actually exist. - */ -static char *ppc_modes[] = { - "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", - "EPP", "EPP", "EPP", "ECP", - "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", - "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 -}; - -static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; - -#ifdef __i386__ -/* - * BIOS printer list - used by BIOS probe. - */ -#define BIOS_PPC_PORTS 0x408 -#define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) -#define BIOS_MAX_PPC 4 -#endif - -/* - * ppc_ecp_sync() XXX - */ -void -ppc_ecp_sync(device_t dev) { - - int i, r; - struct ppc_data *ppc = DEVTOSOFTC(dev); - - if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) - return; - - r = r_ecr(ppc); - if ((r & 0xe0) != PPC_ECR_EPP) - return; - - for (i = 0; i < 100; i++) { - r = r_ecr(ppc); - if (r & 0x1) - return; - DELAY(100); - } - - printf("ppc%d: ECP sync failed as data still " \ - "present in FIFO.\n", ppc->ppc_unit); - - return; -} - -/* - * ppc_detect_fifo() - * - * Detect parallel port FIFO - */ -static int -ppc_detect_fifo(struct ppc_data *ppc) -{ - char ecr_sav; - char ctr_sav, ctr, cc; - short i; - - /* save registers */ - ecr_sav = r_ecr(ppc); - ctr_sav = r_ctr(ppc); - - /* enter ECP configuration mode, no interrupt, no DMA */ - w_ecr(ppc, 0xf4); - - /* read PWord size - transfers in FIFO mode must be PWord aligned */ - ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); - - /* XXX 16 and 32 bits implementations not supported */ - if (ppc->ppc_pword != PPC_PWORD_8) { - LOG_PPC(__func__, ppc, "PWord not supported"); - goto error; - } - - w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ - ctr = r_ctr(ppc); - w_ctr(ppc, ctr | PCD); /* set direction to 1 */ - - /* enter ECP test mode, no interrupt, no DMA */ - w_ecr(ppc, 0xd4); - - /* flush the FIFO */ - for (i=0; i<1024; i++) { - if (r_ecr(ppc) & PPC_FIFO_EMPTY) - break; - cc = r_fifo(ppc); - } - - if (i >= 1024) { - LOG_PPC(__func__, ppc, "can't flush FIFO"); - goto error; - } - - /* enable interrupts, no DMA */ - w_ecr(ppc, 0xd0); - - /* determine readIntrThreshold - * fill the FIFO until serviceIntr is set - */ - for (i=0; i<1024; i++) { - w_fifo(ppc, (char)i); - if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { - /* readThreshold reached */ - ppc->ppc_rthr = i+1; - } - if (r_ecr(ppc) & PPC_FIFO_FULL) { - ppc->ppc_fifo = i+1; - break; - } - } - - if (i >= 1024) { - LOG_PPC(__func__, ppc, "can't fill FIFO"); - goto error; - } - - w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ - w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ - w_ecr(ppc, 0xd0); /* enable interrupts */ - - /* determine writeIntrThreshold - * empty the FIFO until serviceIntr is set - */ - for (i=ppc->ppc_fifo; i>0; i--) { - if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { - LOG_PPC(__func__, ppc, "invalid data in FIFO"); - goto error; - } - if (r_ecr(ppc) & PPC_SERVICE_INTR) { - /* writeIntrThreshold reached */ - ppc->ppc_wthr = ppc->ppc_fifo - i+1; - } - /* if FIFO empty before the last byte, error */ - if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { - LOG_PPC(__func__, ppc, "data lost in FIFO"); - goto error; - } - } - - /* FIFO must be empty after the last byte */ - if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { - LOG_PPC(__func__, ppc, "can't empty the FIFO"); - goto error; - } - - w_ctr(ppc, ctr_sav); - w_ecr(ppc, ecr_sav); - - return (0); - -error: - w_ctr(ppc, ctr_sav); - w_ecr(ppc, ecr_sav); - - return (EINVAL); -} - -static int -ppc_detect_port(struct ppc_data *ppc) -{ - - w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ - w_dtr(ppc, 0xaa); - if (r_dtr(ppc) != 0xaa) - return (0); - - return (1); -} - -/* - * EPP timeout, according to the PC87332 manual - * Semantics of clearing EPP timeout bit. - * PC87332 - reading SPP_STR does it... - * SMC - write 1 to EPP timeout bit XXX - * Others - (?) write 0 to EPP timeout bit - */ -static void -ppc_reset_epp_timeout(struct ppc_data *ppc) -{ - register char r; - - r = r_str(ppc); - w_str(ppc, r | 0x1); - w_str(ppc, r & 0xfe); - - return; -} - -static int -ppc_check_epp_timeout(struct ppc_data *ppc) -{ - ppc_reset_epp_timeout(ppc); - - return (!(r_str(ppc) & TIMEOUT)); -} - -/* - * Configure current operating mode - */ -static int -ppc_generic_setmode(struct ppc_data *ppc, int mode) -{ - u_char ecr = 0; - - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); - - /* if ECP mode, configure ecr register */ - if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { - /* return to byte mode (keeping direction bit), - * no interrupt, no DMA to be able to change to - * ECP - */ - w_ecr(ppc, PPC_ECR_RESET); - ecr = PPC_DISABLE_INTR; - - if (mode & PPB_EPP) - return (EINVAL); - else if (mode & PPB_ECP) - /* select ECP mode */ - ecr |= PPC_ECR_ECP; - else if (mode & PPB_PS2) - /* select PS2 mode with ECP */ - ecr |= PPC_ECR_PS2; - else - /* select COMPATIBLE/NIBBLE mode */ - ecr |= PPC_ECR_STD; - - w_ecr(ppc, ecr); - } - - ppc->ppc_mode = mode; - - return (0); -} - -/* - * The ppc driver is free to choose options like FIFO or DMA - * if ECP mode is available. - * - * The 'RAW' option allows the upper drivers to force the ppc mode - * even with FIFO, DMA available. - */ -static int -ppc_smclike_setmode(struct ppc_data *ppc, int mode) -{ - u_char ecr = 0; - - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); - - /* if ECP mode, configure ecr register */ - if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { - /* return to byte mode (keeping direction bit), - * no interrupt, no DMA to be able to change to - * ECP or EPP mode - */ - w_ecr(ppc, PPC_ECR_RESET); - ecr = PPC_DISABLE_INTR; - - if (mode & PPB_EPP) - /* select EPP mode */ - ecr |= PPC_ECR_EPP; - else if (mode & PPB_ECP) - /* select ECP mode */ - ecr |= PPC_ECR_ECP; - else if (mode & PPB_PS2) - /* select PS2 mode with ECP */ - ecr |= PPC_ECR_PS2; - else - /* select COMPATIBLE/NIBBLE mode */ - ecr |= PPC_ECR_STD; - - w_ecr(ppc, ecr); - } - - ppc->ppc_mode = mode; - - return (0); -} - -#ifdef PPC_PROBE_CHIPSET -/* - * ppc_pc873xx_detect - * - * Probe for a Natsemi PC873xx-family part. - * - * References in this function are to the National Semiconductor - * PC87332 datasheet TL/C/11930, May 1995 revision. - */ -static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; -static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; -static int pc873xx_irqtab[] = {5, 7, 5, 0}; - -static int pc873xx_regstab[] = { - PC873_FER, PC873_FAR, PC873_PTR, - PC873_FCR, PC873_PCR, PC873_PMC, - PC873_TUP, PC873_SID, PC873_PNP0, - PC873_PNP1, PC873_LPTBA, -1 -}; - -static char *pc873xx_rnametab[] = { - "FER", "FAR", "PTR", "FCR", "PCR", - "PMC", "TUP", "SID", "PNP0", "PNP1", - "LPTBA", NULL -}; - -static int -ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ -{ - static int index = 0; - int idport, irq; - int ptr, pcr, val, i; - - while ((idport = pc873xx_basetab[index++])) { - - /* XXX should check first to see if this location is already claimed */ - - /* - * Pull the 873xx through the power-on ID cycle (2.2,1.). - * We can't use this to locate the chip as it may already have - * been used by the BIOS. - */ - (void)inb(idport); (void)inb(idport); - (void)inb(idport); (void)inb(idport); - - /* - * Read the SID byte. Possible values are : - * - * 01010xxx PC87334 - * 0001xxxx PC87332 - * 01110xxx PC87306 - * 00110xxx PC87303 - */ - outb(idport, PC873_SID); - val = inb(idport + 1); - if ((val & 0xf0) == 0x10) { - ppc->ppc_model = NS_PC87332; - } else if ((val & 0xf8) == 0x70) { - ppc->ppc_model = NS_PC87306; - } else if ((val & 0xf8) == 0x50) { - ppc->ppc_model = NS_PC87334; - } else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the - documentation, but probing - yielded 0x40... */ - ppc->ppc_model = NS_PC87303; - } else { - if (bootverbose && (val != 0xff)) - printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); - continue ; /* not recognised */ - } - - /* print registers */ - if (bootverbose) { - printf("PC873xx"); - for (i=0; pc873xx_regstab[i] != -1; i++) { - outb(idport, pc873xx_regstab[i]); - printf(" %s=0x%x", pc873xx_rnametab[i], - inb(idport + 1) & 0xff); - } - printf("\n"); - } - - /* - * We think we have one. Is it enabled and where we want it to be? - */ - outb(idport, PC873_FER); - val = inb(idport + 1); - if (!(val & PC873_PPENABLE)) { - if (bootverbose) - printf("PC873xx parallel port disabled\n"); - continue; - } - outb(idport, PC873_FAR); - val = inb(idport + 1); - /* XXX we should create a driver instance for every port found */ - if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) { - - /* First try to change the port address to that requested... */ - - switch(ppc->ppc_base) { - case 0x378: - val &= 0xfc; - break; - - case 0x3bc: - val &= 0xfd; - break; - - case 0x278: - val &= 0xfe; - break; - - default: - val &= 0xfd; - break; - } - - outb(idport, PC873_FAR); - outb(idport + 1, val); - outb(idport + 1, val); - - /* Check for success by reading back the value we supposedly - wrote and comparing...*/ - - outb(idport, PC873_FAR); - val = inb(idport + 1) & 0x3; - - /* If we fail, report the failure... */ - - if (pc873xx_porttab[val] != ppc->ppc_base) { - if (bootverbose) - printf("PC873xx at 0x%x not for driver at port 0x%x\n", - pc873xx_porttab[val], ppc->ppc_base); - } - continue; - } - - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - - /* get irq settings */ - if (ppc->ppc_base == 0x378) - irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; - else - irq = pc873xx_irqtab[val]; - - if (bootverbose) - printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); - - /* - * Check if irq settings are correct - */ - if (irq != ppc->ppc_irq) { - /* - * If the chipset is not locked and base address is 0x378, - * we have another chance - */ - if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { - if (ppc->ppc_irq == 7) { - outb(idport + 1, (ptr | PC873_LPTBIRQ7)); - outb(idport + 1, (ptr | PC873_LPTBIRQ7)); - } else { - outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); - outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); - } - if (bootverbose) - printf("PC873xx irq set to %d\n", ppc->ppc_irq); - } else { - if (bootverbose) - printf("PC873xx sorry, can't change irq setting\n"); - } - } else { - if (bootverbose) - printf("PC873xx irq settings are correct\n"); - } - - outb(idport, PC873_PCR); - pcr = inb(idport + 1); - - if ((ptr & PC873_CFGLOCK) || !chipset_mode) { - if (bootverbose) - printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); - - ppc->ppc_avm |= PPB_NIBBLE; - if (bootverbose) - printf(", NIBBLE"); - - if (pcr & PC873_EPPEN) { - ppc->ppc_avm |= PPB_EPP; - - if (bootverbose) - printf(", EPP"); - - if (pcr & PC873_EPP19) - ppc->ppc_epp = EPP_1_9; - else - ppc->ppc_epp = EPP_1_7; - - if ((ppc->ppc_model == NS_PC87332) && bootverbose) { - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - if (ptr & PC873_EPPRDIR) - printf(", Regular mode"); - else - printf(", Automatic mode"); - } - } else if (pcr & PC873_ECPEN) { - ppc->ppc_avm |= PPB_ECP; - if (bootverbose) - printf(", ECP"); - - if (pcr & PC873_ECPCLK) { /* XXX */ - ppc->ppc_avm |= PPB_PS2; - if (bootverbose) - printf(", PS/2"); - } - } else { - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - if (ptr & PC873_EXTENDED) { - ppc->ppc_avm |= PPB_SPP; - if (bootverbose) - printf(", SPP"); - } - } - } else { - if (bootverbose) - printf("PC873xx unlocked"); - - if (chipset_mode & PPB_ECP) { - if ((chipset_mode & PPB_EPP) && bootverbose) - printf(", ECP+EPP not supported"); - - pcr &= ~PC873_EPPEN; - pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ - outb(idport + 1, pcr); - outb(idport + 1, pcr); - - if (bootverbose) - printf(", ECP"); - - } else if (chipset_mode & PPB_EPP) { - pcr &= ~(PC873_ECPEN | PC873_ECPCLK); - pcr |= (PC873_EPPEN | PC873_EPP19); - outb(idport + 1, pcr); - outb(idport + 1, pcr); - - ppc->ppc_epp = EPP_1_9; /* XXX */ - - if (bootverbose) - printf(", EPP1.9"); - - /* enable automatic direction turnover */ - if (ppc->ppc_model == NS_PC87332) { - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - ptr &= ~PC873_EPPRDIR; - outb(idport + 1, ptr); - outb(idport + 1, ptr); - - if (bootverbose) - printf(", Automatic mode"); - } - } else { - pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); - outb(idport + 1, pcr); - outb(idport + 1, pcr); - - /* configure extended bit in PTR */ - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - - if (chipset_mode & PPB_PS2) { - ptr |= PC873_EXTENDED; - - if (bootverbose) - printf(", PS/2"); - - } else { - /* default to NIBBLE mode */ - ptr &= ~PC873_EXTENDED; - - if (bootverbose) - printf(", NIBBLE"); - } - outb(idport + 1, ptr); - outb(idport + 1, ptr); - } - - ppc->ppc_avm = chipset_mode; - } - - if (bootverbose) - printf("\n"); - - ppc->ppc_type = PPC_TYPE_GENERIC; - ppc_generic_setmode(ppc, chipset_mode); - - return(chipset_mode); - } - return(-1); -} - -/* - * ppc_smc37c66xgt_detect - * - * SMC FDC37C66xGT configuration. - */ -static int -ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) -{ - int s, i; - u_char r; - int type = -1; - int csr = SMC66x_CSR; /* initial value is 0x3F0 */ - - int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; - - -#define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ - - /* - * Detection: enter configuration mode and read CRD register. - */ - - s = splhigh(); - outb(csr, SMC665_iCODE); - outb(csr, SMC665_iCODE); - splx(s); - - outb(csr, 0xd); - if (inb(cio) == 0x65) { - type = SMC_37C665GT; - goto config; - } - - for (i = 0; i < 2; i++) { - s = splhigh(); - outb(csr, SMC666_iCODE); - outb(csr, SMC666_iCODE); - splx(s); - - outb(csr, 0xd); - if (inb(cio) == 0x66) { - type = SMC_37C666GT; - break; - } - - /* Another chance, CSR may be hard-configured to be at 0x370 */ - csr = SMC666_CSR; - } - -config: - /* - * If chipset not found, do not continue. - */ - if (type == -1) - return (-1); - - /* select CR1 */ - outb(csr, 0x1); - - /* read the port's address: bits 0 and 1 of CR1 */ - r = inb(cio) & SMC_CR1_ADDR; - if (port_address[(int)r] != ppc->ppc_base) - return (-1); - - ppc->ppc_model = type; - - /* - * CR1 and CR4 registers bits 3 and 0/1 for mode configuration - * If SPP mode is detected, try to set ECP+EPP mode - */ - - if (bootverbose) { - outb(csr, 0x1); - printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, - inb(cio) & 0xff); - - outb(csr, 0x4); - printf(" CR4=0x%x", inb(cio) & 0xff); - } - - /* select CR1 */ - outb(csr, 0x1); - - if (!chipset_mode) { - /* autodetect mode */ - - /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ - if (type == SMC_37C666GT) { - ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" configuration hardwired, supposing " \ - "ECP+EPP SPP"); - - } else - if ((inb(cio) & SMC_CR1_MODE) == 0) { - /* already in extended parallel port mode, read CR4 */ - outb(csr, 0x4); - r = (inb(cio) & SMC_CR4_EMODE); - - switch (r) { - case SMC_SPP: - ppc->ppc_avm |= PPB_SPP; - if (bootverbose) - printf(" SPP"); - break; - - case SMC_EPPSPP: - ppc->ppc_avm |= PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" EPP SPP"); - break; - - case SMC_ECP: - ppc->ppc_avm |= PPB_ECP | PPB_SPP; - if (bootverbose) - printf(" ECP SPP"); - break; - - case SMC_ECPEPP: - ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" ECP+EPP SPP"); - break; - } - } else { - /* not an extended port mode */ - ppc->ppc_avm |= PPB_SPP; - if (bootverbose) - printf(" SPP"); - } - - } else { - /* mode forced */ - ppc->ppc_avm = chipset_mode; - - /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ - if (type == SMC_37C666GT) - goto end_detect; - - r = inb(cio); - if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { - /* do not use ECP when the mode is not forced to */ - outb(cio, r | SMC_CR1_MODE); - if (bootverbose) - printf(" SPP"); - } else { - /* an extended mode is selected */ - outb(cio, r & ~SMC_CR1_MODE); - - /* read CR4 register and reset mode field */ - outb(csr, 0x4); - r = inb(cio) & ~SMC_CR4_EMODE; - - if (chipset_mode & PPB_ECP) { - if (chipset_mode & PPB_EPP) { - outb(cio, r | SMC_ECPEPP); - if (bootverbose) - printf(" ECP+EPP"); - } else { - outb(cio, r | SMC_ECP); - if (bootverbose) - printf(" ECP"); - } - } else { - /* PPB_EPP is set */ - outb(cio, r | SMC_EPPSPP); - if (bootverbose) - printf(" EPP SPP"); - } - } - ppc->ppc_avm = chipset_mode; - } - - /* set FIFO threshold to 16 */ - if (ppc->ppc_avm & PPB_ECP) { - /* select CRA */ - outb(csr, 0xa); - outb(cio, 16); - } - -end_detect: - - if (bootverbose) - printf ("\n"); - - if (ppc->ppc_avm & PPB_EPP) { - /* select CR4 */ - outb(csr, 0x4); - r = inb(cio); - - /* - * Set the EPP protocol... - * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 - */ - if (ppc->ppc_epp == EPP_1_9) - outb(cio, (r & ~SMC_CR4_EPPTYPE)); - else - outb(cio, (r | SMC_CR4_EPPTYPE)); - } - - /* end config mode */ - outb(csr, 0xaa); - - ppc->ppc_type = PPC_TYPE_SMCLIKE; - ppc_smclike_setmode(ppc, chipset_mode); - - return (chipset_mode); -} - -/* - * SMC FDC37C935 configuration - * Found on many Alpha machines - */ -static int -ppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode) -{ - int s; - int type = -1; - - s = splhigh(); - outb(SMC935_CFG, 0x55); /* enter config mode */ - outb(SMC935_CFG, 0x55); - splx(s); - - outb(SMC935_IND, SMC935_ID); /* check device id */ - if (inb(SMC935_DAT) == 0x2) - type = SMC_37C935; - - if (type == -1) { - outb(SMC935_CFG, 0xaa); /* exit config mode */ - return (-1); - } - - ppc->ppc_model = type; - - outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */ - outb(SMC935_DAT, 3); /* which is logical device 3 */ - - /* set io port base */ - outb(SMC935_IND, SMC935_PORTHI); - outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8)); - outb(SMC935_IND, SMC935_PORTLO); - outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff)); - - if (!chipset_mode) - ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */ - else { - ppc->ppc_avm = chipset_mode; - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */ - - /* SPP + EPP or just plain SPP */ - if (chipset_mode & (PPB_SPP)) { - if (chipset_mode & PPB_EPP) { - if (ppc->ppc_epp == EPP_1_9) { - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_EPP19SPP); - } - if (ppc->ppc_epp == EPP_1_7) { - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_EPP17SPP); - } - } else { - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_SPP); - } - } - - /* ECP + EPP or just plain ECP */ - if (chipset_mode & PPB_ECP) { - if (chipset_mode & PPB_EPP) { - if (ppc->ppc_epp == EPP_1_9) { - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_ECPEPP19); - } - if (ppc->ppc_epp == EPP_1_7) { - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_ECPEPP17); - } - } else { - outb(SMC935_IND, SMC935_PPMODE); - outb(SMC935_DAT, SMC935_ECP); - } - } - } - - outb(SMC935_CFG, 0xaa); /* exit config mode */ - - ppc->ppc_type = PPC_TYPE_SMCLIKE; - ppc_smclike_setmode(ppc, chipset_mode); - - return (chipset_mode); -} - -/* - * Winbond W83877F stuff - * - * EFER: extended function enable register - * EFIR: extended function index register - * EFDR: extended function data register - */ -#define efir ((efer == 0x250) ? 0x251 : 0x3f0) -#define efdr ((efer == 0x250) ? 0x252 : 0x3f1) - -static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; -static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; -static int w83877f_keyiter[] = { 1, 2, 2, 1 }; -static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; - -static int -ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) -{ - int i, j, efer; - unsigned char r, hefere, hefras; - - for (i = 0; i < 4; i ++) { - /* first try to enable configuration registers */ - efer = w83877f_efers[i]; - - /* write the key to the EFER */ - for (j = 0; j < w83877f_keyiter[i]; j ++) - outb (efer, w83877f_keys[i]); - - /* then check HEFERE and HEFRAS bits */ - outb (efir, 0x0c); - hefere = inb(efdr) & WINB_HEFERE; - - outb (efir, 0x16); - hefras = inb(efdr) & WINB_HEFRAS; - - /* - * HEFRAS HEFERE - * 0 1 write 89h to 250h (power-on default) - * 1 0 write 86h twice to 3f0h - * 1 1 write 87h twice to 3f0h - * 0 0 write 88h to 250h - */ - if ((hefere | hefras) == w83877f_hefs[i]) - goto found; - } - - return (-1); /* failed */ - -found: - /* check base port address - read from CR23 */ - outb(efir, 0x23); - if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ - return (-1); - - /* read CHIP ID from CR9/bits0-3 */ - outb(efir, 0x9); - - switch (inb(efdr) & WINB_CHIPID) { - case WINB_W83877F_ID: - ppc->ppc_model = WINB_W83877F; - break; - - case WINB_W83877AF_ID: - ppc->ppc_model = WINB_W83877AF; - break; - - default: - ppc->ppc_model = WINB_UNKNOWN; - } - - if (bootverbose) { - /* dump of registers */ - printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); - for (i = 0; i <= 0xd; i ++) { - outb(efir, i); - printf("0x%x ", inb(efdr)); - } - for (i = 0x10; i <= 0x17; i ++) { - outb(efir, i); - printf("0x%x ", inb(efdr)); - } - outb(efir, 0x1e); - printf("0x%x ", inb(efdr)); - for (i = 0x20; i <= 0x29; i ++) { - outb(efir, i); - printf("0x%x ", inb(efdr)); - } - printf("\n"); - printf("ppc%d:", ppc->ppc_unit); - } - - ppc->ppc_type = PPC_TYPE_GENERIC; - - if (!chipset_mode) { - /* autodetect mode */ - - /* select CR0 */ - outb(efir, 0x0); - r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); - - /* select CR9 */ - outb(efir, 0x9); - r |= (inb(efdr) & WINB_PRTMODS2); - - switch (r) { - case WINB_W83757: - if (bootverbose) - printf("ppc%d: W83757 compatible mode\n", - ppc->ppc_unit); - return (-1); /* generic or SMC-like */ - - case WINB_EXTFDC: - case WINB_EXTADP: - case WINB_EXT2FDD: - case WINB_JOYSTICK: - if (bootverbose) - printf(" not in parallel port mode\n"); - return (-1); - - case (WINB_PARALLEL | WINB_EPP_SPP): - ppc->ppc_avm |= PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" EPP SPP"); - break; - - case (WINB_PARALLEL | WINB_ECP): - ppc->ppc_avm |= PPB_ECP | PPB_SPP; - if (bootverbose) - printf(" ECP SPP"); - break; - - case (WINB_PARALLEL | WINB_ECP_EPP): - ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - ppc->ppc_type = PPC_TYPE_SMCLIKE; - - if (bootverbose) - printf(" ECP+EPP SPP"); - break; - default: - printf("%s: unknown case (0x%x)!\n", __func__, r); - } - - } else { - /* mode forced */ - - /* select CR9 and set PRTMODS2 bit */ - outb(efir, 0x9); - outb(efdr, inb(efdr) & ~WINB_PRTMODS2); - - /* select CR0 and reset PRTMODSx bits */ - outb(efir, 0x0); - outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); - - if (chipset_mode & PPB_ECP) { - if (chipset_mode & PPB_EPP) { - outb(efdr, inb(efdr) | WINB_ECP_EPP); - if (bootverbose) - printf(" ECP+EPP"); - - ppc->ppc_type = PPC_TYPE_SMCLIKE; - - } else { - outb(efdr, inb(efdr) | WINB_ECP); - if (bootverbose) - printf(" ECP"); - } - } else { - /* select EPP_SPP otherwise */ - outb(efdr, inb(efdr) | WINB_EPP_SPP); - if (bootverbose) - printf(" EPP SPP"); - } - ppc->ppc_avm = chipset_mode; - } - - if (bootverbose) - printf("\n"); - - /* exit configuration mode */ - outb(efer, 0xaa); - - switch (ppc->ppc_type) { - case PPC_TYPE_SMCLIKE: - ppc_smclike_setmode(ppc, chipset_mode); - break; - default: - ppc_generic_setmode(ppc, chipset_mode); - break; - } - - return (chipset_mode); -} -#endif - -/* - * ppc_generic_detect - */ -static int -ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) -{ - /* default to generic */ - ppc->ppc_type = PPC_TYPE_GENERIC; - - if (bootverbose) - printf("ppc%d:", ppc->ppc_unit); - - /* first, check for ECP */ - w_ecr(ppc, PPC_ECR_PS2); - if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { - ppc->ppc_dtm |= PPB_ECP | PPB_SPP; - if (bootverbose) - printf(" ECP SPP"); - - /* search for SMC style ECP+EPP mode */ - w_ecr(ppc, PPC_ECR_EPP); - } - - /* try to reset EPP timeout bit */ - if (ppc_check_epp_timeout(ppc)) { - ppc->ppc_dtm |= PPB_EPP; - - if (ppc->ppc_dtm & PPB_ECP) { - /* SMC like chipset found */ - ppc->ppc_model = SMC_LIKE; - ppc->ppc_type = PPC_TYPE_SMCLIKE; - - if (bootverbose) - printf(" ECP+EPP"); - } else { - if (bootverbose) - printf(" EPP"); - } - } else { - /* restore to standard mode */ - w_ecr(ppc, PPC_ECR_STD); - } - - /* XXX try to detect NIBBLE and PS2 modes */ - ppc->ppc_dtm |= PPB_NIBBLE; - - if (bootverbose) - printf(" SPP"); - - if (chipset_mode) - ppc->ppc_avm = chipset_mode; - else - ppc->ppc_avm = ppc->ppc_dtm; - - if (bootverbose) - printf("\n"); - - switch (ppc->ppc_type) { - case PPC_TYPE_SMCLIKE: - ppc_smclike_setmode(ppc, chipset_mode); - break; - default: - ppc_generic_setmode(ppc, chipset_mode); - break; - } - - return (chipset_mode); -} - -/* - * ppc_detect() - * - * mode is the mode suggested at boot - */ -static int -ppc_detect(struct ppc_data *ppc, int chipset_mode) { - -#ifdef PPC_PROBE_CHIPSET - int i, mode; - - /* list of supported chipsets */ - int (*chipset_detect[])(struct ppc_data *, int) = { - ppc_pc873xx_detect, - ppc_smc37c66xgt_detect, - ppc_w83877f_detect, - ppc_smc37c935_detect, - ppc_generic_detect, - NULL - }; -#endif - - /* if can't find the port and mode not forced return error */ - if (!ppc_detect_port(ppc) && chipset_mode == 0) - return (EIO); /* failed, port not present */ - - /* assume centronics compatible mode is supported */ - ppc->ppc_avm = PPB_COMPATIBLE; - -#ifdef PPC_PROBE_CHIPSET - /* we have to differenciate available chipset modes, - * chipset running modes and IEEE-1284 operating modes - * - * after detection, the port must support running in compatible mode - */ - if (ppc->ppc_flags & 0x40) { - if (bootverbose) - printf("ppc: chipset forced to generic\n"); -#endif - - ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); - -#ifdef PPC_PROBE_CHIPSET - } else { - for (i=0; chipset_detect[i] != NULL; i++) { - if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { - ppc->ppc_mode = mode; - break; - } - } - } -#endif - - /* configure/detect ECP FIFO */ - if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) - ppc_detect_fifo(ppc); - - return (0); -} - -/* - * ppc_exec_microseq() - * - * Execute a microsequence. - * Microsequence mechanism is supposed to handle fast I/O operations. - */ -int -ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) -{ - struct ppc_data *ppc = DEVTOSOFTC(dev); - struct ppb_microseq *mi; - char cc, *p; - int i, iter, len; - int error; - - register int reg; - register char mask; - register int accum = 0; - register char *ptr = 0; - - struct ppb_microseq *stack = 0; - -/* microsequence registers are equivalent to PC-like port registers */ - -#define r_reg(register,ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, register)) -#define w_reg(register, ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, register, byte)) - -#define INCR_PC (mi ++) /* increment program counter */ - - mi = *p_msq; - for (;;) { - switch (mi->opcode) { - case MS_OP_RSET: - cc = r_reg(mi->arg[0].i, ppc); - cc &= (char)mi->arg[2].i; /* clear mask */ - cc |= (char)mi->arg[1].i; /* assert mask */ - w_reg(mi->arg[0].i, ppc, cc); - INCR_PC; - break; - - case MS_OP_RASSERT_P: - reg = mi->arg[1].i; - ptr = ppc->ppc_ptr; - - if ((len = mi->arg[0].i) == MS_ACCUM) { - accum = ppc->ppc_accum; - for (; accum; accum--) - w_reg(reg, ppc, *ptr++); - ppc->ppc_accum = accum; - } else - for (i=0; i<len; i++) - w_reg(reg, ppc, *ptr++); - ppc->ppc_ptr = ptr; - - INCR_PC; - break; - - case MS_OP_RFETCH_P: - reg = mi->arg[1].i; - mask = (char)mi->arg[2].i; - ptr = ppc->ppc_ptr; - - if ((len = mi->arg[0].i) == MS_ACCUM) { - accum = ppc->ppc_accum; - for (; accum; accum--) - *ptr++ = r_reg(reg, ppc) & mask; - ppc->ppc_accum = accum; - } else - for (i=0; i<len; i++) - *ptr++ = r_reg(reg, ppc) & mask; - ppc->ppc_ptr = ptr; - - INCR_PC; - break; - - case MS_OP_RFETCH: - *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & - (char)mi->arg[1].i; - INCR_PC; - break; - - case MS_OP_RASSERT: - case MS_OP_DELAY: - - /* let's suppose the next instr. is the same */ - prefetch: - for (;mi->opcode == MS_OP_RASSERT; INCR_PC) - w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); - - if (mi->opcode == MS_OP_DELAY) { - DELAY(mi->arg[0].i); - INCR_PC; - goto prefetch; - } - break; - - case MS_OP_ADELAY: - if (mi->arg[0].i) - tsleep(NULL, PPBPRI, "ppbdelay", - mi->arg[0].i * (hz/1000)); - INCR_PC; - break; - - case MS_OP_TRIG: - reg = mi->arg[0].i; - iter = mi->arg[1].i; - p = (char *)mi->arg[2].p; - - /* XXX delay limited to 255 us */ - for (i=0; i<iter; i++) { - w_reg(reg, ppc, *p++); - DELAY((unsigned char)*p++); - } - INCR_PC; - break; - - case MS_OP_SET: - ppc->ppc_accum = mi->arg[0].i; - INCR_PC; - break; - - case MS_OP_DBRA: - if (--ppc->ppc_accum > 0) - mi += mi->arg[0].i; - INCR_PC; - break; - - case MS_OP_BRSET: - cc = r_str(ppc); - if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) - mi += mi->arg[1].i; - INCR_PC; - break; - - case MS_OP_BRCLEAR: - cc = r_str(ppc); - if ((cc & (char)mi->arg[0].i) == 0) - mi += mi->arg[1].i; - INCR_PC; - break; - - case MS_OP_BRSTAT: - cc = r_str(ppc); - if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == - (char)mi->arg[0].i) - mi += mi->arg[2].i; - INCR_PC; - break; - - case MS_OP_C_CALL: - /* - * If the C call returns !0 then end the microseq. - * The current state of ptr is passed to the C function - */ - if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) - return (error); - - INCR_PC; - break; - - case MS_OP_PTR: - ppc->ppc_ptr = (char *)mi->arg[0].p; - INCR_PC; - break; - - case MS_OP_CALL: - if (stack) - panic("%s: too much calls", __func__); - - if (mi->arg[0].p) { - /* store the state of the actual - * microsequence - */ - stack = mi; - - /* jump to the new microsequence */ - mi = (struct ppb_microseq *)mi->arg[0].p; - } else - INCR_PC; - - break; - - case MS_OP_SUBRET: - /* retrieve microseq and pc state before the call */ - mi = stack; - - /* reset the stack */ - stack = 0; - - /* XXX return code */ - - INCR_PC; - break; - - case MS_OP_PUT: - case MS_OP_GET: - case MS_OP_RET: - /* can't return to ppb level during the execution - * of a submicrosequence */ - if (stack) - panic("%s: can't return to ppb level", - __func__); - - /* update pc for ppb level of execution */ - *p_msq = mi; - - /* return to ppb level of execution */ - return (0); - - default: - panic("%s: unknown microsequence opcode 0x%x", - __func__, mi->opcode); - } - } - - /* unreached */ -} - -static void -ppcintr(void *arg) -{ - device_t dev = (device_t)arg; - struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); - u_char ctr, ecr, str; - - str = r_str(ppc); - ctr = r_ctr(ppc); - ecr = r_ecr(ppc); - -#if defined(PPC_DEBUG) && PPC_DEBUG > 1 - printf("![%x/%x/%x]", ctr, ecr, str); -#endif - - /* don't use ecp mode with IRQENABLE set */ - if (ctr & IRQENABLE) { - return; - } - - /* interrupts are generated by nFault signal - * only in ECP mode */ - if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { - /* check if ppc driver has programmed the - * nFault interrupt */ - if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { - - w_ecr(ppc, ecr | PPC_nFAULT_INTR); - ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; - } else { - /* shall be handled by underlying layers XXX */ - return; - } - } - - if (ppc->ppc_irqstat & PPC_IRQ_DMA) { - /* disable interrupts (should be done by hardware though) */ - w_ecr(ppc, ecr | PPC_SERVICE_INTR); - ppc->ppc_irqstat &= ~PPC_IRQ_DMA; - ecr = r_ecr(ppc); - - /* check if DMA completed */ - if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { -#ifdef PPC_DEBUG - printf("a"); -#endif - /* stop DMA */ - w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); - ecr = r_ecr(ppc); - - if (ppc->ppc_dmastat == PPC_DMA_STARTED) { -#ifdef PPC_DEBUG - printf("d"); -#endif - isa_dmadone( - ppc->ppc_dmaflags, - ppc->ppc_dmaddr, - ppc->ppc_dmacnt, - ppc->ppc_dmachan); - - ppc->ppc_dmastat = PPC_DMA_COMPLETE; - - /* wakeup the waiting process */ - wakeup(ppc); - } - } - } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { - - /* classic interrupt I/O */ - ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; - } - - return; -} - -int -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); -} - -void -ppc_reset_epp(device_t dev) -{ - struct ppc_data *ppc = DEVTOSOFTC(dev); - - ppc_reset_epp_timeout(ppc); - - return; -} - -int -ppc_setmode(device_t dev, int mode) -{ - struct ppc_data *ppc = DEVTOSOFTC(dev); - - switch (ppc->ppc_type) { - case PPC_TYPE_SMCLIKE: - return (ppc_smclike_setmode(ppc, mode)); - break; - - case PPC_TYPE_GENERIC: - default: - return (ppc_generic_setmode(ppc, mode)); - break; - } - - /* not reached */ - 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_cbus_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) -{ -#ifdef __i386__ - static short next_bios_ppc = 0; -#endif - struct ppc_data *ppc; - int error; - u_long port; -#ifdef PC98 -#define PC98_IEEE_1284_DISABLE 0x100 -#define PC98_IEEE_1284_PORT 0x140 - - unsigned int pc98_ieee_mode = 0x00; - unsigned int tmp; -#endif - - /* - * Allocate the ppc_data structure. - */ - 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; - - /* retrieve ISA parameters */ - error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, NULL); - -#ifdef __i386__ - /* - * If port not specified, use bios list. - */ - if (error) { -#ifndef PC98 - if((next_bios_ppc < BIOS_MAX_PPC) && - (*(BIOS_PORTS+next_bios_ppc) != 0) ) { - port = *(BIOS_PORTS+next_bios_ppc++); - if (bootverbose) - device_printf(dev, "parallel port found at 0x%x\n", - (int) port); - } else { - device_printf(dev, "parallel port not found.\n"); - return ENXIO; - } -#else - 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); - } -#endif - bus_set_resource(dev, SYS_RES_IOPORT, 0, port, - IO_LPTSIZE_EXTENDED); - } -#endif -#ifdef __alpha__ - /* - * 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, - IO_LPTSIZE_NORMAL); - } -#endif - - /* IO port is mandatory */ - - /* Try "extended" IO port range...*/ - ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, - &ppc->rid_ioport, 0, ~0, - IO_LPTSIZE_EXTENDED, RF_ACTIVE); - - if (ppc->res_ioport != 0) { - if (bootverbose) - device_printf(dev, "using extended I/O port range\n"); - } else { - /* Failed? If so, then try the "normal" IO port range... */ - ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, - &ppc->rid_ioport, 0, ~0, - IO_LPTSIZE_NORMAL, - RF_ACTIVE); - if (ppc->res_ioport != 0) { - if (bootverbose) - device_printf(dev, "using normal I/O port range\n"); - } else { - device_printf(dev, "cannot reserve I/O port range\n"); - goto error; - } - } - - ppc->ppc_base = rman_get_start(ppc->res_ioport); - - ppc->bsh = rman_get_bushandle(ppc->res_ioport); - ppc->bst = rman_get_bustag(ppc->res_ioport); - - ppc->ppc_flags = device_get_flags(dev); - - if (!(ppc->ppc_flags & 0x20)) { - ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &ppc->rid_irq, - RF_SHAREABLE); - ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, - &ppc->rid_drq, - RF_ACTIVE); - } - - if (ppc->res_irq) - ppc->ppc_irq = rman_get_start(ppc->res_irq); - if (ppc->res_drq) - ppc->ppc_dmachan = rman_get_start(ppc->res_drq); - - ppc->ppc_unit = device_get_unit(dev); - ppc->ppc_model = GENERIC; - - ppc->ppc_mode = PPB_COMPATIBLE; - ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; - - ppc->ppc_type = PPC_TYPE_GENERIC; - -#ifdef 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. - */ - if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) - goto error; - - return (0); - -error: -#ifdef 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); - } - if (ppc->res_ioport != 0) { - bus_deactivate_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, - ppc->res_ioport); - bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, - ppc->res_ioport); - } - if (ppc->res_drq != 0) { - bus_deactivate_resource(dev, SYS_RES_DRQ, ppc->rid_drq, - ppc->res_drq); - bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, - ppc->res_drq); - } - return (ENXIO); -} - -int -ppc_attach(device_t dev) -{ - struct ppc_data *ppc = DEVTOSOFTC(dev); - - device_t ppbus; - - device_printf(dev, "%s chipset (%s) in %s mode%s\n", - ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], - ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? - ppc_epp_protocol[ppc->ppc_epp] : ""); - - if (ppc->ppc_fifo) - 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); - - /* - * Probe the ppbus and attach devices found. - */ - device_probe_and_attach(ppbus); - - /* register the ppc interrupt handler as default */ - if (ppc->res_irq) { - /* default to the tty mask for registration */ /* XXX */ - if (bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY, - ppcintr, dev, &ppc->intr_cookie) == 0) { - - /* remember the ppcintr is registered */ - ppc->ppc_registered = 1; - } - } - - return (0); -} - -u_char -ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) -{ - struct ppc_data *ppc = DEVTOSOFTC(ppcdev); - switch (iop) { - case PPB_OUTSB_EPP: - bus_space_write_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); - break; - case PPB_OUTSW_EPP: - bus_space_write_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); - break; - case PPB_OUTSL_EPP: - bus_space_write_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); - break; - case PPB_INSB_EPP: - bus_space_read_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); - break; - case PPB_INSW_EPP: - bus_space_read_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); - break; - case PPB_INSL_EPP: - bus_space_read_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); - break; - case PPB_RDTR: - return (r_dtr(ppc)); - case PPB_RSTR: - return (r_str(ppc)); - case PPB_RCTR: - return (r_ctr(ppc)); - case PPB_REPP_A: - return (r_epp_A(ppc)); - case PPB_REPP_D: - return (r_epp_D(ppc)); - case PPB_RECR: - return (r_ecr(ppc)); - case PPB_RFIFO: - return (r_fifo(ppc)); - case PPB_WDTR: - w_dtr(ppc, byte); - break; - case PPB_WSTR: - w_str(ppc, byte); - break; - case PPB_WCTR: - w_ctr(ppc, byte); - break; - case PPB_WEPP_A: - w_epp_A(ppc, byte); - break; - case PPB_WEPP_D: - w_epp_D(ppc, byte); - break; - case PPB_WECR: - w_ecr(ppc, byte); - break; - case PPB_WFIFO: - w_fifo(ppc, byte); - break; - default: - panic("%s: unknown I/O operation", __func__); - break; - } - - return (0); /* not significative */ -} - -int -ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) -{ - struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); - - switch (index) { - case PPC_IVAR_EPP_PROTO: - *val = (u_long)ppc->ppc_epp; - break; - case PPC_IVAR_IRQ: - *val = (u_long)ppc->ppc_irq; - break; - default: - return (ENOENT); - } - - return (0); -} - -/* - * Resource is useless here since ppbus devices' interrupt handlers are - * multiplexed to the same resource initially allocated by ppc - */ -int -ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, - void (*ihand)(void *), void *arg, void **cookiep) -{ - int error; - struct ppc_data *ppc = DEVTOSOFTC(bus); - - if (ppc->ppc_registered) { - /* XXX refuse registration if DMA is in progress */ - - /* first, unregister the default interrupt handler */ - if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus), - bus, ppc->res_irq, ppc->intr_cookie))) - return (error); - -/* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */ -/* ppc->res_irq); */ - - /* DMA/FIFO operation won't be possible anymore */ - ppc->ppc_registered = 0; - } - - /* pass registration to the upper layer, ignore the incoming resource */ - return (BUS_SETUP_INTR(device_get_parent(bus), child, - r, flags, ihand, arg, cookiep)); -} - -/* - * When no underlying device has a registered interrupt, register the ppc - * layer one - */ -int -ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) -{ - int error; - struct ppc_data *ppc = DEVTOSOFTC(bus); - device_t parent = device_get_parent(bus); - - /* pass unregistration to the upper layer */ - if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih))) - return (error); - - /* default to the tty mask for registration */ /* XXX */ - if (ppc->ppc_irq && - !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq, - INTR_TYPE_TTY, ppcintr, bus, &ppc->intr_cookie))) { - - /* remember the ppcintr is registered */ - ppc->ppc_registered = 1; - } - - return (error); -} - -DRIVER_MODULE(ppc, isa, ppc_driver, ppc_devclass, 0, 0); -#ifndef PC98 -DRIVER_MODULE(ppc, acpi, ppc_driver, ppc_devclass, 0, 0); -#endif diff --git a/sys/pc98/cbus/ppcreg.h b/sys/pc98/cbus/ppcreg.h deleted file mode 100644 index 2aa5ce4..0000000 --- a/sys/pc98/cbus/ppcreg.h +++ /dev/null @@ -1,280 +0,0 @@ -/*- - * Copyright (c) 2001 Alcove - Nicolas Souchu - * 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. - * - * $FreeBSD$ - * - */ -#ifndef __PPCREG_H -#define __PPCREG_H - -/* - * Parallel Port Chipset type. - */ -#define SMC_LIKE 0 -#define SMC_37C665GT 1 -#define SMC_37C666GT 2 -#define NS_PC87332 3 -#define NS_PC87306 4 -#define INTEL_820191AA 5 /* XXX not implemented */ -#define GENERIC 6 -#define WINB_W83877F 7 -#define WINB_W83877AF 8 -#define WINB_UNKNOWN 9 -#define NS_PC87334 10 -#define SMC_37C935 11 -#define NS_PC87303 12 - -/* - * Parallel Port Chipset Type. SMC versus GENERIC (others) - */ -#define PPC_TYPE_SMCLIKE 0 -#define PPC_TYPE_GENERIC 1 - -/* - * Generic structure to hold parallel port chipset info. - */ -struct ppc_data { - - int ppc_unit; - int ppc_model; /* chipset model if detected */ - int ppc_type; /* generic or smclike chipset type */ - - int ppc_mode; /* chipset current mode */ - int ppc_avm; /* chipset available modes */ - int ppc_dtm; /* chipset detected modes */ - -#define PPC_IRQ_NONE 0x0 -#define PPC_IRQ_nACK 0x1 -#define PPC_IRQ_DMA 0x2 -#define PPC_IRQ_FIFO 0x4 -#define PPC_IRQ_nFAULT 0x8 - int ppc_irqstat; /* remind irq settings */ - -#define PPC_DMA_INIT 0x01 -#define PPC_DMA_STARTED 0x02 -#define PPC_DMA_COMPLETE 0x03 -#define PPC_DMA_INTERRUPTED 0x04 -#define PPC_DMA_ERROR 0x05 - int ppc_dmastat; /* dma state */ - int ppc_dmachan; /* dma channel */ - int ppc_dmaflags; /* dma transfer flags */ - caddr_t ppc_dmaddr; /* buffer address */ - u_int ppc_dmacnt; /* count of bytes sent with dma */ - -#define PPC_PWORD_MASK 0x30 -#define PPC_PWORD_16 0x00 -#define PPC_PWORD_8 0x10 -#define PPC_PWORD_32 0x20 - char ppc_pword; /* PWord size */ - short ppc_fifo; /* FIFO threshold */ - - short ppc_wthr; /* writeIntrThresold */ - short ppc_rthr; /* readIntrThresold */ - - char *ppc_ptr; /* microseq current pointer */ - int ppc_accum; /* microseq accumulator */ - int ppc_base; /* parallel port base address */ - int ppc_epp; /* EPP mode (1.7 or 1.9) */ - int ppc_irq; - - unsigned char ppc_flags; - - device_t ppbus; /* parallel port chipset corresponding ppbus */ - - int rid_irq, rid_drq, rid_ioport; - struct resource *res_irq, *res_drq, *res_ioport; - - bus_space_handle_t bsh; - bus_space_tag_t bst; - - void *intr_cookie; - - int ppc_registered; /* 1 if ppcintr() is the registered interrupt */ -}; - -/* - * Parallel Port Chipset registers. - */ -#define PPC_SPP_DTR 0 /* SPP data register */ -#define PPC_ECP_A_FIFO 0 /* ECP Address fifo register */ -#define PPC_SPP_STR 1 /* SPP status register */ -#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) */ -#ifdef 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 */ -#define PPC_SERVICE_INTR 0x4 /* ecr register - bit 2 */ -#define PPC_ENABLE_DMA 0x8 /* ecr register - bit 3 */ -#define PPC_nFAULT_INTR 0x10 /* ecr register - bit 4 */ -#define PPC_ECR_STD 0x0 -#define PPC_ECR_PS2 0x20 -#define PPC_ECR_FIFO 0x40 -#define PPC_ECR_ECP 0x60 -#define PPC_ECR_EPP 0x80 - -#define PPC_DISABLE_INTR (PPC_SERVICE_INTR | PPC_nFAULT_INTR) -#define PPC_ECR_RESET (PPC_ECR_PS2 | PPC_DISABLE_INTR) - -#define r_dtr(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_SPP_DTR)) -#define r_str(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_SPP_STR)) -#define r_ctr(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_SPP_CTR)) - -#define r_epp_A(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_EPP_ADDR)) -#define r_epp_D(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_EPP_DATA)) -#define r_cnfgA(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_ECP_CNFGA)) -#define r_cnfgB(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_ECP_CNFGB)) -#define r_ecr(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_ECP_ECR)) -#define r_fifo(ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, PPC_ECP_D_FIFO)) - -#define w_dtr(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_SPP_DTR, byte)) -#define w_str(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_SPP_STR, byte)) -#define w_ctr(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_SPP_CTR, byte)) - -#define w_epp_A(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_EPP_ADDR, byte)) -#define w_epp_D(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_EPP_DATA, byte)) -#define w_ecr(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_ECP_ECR, byte)) -#define w_fifo(ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, PPC_ECP_D_FIFO, byte)) - -/* - * Register defines for the PC873xx parts - */ - -#define PC873_FER 0x00 -#define PC873_PPENABLE (1<<0) -#define PC873_FAR 0x01 -#define PC873_PTR 0x02 -#define PC873_CFGLOCK (1<<6) -#define PC873_EPPRDIR (1<<7) -#define PC873_EXTENDED (1<<7) -#define PC873_LPTBIRQ7 (1<<3) -#define PC873_FCR 0x03 -#define PC873_ZWS (1<<5) -#define PC873_ZWSPWDN (1<<6) -#define PC873_PCR 0x04 -#define PC873_EPPEN (1<<0) -#define PC873_EPP19 (1<<1) -#define PC873_ECPEN (1<<2) -#define PC873_ECPCLK (1<<3) -#define PC873_PMC 0x06 -#define PC873_TUP 0x07 -#define PC873_SID 0x08 -#define PC873_PNP0 0x1b -#define PC873_PNP1 0x1c -#define PC873_LPTBA 0x19 - -/* - * Register defines for the SMC FDC37C66xGT parts - */ - -/* Init codes */ -#define SMC665_iCODE 0x55 -#define SMC666_iCODE 0x44 - -/* Base configuration ports */ -#define SMC66x_CSR 0x3F0 -#define SMC666_CSR 0x370 /* hard-configured value for 666 */ - -/* Bits */ -#define SMC_CR1_ADDR 0x3 /* bit 0 and 1 */ -#define SMC_CR1_MODE (1<<3) /* bit 3 */ -#define SMC_CR4_EMODE 0x3 /* bits 0 and 1 */ -#define SMC_CR4_EPPTYPE (1<<6) /* bit 6 */ - -/* Extended modes */ -#define SMC_SPP 0x0 /* SPP */ -#define SMC_EPPSPP 0x1 /* EPP and SPP */ -#define SMC_ECP 0x2 /* ECP */ -#define SMC_ECPEPP 0x3 /* ECP and EPP */ - -/* - * Register defines for the SMC FDC37C935 parts - */ - -/* Configuration ports */ -#define SMC935_CFG 0x370 -#define SMC935_IND 0x370 -#define SMC935_DAT 0x371 - -/* Registers */ -#define SMC935_LOGDEV 0x7 -#define SMC935_ID 0x20 -#define SMC935_PORTHI 0x60 -#define SMC935_PORTLO 0x61 -#define SMC935_PPMODE 0xf0 - -/* Parallel port modes */ -#define SMC935_SPP 0x38 + 0 -#define SMC935_EPP19SPP 0x38 + 1 -#define SMC935_ECP 0x38 + 2 -#define SMC935_ECPEPP19 0x38 + 3 -#define SMC935_CENT 0x38 + 4 -#define SMC935_EPP17SPP 0x38 + 5 -#define SMC935_UNUSED 0x38 + 6 -#define SMC935_ECPEPP17 0x38 + 7 - -/* - * Register defines for the Winbond W83877F parts - */ - -#define WINB_W83877F_ID 0xa -#define WINB_W83877AF_ID 0xb - -/* Configuration bits */ -#define WINB_HEFERE (1<<5) /* CROC bit 5 */ -#define WINB_HEFRAS (1<<0) /* CR16 bit 0 */ - -#define WINB_PNPCVS (1<<2) /* CR16 bit 2 */ -#define WINB_CHIPID 0xf /* CR9 bits 0-3 */ - -#define WINB_PRTMODS0 (1<<2) /* CR0 bit 2 */ -#define WINB_PRTMODS1 (1<<3) /* CR0 bit 3 */ -#define WINB_PRTMODS2 (1<<7) /* CR9 bit 7 */ - -/* W83877F modes: CR9/bit7 | CR0/bit3 | CR0/bit2 */ -#define WINB_W83757 0x0 -#define WINB_EXTFDC 0x4 -#define WINB_EXTADP 0x8 -#define WINB_EXT2FDD 0xc -#define WINB_JOYSTICK 0x80 - -#define WINB_PARALLEL 0x80 -#define WINB_EPP_SPP 0x4 -#define WINB_ECP 0x8 -#define WINB_ECP_EPP 0xc - -#endif |