diff options
32 files changed, 3343 insertions, 2522 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index a651ccb..3a284bd 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2131,6 +2131,8 @@ pseudo-device "i4bisppp" 4 # ppc ISA-bus parallel port interfaces. # +options PPC_PROBE_CHIPSET # Enable chipset specific detection + # (see flags in ppc(4)) options DEBUG_1284 # IEEE1284 signaling protocol debug options PERIPH_1284 # Makes your computer act as a IEEE1284 # compliant peripheral diff --git a/sys/conf/files b/sys/conf/files index 5545f8b..69bfdbd 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -209,6 +209,20 @@ dev/pdq/pdq.c optional fea dev/pdq/pdq_ifsubr.c optional fea dev/pdq/pdq.c optional fpa dev/pdq/pdq_ifsubr.c optional fpa +ppbus_if.o optional ppbus \ + dependency "ppbus_if.c ppbus_if.h" \ + compile-with "${NORMAL_C}" \ + no-implicit-rule local +ppbus_if.c optional ppbus \ + dependency "$S/kern/makedevops.pl $S/dev/ppbus/ppbus_if.m" \ + compile-with "perl5 $S/kern/makedevops.pl -c $S/dev/ppbus/ppbus_if.m" \ + no-obj no-implicit-rule before-depend local \ + clean "ppbus_if.c" +ppbus_if.h optional ppbus \ + dependency "$S/kern/makedevops.pl $S/dev/ppbus/ppbus_if.m" \ + compile-with "perl5 $S/kern/makedevops.pl -h $S/dev/ppbus/ppbus_if.m" \ + no-obj no-implicit-rule before-depend \ + clean "ppbus_if.h" dev/ppbus/immio.c optional vpo dev/ppbus/if_plip.c optional plip dev/ppbus/lpbb.c optional lpbb diff --git a/sys/conf/options.i386 b/sys/conf/options.i386 index 1bd8511..8ef1aee 100644 --- a/sys/conf/options.i386 +++ b/sys/conf/options.i386 @@ -6,6 +6,7 @@ USER_LDT MATH_EMULATE opt_math_emulate.h GPL_MATH_EMULATE opt_math_emulate.h PMAP_SHPGPERPROC opt_pmap.h +PPC_PROBE_CHIPSET opt_ppc.h PPC_DEBUG opt_ppc.h SHOW_BUSYBUFS PANIC_REBOOT_WAIT_TIME opt_panic.h diff --git a/sys/dev/pcf/pcf.c b/sys/dev/pcf/pcf.c index 1aeb7e6..e37823e 100644 --- a/sys/dev/pcf/pcf.c +++ b/sys/dev/pcf/pcf.c @@ -34,12 +34,20 @@ #include <sys/malloc.h> #include <machine/clock.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <isa/isareg.h> +#include <isa/isavar.h> #include <i386/isa/isa_device.h> #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" +#define IO_PCFSIZE 2 + #define TIMEOUT 9999 /* XXX */ /* Status bits of S1 register (read only) */ @@ -71,37 +79,23 @@ struct pcf_softc { int pcf_base; /* isa port */ + int pcf_flags; u_char pcf_addr; /* interface I2C address */ int pcf_slave_mode; /* receiver or transmitter */ int pcf_started; /* 1 if start condition sent */ device_t iicbus; /* the corresponding iicbus */ -}; - -struct pcf_isa_softc { - - int pcf_unit; /* unit of the isa device */ - int pcf_base; /* isa port */ - int pcf_irq; /* isa irq or null if polled */ - - unsigned int pcf_flags; /* boot flags */ -}; - -#define MAXPCF 2 - -static struct pcf_isa_softc *pcfdata[MAXPCF]; -static int npcf = 0; - -static int pcfprobe_isa(struct isa_device *); -static int pcfattach_isa(struct isa_device *); -struct isa_driver pcfdriver = { - pcfprobe_isa, pcfattach_isa, "pcf" + int rid_irq, rid_ioport; + struct resource *res_irq, *res_ioport; + void *intr_cookie; }; static int pcf_probe(device_t); static int pcf_attach(device_t); +static void pcfintr(void *arg); + static int pcf_print_child(device_t, device_t); static int pcf_repeated_start(device_t, u_char, int); @@ -109,7 +103,6 @@ static int pcf_start(device_t, u_char, int); static int pcf_stop(device_t); static int pcf_write(device_t, char *, int, int *, int); static int pcf_read(device_t, char *, int, int *, int, int); -static ointhand2_t pcfintr; static int pcf_rst_card(device_t, u_char, u_char, u_char *); static device_method_t pcf_methods[] = { @@ -143,72 +136,68 @@ static devclass_t pcf_devclass; #define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) static int -pcfprobe_isa(struct isa_device *dvp) +pcf_probe(device_t pcfdev) { - device_t pcfdev; - struct pcf_isa_softc *pcf; - - if (npcf >= MAXPCF) - return (0); - - if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc), - M_DEVBUF, M_NOWAIT)) == NULL) - return (0); - - pcf->pcf_base = dvp->id_iobase; /* XXX should be ivars */ - pcf->pcf_unit = dvp->id_unit; + struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); + device_t parent = device_get_parent(pcfdev); - if (!(dvp->id_flags & IIC_POLLED)) - pcf->pcf_irq = (dvp->id_irq); + device_set_desc(pcfdev, "PCF8584 I2C bus controller"); - pcfdata[npcf++] = pcf; + pcf = DEVTOSOFTC(pcfdev); + bzero(pcf, sizeof(struct pcf_softc)); - /* XXX add the pcf device to the root_bus until isa bus exists */ - pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit); + pcf->rid_irq = pcf->rid_ioport = 0; + pcf->res_irq = pcf->res_ioport = 0; - if (!pcfdev) + /* IO port is mandatory */ + pcf->res_ioport = bus_alloc_resource(pcfdev, SYS_RES_IOPORT, + &pcf->rid_ioport, 0ul, ~0ul, + IO_PCFSIZE, RF_ACTIVE); + if (pcf->res_ioport == 0) { + device_printf(pcfdev, "cannot reserve I/O port range\n"); goto error; + } + BUS_READ_IVAR(parent, pcfdev, ISA_IVAR_PORT, &pcf->pcf_base); - return (1); - -error: - free(pcf, M_DEVBUF); - return (0); -} - -static int -pcfattach_isa(struct isa_device *isdp) -{ - isdp->id_ointr = pcfintr; - return (1); /* ok */ -} + pcf->pcf_flags = device_get_flags(pcfdev); -static int -pcf_probe(device_t pcfdev) -{ - struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); - int unit = device_get_unit(pcfdev); - - /* retrieve base address from isa initialization - * - * XXX should use ivars with isabus - */ - pcf->pcf_base = pcfdata[unit]->pcf_base; + if (!(pcf->pcf_flags & IIC_POLLED)) { + pcf->res_irq = bus_alloc_resource(pcfdev, SYS_RES_IRQ, &pcf->rid_irq, + 0ul, ~0ul, 1, RF_ACTIVE); + if (pcf->res_irq == 0) { + device_printf(pcfdev, "can't reserve irq, polled mode.\n"); + pcf->pcf_flags |= IIC_POLLED; + } + } /* reset the chip */ pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); - /* XXX try do detect chipset */ - - device_set_desc(pcfdev, "PCF8584 I2C bus controller"); - return (0); +error: + if (pcf->res_ioport != 0) { + bus_deactivate_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport, + pcf->res_ioport); + bus_release_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport, + pcf->res_ioport); + } + return (ENXIO); } static int pcf_attach(device_t pcfdev) { - struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); + struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); + device_t parent = device_get_parent(pcfdev); + int error = 0; + + if (pcf->res_irq) { + /* default to the tty mask for registration */ /* XXX */ + error = BUS_SETUP_INTR(parent, pcfdev, pcf->res_irq, INTR_TYPE_NET, + pcfintr, pcfdev, &pcf->intr_cookie); + if (error) + return (error); + } pcf->iicbus = iicbus_alloc_bus(pcfdev); @@ -392,10 +381,10 @@ error: } static void -pcfintr(unit) +pcfintr(void *arg) { - struct pcf_softc *pcf = - (struct pcf_softc *)devclass_get_softc(pcf_devclass, unit); + device_t pcfdev = (device_t)arg; + struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); char data, status, addr; char error = 0; @@ -403,14 +392,13 @@ pcfintr(unit) status = PCF_GET_S1(pcf); if (status & PIN) { - printf("pcf%d: spurious interrupt, status=0x%x\n", unit, - status & 0xff); + device_printf(pcfdev, "spurious interrupt, status=0x%x\n", status & 0xff); goto error; } if (status & LAB) - printf("pcf%d: bus arbitration lost!\n", unit); + device_printf(pcfdev, "bus arbitration lost!\n"); if (status & BER) { error = IIC_EBUSERR; @@ -643,4 +631,4 @@ error: return (error); } -DRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0); +DRIVER_MODULE(pcf, isa, pcf_driver, pcf_devclass, 0, 0); diff --git a/sys/dev/ppbus/if_plip.c b/sys/dev/ppbus/if_plip.c index f2085e4..033889e 100644 --- a/sys/dev/ppbus/if_plip.c +++ b/sys/dev/ppbus/if_plip.c @@ -77,15 +77,28 @@ /* * Update for ppbus, PLIP support only - Nicolas Souchu */ +#include "plip.h" + +#if NPLIP > 0 + +#include "opt_plip.h" #include <sys/param.h> #include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> #include <sys/kernel.h> #include <sys/malloc.h> +#include <machine/clock.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + #include <net/if.h> #include <net/if_types.h> #include <net/netisr.h> @@ -96,8 +109,8 @@ #include <net/bpf.h> #include <dev/ppbus/ppbconf.h> - -#include "opt_plip.h" +#include "ppbus_if.h" +#include <dev/ppbus/ppbio.h> #ifndef LPMTU /* MTU for the lp# interfaces */ #define LPMTU 1500 @@ -135,20 +148,15 @@ static int volatile lptflag = 1; static int volatile lptflag = 0; #endif -struct lpt_softc { +struct lp_data { unsigned short lp_unit; - struct ppb_device lp_dev; - struct ifnet sc_if; u_char *sc_ifbuf; int sc_iferrs; -}; - -static int nlp = 0; -#define MAXPLIP 8 /* XXX not much better! */ -static struct lpt_softc *lpdata[MAXPLIP]; + struct resource *res_irq; +}; /* Tables for the lp# interface */ static u_char *txmith; @@ -162,87 +170,87 @@ static u_char *ctxmith; #define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) /* Functions for the lp# interface */ -static struct ppb_device *lpprobe(struct ppb_data *); -static int lpattach(struct ppb_device *); +static int lp_probe(device_t dev); +static int lp_attach(device_t dev); static int lpinittables(void); static int lpioctl(struct ifnet *, u_long, caddr_t); static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); -static void lpintr(int); +static void lp_intr(void *); -/* - * Make ourselves visible as a ppbus driver - */ +#define DEVTOSOFTC(dev) \ + ((struct lp_data *)device_get_softc(dev)) +#define UNITOSOFTC(unit) \ + ((struct lp_data *)devclass_get_softc(lp_devclass, (unit))) +#define UNITODEVICE(unit) \ + (devclass_get_device(lp_devclass, (unit))) -static struct ppb_driver lpdriver = { - lpprobe, lpattach, "lp" +static devclass_t lp_devclass; + +static device_method_t lp_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, lp_probe), + DEVMETHOD(device_attach, lp_attach), + + { 0, 0 } }; -DATA_SET(ppbdriver_set, lpdriver); +static driver_t lp_driver = { + "plip", + lp_methods, + sizeof(struct lp_data), +}; /* * lpprobe() */ -static struct ppb_device * -lpprobe(struct ppb_data *ppb) +static int +lp_probe(device_t dev) { - struct lpt_softc *lp; + device_t ppbus = device_get_parent(dev); + struct lp_data *lp; + int irq, zero = 0; + + lp = DEVTOSOFTC(dev); + bzero(lp, sizeof(struct lp_data)); + + /* retrieve the ppbus irq */ + BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); /* if we haven't interrupts, the probe fails */ - if (!ppb->ppb_link->id_irq) { - printf("plip: not an interrupt driven port, failed.\n"); - return (0); + if (irq == -1) { + device_printf(dev, "not an interrupt driven port, failed.\n"); + return (ENXIO); } - lp = (struct lpt_softc *) malloc(sizeof(struct lpt_softc), - M_TEMP, M_NOWAIT); - if (!lp) { - printf("lp: cannot malloc!\n"); - return (0); + /* reserve the interrupt resource, expecting irq is available to continue */ + lp->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1, + RF_SHAREABLE); + if (lp->res_irq == 0) { + device_printf(dev, "cannot reserve interrupt, failed.\n"); + return (ENXIO); } - bzero(lp, sizeof(struct lpt_softc)); - - lpdata[nlp] = lp; /* * lp dependent initialisation. */ - lp->lp_unit = nlp; - - if (bootverbose) - printf("plip: irq %d\n", ppb->ppb_link->id_irq); - - /* - * ppbus dependent initialisation. - */ - lp->lp_dev.id_unit = lp->lp_unit; - lp->lp_dev.name = lpdriver.name; - lp->lp_dev.ppb = ppb; - lp->lp_dev.intr = lpintr; + lp->lp_unit = device_get_unit(dev); - /* Ok, go to next device on next probe */ - nlp ++; + device_set_desc(dev, "PLIP network interface"); - return (&lp->lp_dev); + return (0); } static int -lpattach (struct ppb_device *dev) +lp_attach (device_t dev) { - int unit = dev->id_unit; - struct lpt_softc *sc = lpdata[unit]; - struct ifnet *ifp = &sc->sc_if; + struct lp_data *lp = DEVTOSOFTC(dev); + struct ifnet *ifp = &lp->sc_if; - /* - * Report ourselves - */ - printf("plip%d: <PLIP network interface> on ppbus %d\n", - dev->id_unit, dev->ppb->ppb_link->adapter_unit); - - ifp->if_softc = sc; + ifp->if_softc = lp; ifp->if_name = "lp"; - ifp->if_unit = unit; + ifp->if_unit = device_get_unit(dev); ifp->if_mtu = LPMTU; ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; ifp->if_ioctl = lpioctl; @@ -255,7 +263,7 @@ lpattach (struct ppb_device *dev) bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); - return (1); + return (0); } /* * Build the translation tables for the LPIP (BSD unix) protocol. @@ -303,10 +311,13 @@ lpinittables (void) static int lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) { - struct lpt_softc *sc = lpdata[ifp->if_unit]; + device_t dev = UNITODEVICE(ifp->if_unit); + device_t ppbus = device_get_parent(dev); + struct lp_data *sc = DEVTOSOFTC(dev); struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; u_char *ptr; + void *ih; int error; switch (cmd) { @@ -322,11 +333,11 @@ lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSIFFLAGS: if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { - ppb_wctr(&sc->lp_dev, 0x00); + ppb_wctr(ppbus, 0x00); ifp->if_flags &= ~IFF_RUNNING; /* IFF_UP is not set, try to release the bus anyway */ - ppb_release_bus(&sc->lp_dev); + ppb_release_bus(ppbus, dev); break; } if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { @@ -334,26 +345,33 @@ lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) /* XXX * Should the request be interruptible? */ - if ((error = ppb_request_bus(&sc->lp_dev, PPB_WAIT|PPB_INTR))) + if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR))) return (error); /* Now IFF_UP means that we own the bus */ - ppb_set_mode(&sc->lp_dev, PPB_COMPATIBLE); + ppb_set_mode(ppbus, PPB_COMPATIBLE); if (lpinittables()) { - ppb_release_bus(&sc->lp_dev); + ppb_release_bus(ppbus, dev); return ENOBUFS; } sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, M_DEVBUF, M_WAITOK); if (!sc->sc_ifbuf) { - ppb_release_bus(&sc->lp_dev); + ppb_release_bus(ppbus, dev); return ENOBUFS; } - ppb_wctr(&sc->lp_dev, IRQENABLE); + /* attach our interrupt handler, later detached when the bus is released */ + if ((error = BUS_SETUP_INTR(ppbus, dev, sc->res_irq, + INTR_TYPE_NET, lp_intr, dev, &ih))) { + ppb_release_bus(ppbus, dev); + return (error); + } + + ppb_wctr(ppbus, IRQENABLE); ifp->if_flags |= IFF_RUNNING; } break; @@ -404,15 +422,15 @@ lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) } static __inline int -clpoutbyte (u_char byte, int spin, struct ppb_device *dev) +clpoutbyte (u_char byte, int spin, device_t ppbus) { - ppb_wdtr(dev, ctxmitl[byte]); - while (ppb_rstr(dev) & CLPIP_SHAKE) + ppb_wdtr(ppbus, ctxmitl[byte]); + while (ppb_rstr(ppbus) & CLPIP_SHAKE) if (--spin == 0) { return 1; } - ppb_wdtr(dev, ctxmith[byte]); - while (!(ppb_rstr(dev) & CLPIP_SHAKE)) + ppb_wdtr(ppbus, ctxmith[byte]); + while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) if (--spin == 0) { return 1; } @@ -420,23 +438,23 @@ clpoutbyte (u_char byte, int spin, struct ppb_device *dev) } static __inline int -clpinbyte (int spin, struct ppb_device *dev) +clpinbyte (int spin, device_t ppbus) { u_char c, cl; - while((ppb_rstr(dev) & CLPIP_SHAKE)) + while((ppb_rstr(ppbus) & CLPIP_SHAKE)) if(!--spin) { return -1; } - cl = ppb_rstr(dev); - ppb_wdtr(dev, 0x10); + cl = ppb_rstr(ppbus); + ppb_wdtr(ppbus, 0x10); - while(!(ppb_rstr(dev) & CLPIP_SHAKE)) + while(!(ppb_rstr(ppbus) & CLPIP_SHAKE)) if(!--spin) { return -1; } - c = ppb_rstr(dev); - ppb_wdtr(dev, 0x00); + c = ppb_rstr(ppbus); + ppb_wdtr(ppbus, 0x00); return (ctrecvl[cl] | ctrecvh[c]); } @@ -460,9 +478,11 @@ lptap(struct ifnet *ifp, struct mbuf *m) } static void -lpintr (int unit) +lp_intr (void *arg) { - struct lpt_softc *sc = lpdata[unit]; + device_t dev = (device_t)arg; + device_t ppbus = device_get_parent(dev); + struct lp_data *sc = DEVTOSOFTC(dev); int len, s, j; u_char *bp; u_char c, cl; @@ -473,14 +493,14 @@ lpintr (int unit) if (sc->sc_if.if_flags & IFF_LINK0) { /* Ack. the request */ - ppb_wdtr(&sc->lp_dev, 0x01); + ppb_wdtr(ppbus, 0x01); /* Get the packet length */ - j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); + j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) goto err; len = j; - j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); + j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) goto err; len = len + (j << 8); @@ -490,14 +510,14 @@ lpintr (int unit) bp = sc->sc_ifbuf; while (len--) { - j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); + j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) { goto err; } *bp++ = j; } /* Get and ignore checksum */ - j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); + j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) { goto err; } @@ -525,27 +545,27 @@ lpintr (int unit) } goto done; } - while ((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) { + while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { len = sc->sc_if.if_mtu + LPIPHDRLEN; bp = sc->sc_ifbuf; while (len--) { - cl = ppb_rstr(&sc->lp_dev); - ppb_wdtr(&sc->lp_dev, 8); + cl = ppb_rstr(ppbus); + ppb_wdtr(ppbus, 8); j = LPMAXSPIN2; - while((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) + while((ppb_rstr(ppbus) & LPIP_SHAKE)) if(!--j) goto err; - c = ppb_rstr(&sc->lp_dev); - ppb_wdtr(&sc->lp_dev, 0); + c = ppb_rstr(ppbus); + ppb_wdtr(ppbus, 0); *bp++= trecvh[cl] | trecvl[c]; j = LPMAXSPIN2; - while (!((cl=ppb_rstr(&sc->lp_dev)) & LPIP_SHAKE)) { + while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) { if (cl != c && - (((cl = ppb_rstr(&sc->lp_dev)) ^ 0xb8) & 0xf8) == + (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) == (c & 0xf8)) goto end; if (!--j) goto err; @@ -578,7 +598,7 @@ lpintr (int unit) goto done; err: - ppb_wdtr(&sc->lp_dev, 0); + ppb_wdtr(ppbus, 0); lprintf("R"); sc->sc_if.if_ierrors++; sc->sc_iferrs++; @@ -588,8 +608,8 @@ lpintr (int unit) * so stop wasting our time */ if (sc->sc_iferrs > LPMAXERRS) { - printf("lp%d: Too many errors, Going off-line.\n", unit); - ppb_wctr(&sc->lp_dev, 0x00); + printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev)); + ppb_wctr(ppbus, 0x00); sc->sc_if.if_flags &= ~IFF_RUNNING; sc->sc_iferrs=0; } @@ -600,14 +620,14 @@ lpintr (int unit) } static __inline int -lpoutbyte (u_char byte, int spin, struct ppb_device *dev) +lpoutbyte (u_char byte, int spin, device_t ppbus) { - ppb_wdtr(dev, txmith[byte]); - while (!(ppb_rstr(dev) & LPIP_SHAKE)) + ppb_wdtr(ppbus, txmith[byte]); + while (!(ppb_rstr(ppbus) & LPIP_SHAKE)) if (--spin == 0) return 1; - ppb_wdtr(dev, txmitl[byte]); - while (ppb_rstr(dev) & LPIP_SHAKE) + ppb_wdtr(ppbus, txmitl[byte]); + while (ppb_rstr(ppbus) & LPIP_SHAKE) if (--spin == 0) return 1; return 0; @@ -617,7 +637,8 @@ static int lpoutput (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { - struct lpt_softc *sc = lpdata[ifp->if_unit]; + device_t dev = UNITODEVICE(ifp->if_unit); + device_t ppbus = device_get_parent(dev); int s, err; struct mbuf *mm; u_char *cp = "\0\0"; @@ -634,19 +655,19 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, s = splhigh(); /* Suspend (on laptops) or receive-errors might have taken us offline */ - ppb_wctr(&sc->lp_dev, IRQENABLE); + ppb_wctr(ppbus, IRQENABLE); if (ifp->if_flags & IFF_LINK0) { - if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) { + if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { lprintf("&"); - lpintr(ifp->if_unit); + lp_intr(dev); } /* Alert other end to pending packet */ spin = LPMAXSPIN1; - ppb_wdtr(&sc->lp_dev, 0x08); - while ((ppb_rstr(&sc->lp_dev) & 0x08) == 0) + ppb_wdtr(ppbus, 0x08); + while ((ppb_rstr(ppbus) & 0x08) == 0) if (--spin == 0) { goto nend; } @@ -659,21 +680,21 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, for (mm = m; mm; mm = mm->m_next) { count += mm->m_len; } - if (clpoutbyte(count & 0xFF, LPMAXSPIN1, &sc->lp_dev)) + if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) goto nend; - if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, &sc->lp_dev)) + if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) goto nend; /* Send dummy ethernet header */ for (i = 0; i < 12; i++) { - if (clpoutbyte(i, LPMAXSPIN1, &sc->lp_dev)) + if (clpoutbyte(i, LPMAXSPIN1, ppbus)) goto nend; chksum += i; } - if (clpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev)) + if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) goto nend; - if (clpoutbyte(0x00, LPMAXSPIN1, &sc->lp_dev)) + if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) goto nend; chksum += 0x08 + 0x00; /* Add into checksum */ @@ -683,17 +704,17 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, len = mm->m_len; while (len--) { chksum += *cp; - if (clpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev)) + if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus)) goto nend; } } while ((mm = mm->m_next)); /* Send checksum */ - if (clpoutbyte(chksum, LPMAXSPIN2, &sc->lp_dev)) + if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) goto nend; /* Go quiescent */ - ppb_wdtr(&sc->lp_dev, 0); + ppb_wdtr(ppbus, 0); err = 0; /* No errors */ @@ -710,22 +731,22 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, m_freem(m); - if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) { + if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { lprintf("^"); - lpintr(ifp->if_unit); + lp_intr(dev); } (void) splx(s); return 0; } - if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) { + if (ppb_rstr(ppbus) & LPIP_SHAKE) { lprintf("&"); - lpintr(ifp->if_unit); + lp_intr(dev); } - if (lpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev)) + if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) goto end; - if (lpoutbyte(0x00, LPMAXSPIN2, &sc->lp_dev)) + if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) goto end; mm = m; @@ -733,7 +754,7 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, cp = mtod(mm,u_char *); len = mm->m_len; while (len--) - if (lpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev)) + if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) goto end; } while ((mm = mm->m_next)); @@ -741,7 +762,7 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, end: --cp; - ppb_wdtr(&sc->lp_dev, txmitl[*cp] ^ 0x17); + ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; @@ -755,11 +776,15 @@ lpoutput (struct ifnet *ifp, struct mbuf *m, m_freem(m); - if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) { + if (ppb_rstr(ppbus) & LPIP_SHAKE) { lprintf("^"); - lpintr(ifp->if_unit); + lp_intr(dev); } (void) splx(s); return 0; } + +DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0); + +#endif /* NPLIP > 0 */ diff --git a/sys/dev/ppbus/immio.c b/sys/dev/ppbus/immio.c index e10f9a1..30d9117 100644 --- a/sys/dev/ppbus/immio.c +++ b/sys/dev/ppbus/immio.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 Nicolas Souchu + * Copyright (c) 1998, 1999 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,8 @@ #ifdef _KERNEL #include <sys/param.h> #include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/malloc.h> #include <sys/buf.h> @@ -49,11 +51,14 @@ #include "opt_vpo.h" +#include <dev/ppbus/ppbio.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> #include <dev/ppbus/vpoio.h> #include <dev/ppbus/ppb_1284.h> +#include "ppbus_if.h" + #define VP0_SELTMO 5000 /* select timeout */ #define VP0_FAST_SPINTMO 500000 /* wait status timeout */ #define VP0_LOW_SPINTMO 5000000 /* wait status timeout */ @@ -275,6 +280,7 @@ imm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus) { DECLARE_CPP_MICROSEQ; + device_t ppbus = device_get_parent(vpo->vpo_dev); char s1, s2, s3; int ret; @@ -286,7 +292,7 @@ imm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus) CPP_S2, (void *)&s2, CPP_S3, (void *)&s3, CPP_PARAM, 0x30); - ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret); if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x38)) { if (bootverbose) @@ -297,7 +303,7 @@ imm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus) } if (release_bus) - return (ppb_release_bus(&vpo->vpo_dev)); + return (ppb_release_bus(ppbus, vpo->vpo_dev)); else return (0); } @@ -310,6 +316,7 @@ imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus) { DECLARE_CPP_MICROSEQ; + device_t ppbus = device_get_parent(vpo->vpo_dev); char s1, s2, s3; int error; int ret; @@ -319,7 +326,7 @@ imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus) *disconnected = 0; if (request_bus) - if ((error = ppb_request_bus(&vpo->vpo_dev, how))) + if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, how))) return (error); ppb_MS_init_msq(cpp_microseq, 3, CPP_S1, (void *)&s1, @@ -327,18 +334,18 @@ imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus) /* select device 0 in compatible mode */ ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0); - ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret); /* disconnect all devices */ ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x30); - ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret); - if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) + if (PPB_IN_EPP_MODE(ppbus)) ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x28); else ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0); - ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret); if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x30)) { if (bootverbose) @@ -359,9 +366,10 @@ imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus) static int imm_detect(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int error; - if ((error = ppb_request_bus(&vpo->vpo_dev, PPB_DONTWAIT))) + if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_DONTWAIT))) return (error); /* disconnect the drive, keep the bus */ @@ -378,7 +386,7 @@ imm_detect(struct vpoio_data *vpo) } /* send SCSI reset signal */ - ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, NULL); + ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, NULL); /* release the bus now */ imm_disconnect(vpo, &error, 1); @@ -396,7 +404,7 @@ imm_detect(struct vpoio_data *vpo) return (0); error: - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); return (VP0_EINITFAILED); } @@ -406,12 +414,13 @@ error: static int imm_outstr(struct vpoio_data *vpo, char *buffer, int size) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int error = 0; - if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) - ppb_reset_epp_timeout(&vpo->vpo_dev); + if (PPB_IN_EPP_MODE(ppbus)) + ppb_reset_epp_timeout(ppbus); - ppb_MS_exec(&vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer, + ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer, (union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error); return (error); @@ -423,12 +432,13 @@ imm_outstr(struct vpoio_data *vpo, char *buffer, int size) static int imm_instr(struct vpoio_data *vpo, char *buffer, int size) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int error = 0; - if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) - ppb_reset_epp_timeout(&vpo->vpo_dev); + if (PPB_IN_EPP_MODE(ppbus)) + ppb_reset_epp_timeout(ppbus); - ppb_MS_exec(&vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer, + ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer, (union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error); return (error); @@ -438,13 +448,14 @@ static char imm_select(struct vpoio_data *vpo, int initiator, int target) { DECLARE_SELECT_MICROSEQUENCE; + device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; /* initialize the select microsequence */ ppb_MS_init_msq(select_microseq, 1, SELECT_TARGET, 1 << initiator | 1 << target); - ppb_MS_microseq(&vpo->vpo_dev, select_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, select_microseq, &ret); return (ret); } @@ -459,15 +470,15 @@ imm_select(struct vpoio_data *vpo, int initiator, int target) static char imm_wait(struct vpoio_data *vpo, int tmo) { - + device_t ppbus = device_get_parent(vpo->vpo_dev); register int k; register char r; - ppb_wctr(&vpo->vpo_dev, 0xc); + ppb_wctr(ppbus, 0xc); /* XXX should be ported to microseq */ k = 0; - while (!((r = ppb_rstr(&vpo->vpo_dev)) & 0x80) && (k++ < tmo)) + while (!((r = ppb_rstr(ppbus)) & 0x80) && (k++ < tmo)) DELAY(1); /* @@ -477,7 +488,7 @@ imm_wait(struct vpoio_data *vpo, int tmo) * 0xa8 = ZIP+ wants command * 0xb8 = end of transfer, ZIP+ is sending status */ - ppb_wctr(&vpo->vpo_dev, 0x4); + ppb_wctr(ppbus, 0x4); if (k < tmo) return (r & 0xb8); @@ -488,26 +499,28 @@ static int imm_negociate(struct vpoio_data *vpo) { DECLARE_NEGOCIATE_MICROSEQ; + device_t ppbus = device_get_parent(vpo->vpo_dev); int negociate_mode; int ret; - if (PPB_IN_NIBBLE_MODE(&vpo->vpo_dev)) + if (PPB_IN_NIBBLE_MODE(ppbus)) negociate_mode = 0; - else if (PPB_IN_PS2_MODE(&vpo->vpo_dev)) + else if (PPB_IN_PS2_MODE(ppbus)) negociate_mode = 1; else return (0); #if 0 /* XXX use standalone code not to depend on ppb_1284 code yet */ - ret = ppb_1284_negociate(&vpo->vpo_dev, negociate_mode); + ret = ppb_1284_negociate(ppbus, negociate_mode); if (ret) return (VP0_ENEGOCIATE); #endif - ppb_MS_init_msq(negociate_microseq, 1, NEGOCIATED_MODE, negociate_mode); + ppb_MS_init_msq(negociate_microseq, 1, + NEGOCIATED_MODE, negociate_mode); - ppb_MS_microseq(&vpo->vpo_dev, negociate_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, negociate_microseq, &ret); return (ret); } @@ -518,21 +531,20 @@ imm_negociate(struct vpoio_data *vpo) * Low level probe of vpo device * */ -struct ppb_device * -imm_probe(struct ppb_data *ppb, struct vpoio_data *vpo) +int +imm_probe(device_t dev, struct vpoio_data *vpo) { + int error; /* ppbus dependent initialisation */ - vpo->vpo_dev.id_unit = vpo->vpo_unit; - vpo->vpo_dev.name = "vpo"; - vpo->vpo_dev.ppb = ppb; + vpo->vpo_dev = dev; /* now, try to initialise the drive */ - if (imm_detect(vpo)) { - return (NULL); + if ((error = imm_detect(vpo))) { + return (error); } - return (&vpo->vpo_dev); + return (0); } /* @@ -544,22 +556,17 @@ imm_probe(struct ppb_data *ppb, struct vpoio_data *vpo) int imm_attach(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int epp; /* - * Report ourselves - */ - printf("imm%d: <Iomega Matchmaker Parallel to SCSI interface> on ppbus %d\n", - vpo->vpo_dev.id_unit, vpo->vpo_dev.ppb->ppb_link->adapter_unit); - - /* * Initialize microsequence code */ vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc( sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT); if (!vpo->vpo_nibble_inbyte_msq) - return (0); + return (ENXIO); bcopy((void *)nibble_inbyte_submicroseq, (void *)vpo->vpo_nibble_inbyte_msq, @@ -570,32 +577,32 @@ imm_attach(struct vpoio_data *vpo) /* * Initialize mode dependent in/out microsequences */ - ppb_request_bus(&vpo->vpo_dev, PPB_WAIT); + ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT); /* enter NIBBLE mode to configure submsq */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) { + if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) { - ppb_MS_GET_init(&vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq); - ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq); + ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq); + ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq); } /* enter PS2 mode to configure submsq */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) { + if (ppb_set_mode(ppbus, PPB_PS2) != -1) { - ppb_MS_GET_init(&vpo->vpo_dev, ps2_inbyte_submicroseq); - ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq); + ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq); + ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq); } - epp = ppb_get_epp_protocol(&vpo->vpo_dev); + epp = ppb_get_epp_protocol(ppbus); /* enter EPP mode to configure submsq */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) { + if (ppb_set_mode(ppbus, PPB_EPP) != -1) { switch (epp) { case EPP_1_9: case EPP_1_7: - ppb_MS_GET_init(&vpo->vpo_dev, epp17_instr); - ppb_MS_PUT_init(&vpo->vpo_dev, epp17_outstr); + ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr); + ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr); break; default: panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__, @@ -604,7 +611,7 @@ imm_attach(struct vpoio_data *vpo) } /* try to enter EPP or PS/2 mode, NIBBLE otherwise */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) { + if (ppb_set_mode(ppbus, PPB_EPP) != -1) { switch (epp) { case EPP_1_9: printf("imm%d: EPP 1.9 mode\n", vpo->vpo_unit); @@ -616,25 +623,25 @@ imm_attach(struct vpoio_data *vpo) panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__, epp); } - } else if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) + } else if (ppb_set_mode(ppbus, PPB_PS2) != -1) printf("imm%d: PS2 mode\n", vpo->vpo_unit); - else if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) + else if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) printf("imm%d: NIBBLE mode\n", vpo->vpo_unit); else { printf("imm%d: can't enter NIBBLE, PS2 or EPP mode\n", vpo->vpo_unit); - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF); - return (0); + return (ENXIO); } - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); - return (1); + return (0); } /* @@ -644,6 +651,7 @@ imm_attach(struct vpoio_data *vpo) int imm_reset_bus(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int disconnected; /* first, connect to the drive and request the bus */ @@ -652,7 +660,7 @@ imm_reset_bus(struct vpoio_data *vpo) if (!disconnected) { /* reset the SCSI bus */ - ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, NULL); + ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, NULL); /* then disconnect */ imm_disconnect(vpo, NULL, 1); @@ -672,7 +680,7 @@ imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, int clen, char *buffer, int blen, int *result, int *count, int *ret) { - + device_t ppbus = device_get_parent(vpo->vpo_dev); register char r; char l, h = 0; int len, error = 0, not_connected = 0; @@ -752,7 +760,7 @@ imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, error = imm_outstr(vpo, &buffer[*count], len); } else { - if (!PPB_IN_EPP_MODE(&vpo->vpo_dev)) + if (!PPB_IN_EPP_MODE(ppbus)) len = 1; else len = (((blen - *count) >= VP0_SECTOR_SIZE)) ? @@ -769,9 +777,9 @@ imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, *count += len; } - if ((PPB_IN_NIBBLE_MODE(&vpo->vpo_dev) || - PPB_IN_PS2_MODE(&vpo->vpo_dev)) && negociated) - ppb_MS_microseq(&vpo->vpo_dev, transfer_epilog, NULL); + if ((PPB_IN_NIBBLE_MODE(ppbus) || + PPB_IN_PS2_MODE(ppbus)) && negociated) + ppb_MS_microseq(ppbus, vpo->vpo_dev, transfer_epilog, NULL); /* * Retrieve status ... @@ -795,9 +803,9 @@ imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, *result = ((int) h << 8) | ((int) l & 0xff); error: - if ((PPB_IN_NIBBLE_MODE(&vpo->vpo_dev) || - PPB_IN_PS2_MODE(&vpo->vpo_dev)) && negociated) - ppb_MS_microseq(&vpo->vpo_dev, transfer_epilog, NULL); + if ((PPB_IN_NIBBLE_MODE(ppbus) || + PPB_IN_PS2_MODE(ppbus)) && negociated) + ppb_MS_microseq(ppbus, vpo->vpo_dev, transfer_epilog, NULL); /* return to printer state, release the ppbus */ imm_disconnect(vpo, NULL, 1); diff --git a/sys/dev/ppbus/lpbb.c b/sys/dev/ppbus/lpbb.c index b98f80e2..5b0c75e 100644 --- a/sys/dev/ppbus/lpbb.c +++ b/sys/dev/ppbus/lpbb.c @@ -46,19 +46,19 @@ #include <machine/clock.h> #include <dev/ppbus/ppbconf.h> +#include "ppbus_if.h" +#include <dev/ppbus/ppbio.h> #include <dev/iicbus/iiconf.h> #include <dev/iicbus/iicbus.h> #include "iicbb_if.h" -/* iicbus softc */ struct lpbb_softc { - - struct ppb_device lpbb_dev; + int dummy; }; -static int lpbb_detect(struct lpbb_softc *); +static int lpbb_detect(device_t dev); static int lpbb_probe(device_t); static int lpbb_attach(device_t); @@ -93,38 +93,14 @@ static driver_t lpbb_driver = { sizeof(struct lpbb_softc), }; -/* - * Make ourselves visible as a ppbus driver - */ -static struct ppb_device *lpbb_ppb_probe(struct ppb_data *ppb); -static int lpbb_ppb_attach(struct ppb_device *dev); - -#define MAXLPBB 8 /* XXX not much better! */ -static struct lpbb_softc *lpbbdata[MAXLPBB]; -static int nlpbb = 0; - -#ifdef _KERNEL - -static struct ppb_driver lpbbdriver = { - lpbb_ppb_probe, lpbb_ppb_attach, "lpbb" -}; -DATA_SET(ppbdriver_set, lpbbdriver); - -#endif - static int lpbb_probe(device_t dev) { - struct lpbb_softc *sc = lpbbdata[device_get_unit(dev)]; - struct lpbb_softc *scdst = (struct lpbb_softc *)device_get_softc(dev); - - /* XXX copy softc. Yet, ppbus device is sc->lpbb_dev, but will be - * dev->parent when ppbus will be ported to the new bus architecture */ - bcopy(sc, scdst, sizeof(struct lpbb_softc)); + device_set_desc(dev, "Parallel I2C bit-banging interface"); - device_set_desc(dev, "parallel I2C bit-banging interface"); + if (!lpbb_detect(dev)) + return (ENXIO); - /* probe done by ppbus initialization */ return (0); } @@ -147,60 +123,10 @@ lpbb_attach(device_t dev) return (0); } -/* - * lppbb_ppb_probe() - */ -static struct ppb_device * -lpbb_ppb_probe(struct ppb_data *ppb) -{ - struct lpbb_softc *sc; - - sc = (struct lpbb_softc *) malloc(sizeof(struct lpbb_softc), - M_TEMP, M_NOWAIT); - if (!sc) { - printf("lpbb: cannot malloc!\n"); - return (0); - } - bzero(sc, sizeof(struct lpbb_softc)); - - lpbbdata[nlpbb] = sc; - - /* - * ppbus dependent initialisation. - */ - sc->lpbb_dev.id_unit = nlpbb; - sc->lpbb_dev.name = lpbbdriver.name; - sc->lpbb_dev.ppb = ppb; - sc->lpbb_dev.intr = 0; - - if (!lpbb_detect(sc)) { - free(sc, M_TEMP); - return (NULL); - } - - /* Ok, go to next device on next probe */ - nlpbb ++; - - /* XXX wrong according to new bus architecture. ppbus needs to be - * ported - */ - return (&sc->lpbb_dev); -} - -static int -lpbb_ppb_attach(struct ppb_device *dev) -{ - /* add the parallel port I2C interface to the bus tree */ - if (!device_add_child(root_bus, "lpbb", dev->id_unit)) - return (0); - - return (1); -} - static int lpbb_callback(device_t dev, int index, caddr_t *data) { - struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + device_t ppbus = device_get_parent(dev); int error = 0; int how; @@ -208,12 +134,12 @@ lpbb_callback(device_t dev, int index, caddr_t *data) case IIC_REQUEST_BUS: /* request the ppbus */ how = *(int *)data; - error = ppb_request_bus(&sc->lpbb_dev, how); + error = ppb_request_bus(ppbus, dev, how); break; case IIC_RELEASE_BUS: /* release the ppbus */ - error = ppb_release_bus(&sc->lpbb_dev); + error = ppb_release_bus(ppbus, dev); break; default: @@ -230,49 +156,51 @@ lpbb_callback(device_t dev, int index, caddr_t *data) #define ALIM 0x20 #define I2CKEY 0x50 -static int getSDA(struct lpbb_softc *sc) +static int getSDA(device_t ppbus) { -if((ppb_rstr(&sc->lpbb_dev)&SDA_in)==SDA_in) - return 1; -else - return 0; + if((ppb_rstr(ppbus)&SDA_in)==SDA_in) + return 1; + else + return 0; } -static void setSDA(struct lpbb_softc *sc, char val) +static void setSDA(device_t ppbus, char val) { -if(val==0) - ppb_wdtr(&sc->lpbb_dev, (u_char)SDA_out); -else - ppb_wdtr(&sc->lpbb_dev, (u_char)~SDA_out); + if(val==0) + ppb_wdtr(ppbus, (u_char)SDA_out); + else + ppb_wdtr(ppbus, (u_char)~SDA_out); } -static void setSCL(struct lpbb_softc *sc, unsigned char val) +static void setSCL(device_t ppbus, unsigned char val) { -if(val==0) - ppb_wctr(&sc->lpbb_dev, (u_char)(ppb_rctr(&sc->lpbb_dev)&~SCL_out)); -else - ppb_wctr(&sc->lpbb_dev, (u_char)(ppb_rctr(&sc->lpbb_dev)|SCL_out)); + if(val==0) + ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus)&~SCL_out)); + else + ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus)|SCL_out)); } -static int lpbb_detect(struct lpbb_softc *sc) +static int lpbb_detect(device_t dev) { - if (ppb_request_bus(&sc->lpbb_dev, PPB_DONTWAIT)) { - printf("lpbb: can't allocate ppbus\n"); + device_t ppbus = device_get_parent(dev); + + if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { + device_printf(dev, "can't allocate ppbus\n"); return (0); } /* reset bus */ - setSDA(sc, 1); - setSCL(sc, 1); + setSDA(ppbus, 1); + setSCL(ppbus, 1); - if ((ppb_rstr(&sc->lpbb_dev) & I2CKEY) || - ((ppb_rstr(&sc->lpbb_dev) & ALIM) != ALIM)) { + if ((ppb_rstr(ppbus) & I2CKEY) || + ((ppb_rstr(ppbus) & ALIM) != ALIM)) { - ppb_release_bus(&sc->lpbb_dev); + ppb_release_bus(ppbus, dev); return (0); } - ppb_release_bus(&sc->lpbb_dev); + ppb_release_bus(ppbus, dev); return (1); } @@ -280,11 +208,11 @@ static int lpbb_detect(struct lpbb_softc *sc) static int lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) { - struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + device_t ppbus = device_get_parent(dev); /* reset bus */ - setSDA(sc, 1); - setSCL(sc, 1); + setSDA(ppbus, 1); + setSCL(ppbus, 1); return (IIC_ENOADDR); } @@ -292,18 +220,18 @@ lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) static void lpbb_setlines(device_t dev, int ctrl, int data) { - struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + device_t ppbus = device_get_parent(dev); - setSCL(sc, ctrl); - setSDA(sc, data); + setSCL(ppbus, ctrl); + setSDA(ppbus, data); } static int lpbb_getdataline(device_t dev) { - struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + device_t ppbus = device_get_parent(dev); - return (getSDA(sc)); + return (getSDA(ppbus)); } -DRIVER_MODULE(lpbb, root, lpbb_driver, lpbb_devclass, 0, 0); +DRIVER_MODULE(lpbb, ppbus, lpbb_driver, lpbb_devclass, 0, 0); diff --git a/sys/dev/ppbus/lpt.c b/sys/dev/ppbus/lpt.c index 531ad48..f652a81 100644 --- a/sys/dev/ppbus/lpt.c +++ b/sys/dev/ppbus/lpt.c @@ -60,28 +60,37 @@ * Updated for ppbus by Nicolas Souchu * [Mon Jul 28 1997] */ +#include "lpt.h" +#if NLPT > 0 #ifdef _KERNEL +#include "opt_lpt.h" + #include <sys/param.h> #include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/conf.h> #include <sys/buf.h> #include <sys/kernel.h> #include <sys/uio.h> #include <sys/syslog.h> -#include <sys/malloc.h> #include <machine/clock.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + #include <machine/lpt.h> #endif #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_1284.h> #include <dev/ppbus/lpt.h> - -#include "opt_lpt.h" +#include "ppbus_if.h" +#include <dev/ppbus/ppbio.h> #ifndef LPT_DEBUG #define lprintf(args) @@ -105,9 +114,6 @@ static int volatile lptflag = 1; #define LPTFLAGS(s) ((s)&0xfc) struct lpt_data { - unsigned short lpt_unit; - - struct ppb_device lpt_dev; short sc_state; /* default case: negative prime, negative ack, handshake strobe, @@ -132,36 +138,45 @@ struct lpt_data { #define LP_ENABLE_EXT 0x10 /* we shall use advanced mode when possible */ u_char sc_backoff ; /* time to call lptout() again */ -}; + struct resource *intr_resource; /* interrupt resource */ + void *intr_cookie; /* interrupt registration cookie */ -static int nlpt = 0; -#define MAXLPT 8 /* XXX not much better! */ -static struct lpt_data *lptdata[MAXLPT]; +}; #define LPT_NAME "lpt" /* our official name */ static timeout_t lptout; -static int lpt_port_test(struct lpt_data *sc, u_char data, u_char mask); -static int lpt_detect(struct lpt_data *sc); +static int lpt_port_test(device_t dev, u_char data, u_char mask); +static int lpt_detect(device_t dev); -/* - * Make ourselves visible as a ppbus driver - */ +#define DEVTOSOFTC(dev) \ + ((struct lpt_data *)device_get_softc(dev)) +#define UNITOSOFTC(unit) \ + ((struct lpt_data *)devclass_get_softc(lpt_devclass, (unit))) +#define UNITODEVICE(unit) \ + (devclass_get_device(lpt_devclass, (unit))) -static struct ppb_device *lptprobe(struct ppb_data *ppb); -static int lptattach(struct ppb_device *dev); -static void lptintr(int unit); +static int lpt_probe(device_t dev); +static int lpt_attach(device_t dev); -static void lpt_intr(int unit); /* without spls */ +static void lptintr(device_t dev); +static void lpt_intr(void *arg); /* without spls */ -#ifdef _KERNEL +static devclass_t lpt_devclass; + +static device_method_t lpt_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, lpt_probe), + DEVMETHOD(device_attach, lpt_attach), -static struct ppb_driver lptdriver = { - lptprobe, lptattach, LPT_NAME + { 0, 0 } }; -DATA_SET(ppbdriver_set, lptdriver); -#endif +static driver_t lpt_driver = { + "lpt", + lpt_methods, + sizeof(struct lpt_data), +}; /* bits for state */ #define OPEN (1<<0) /* device is open */ @@ -184,7 +199,7 @@ DATA_SET(ppbdriver_set, lptdriver); /* Only used in polling code */ #define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) #define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) -#define NOT_READY(lpt) ((ppb_rstr(&(lpt)->lpt_dev)^LPS_INVERT)&LPS_MASK) +#define NOT_READY(ppbus) ((ppb_rstr(ppbus)^LPS_INVERT)&LPS_MASK) #define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */ #define MAX_SPIN 20 /* Max delay for device ready in usecs */ @@ -215,43 +230,49 @@ static struct cdevsw lpt_cdevsw = { }; static int -lpt_request_ppbus(struct lpt_data *sc, int how) +lpt_request_ppbus(device_t dev, int how) { + device_t ppbus = device_get_parent(dev); + struct lpt_data *sc = DEVTOSOFTC(dev); int error; if (sc->sc_state & HAVEBUS) return (0); /* we have the bus only if the request succeded */ - if ((error = ppb_request_bus(&sc->lpt_dev, how)) == 0) + if ((error = ppb_request_bus(ppbus, dev, how)) == 0) sc->sc_state |= HAVEBUS; return (error); } static int -lpt_release_ppbus(struct lpt_data *sc) +lpt_release_ppbus(device_t dev) { - ppb_release_bus(&sc->lpt_dev); - sc->sc_state &= ~HAVEBUS; + device_t ppbus = device_get_parent(dev); + struct lpt_data *sc = DEVTOSOFTC(dev); + int error = 0; - return (0); + if ((error = ppb_release_bus(ppbus, dev)) == 0) + sc->sc_state &= ~HAVEBUS; + + return (error); } /* * Internal routine to lptprobe to do port tests of one byte value */ static int -lpt_port_test(struct lpt_data *sc, u_char data, u_char mask) +lpt_port_test(device_t ppbus, u_char data, u_char mask) { int temp, timeout; data = data & mask; - ppb_wdtr(&sc->lpt_dev, data); + ppb_wdtr(ppbus, data); timeout = 10000; do { DELAY(10); - temp = ppb_rdtr(&sc->lpt_dev) & mask; + temp = ppb_rdtr(ppbus) & mask; } while (temp != data && --timeout); lprintf(("out=%x\tin=%x\ttout=%d\n", data, temp, timeout)); @@ -306,8 +327,10 @@ lpt_port_test(struct lpt_data *sc, u_char data, u_char mask) * Quick exit on fail added. */ static int -lpt_detect(struct lpt_data *sc) +lpt_detect(device_t dev) { + device_t ppbus = device_get_parent(dev); + static u_char testbyte[18] = { 0x55, /* alternating zeros */ 0xaa, /* alternating ones */ @@ -320,33 +343,33 @@ lpt_detect(struct lpt_data *sc) status = 1; /* assume success */ - if ((error = lpt_request_ppbus(sc, PPB_DONTWAIT))) { + if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); status = 0; goto end_probe; } for (i = 0; i < 18 && status; i++) - if (!lpt_port_test(sc, testbyte[i], 0xff)) { + if (!lpt_port_test(ppbus, testbyte[i], 0xff)) { status = 0; goto end_probe; } end_probe: /* write 0's to control and data ports */ - ppb_wdtr(&sc->lpt_dev, 0); - ppb_wctr(&sc->lpt_dev, 0); + ppb_wdtr(ppbus, 0); + ppb_wctr(ppbus, 0); - lpt_release_ppbus(sc); + lpt_release_ppbus(dev); return (status); } /* - * lptprobe() + * lpt_probe() */ -static struct ppb_device * -lptprobe(struct ppb_data *ppb) +static int +lpt_probe(device_t dev) { struct lpt_data *sc; static int once; @@ -354,96 +377,81 @@ lptprobe(struct ppb_data *ppb) if (!once++) cdevsw_add(&lpt_cdevsw); - sc = (struct lpt_data *) malloc(sizeof(struct lpt_data), - M_TEMP, M_NOWAIT); - if (!sc) { - printf(LPT_NAME ": cannot malloc!\n"); - return (0); - } + sc = DEVTOSOFTC(dev); bzero(sc, sizeof(struct lpt_data)); - lptdata[nlpt] = sc; - - /* - * lpt dependent initialisation. - */ - sc->lpt_unit = nlpt; - - /* - * ppbus dependent initialisation. - */ - sc->lpt_dev.id_unit = sc->lpt_unit; - sc->lpt_dev.name = lptdriver.name; - sc->lpt_dev.ppb = ppb; - sc->lpt_dev.intr = lptintr; - /* * Now, try to detect the printer. */ - if (!lpt_detect(sc)) { - free(sc, M_TEMP); - return (0); - } + if (!lpt_detect(dev)) + return (ENXIO); - /* Ok, go to next device on next probe */ - nlpt ++; + device_set_desc(dev, "Printer"); - return (&sc->lpt_dev); + return (0); } static int -lptattach(struct ppb_device *dev) +lpt_attach(device_t dev) { - struct lpt_data *sc = lptdata[dev->id_unit]; + device_t ppbus = device_get_parent(dev); + struct lpt_data *sc = DEVTOSOFTC(dev); + int zero = 0, irq, unit = device_get_unit(dev); int error; - /* - * Report ourselves - */ - printf(LPT_NAME "%d: <generic printer> on ppbus %d\n", - dev->id_unit, dev->ppb->ppb_link->adapter_unit); - sc->sc_primed = 0; /* not primed yet */ - if ((error = lpt_request_ppbus(sc, PPB_DONTWAIT))) { + if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); return (0); } - ppb_wctr(&sc->lpt_dev, LPC_NINIT); + ppb_wctr(ppbus, LPC_NINIT); /* check if we can use interrupt, should be done by ppc stuff */ lprintf(("oldirq %x\n", sc->sc_irq)); - if (ppb_get_irq(&sc->lpt_dev)) { + + /* retrieve the ppbus irq */ + BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); + + if (irq > 0) { + /* declare our interrupt handler */ + sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, + &zero, irq, irq, 1, RF_SHAREABLE); + } + if (sc->intr_resource) { sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; - printf(LPT_NAME "%d: Interrupt-driven port\n", dev->id_unit); + device_printf(dev, "Interrupt-driven port\n"); } else { sc->sc_irq = 0; - lprintf((LPT_NAME "%d: Polled port\n", dev->id_unit)); + device_printf(dev, "Polled port\n"); } - lprintf(("irq %x\n", sc->sc_irq)); + lprintf(("irq %x %x\n", irq, sc->sc_irq)); - lpt_release_ppbus(sc); + lpt_release_ppbus(dev); - make_dev(&lpt_cdevsw, dev->id_unit, - UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d", dev->id_unit); - make_dev(&lpt_cdevsw, dev->id_unit | LP_BYPASS, - UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d.ctl", dev->id_unit); - return (1); + make_dev(&lpt_cdevsw, unit, + UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d", unit); + make_dev(&lpt_cdevsw, unit | LP_BYPASS, + UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d.ctl", unit); + return (0); } static void lptout(void *arg) { - struct lpt_data *sc = arg; - int pl; + device_t dev = (device_t)arg; + struct lpt_data *sc = DEVTOSOFTC(dev); +#ifdef LPT_DEBUG + device_t ppbus = device_get_parent(dev); +#endif - lprintf(("T %x ", ppb_rstr(&sc->lpt_dev))); + lprintf(("T %x ", ppb_rstr(ppbus))); if (sc->sc_state & OPEN) { sc->sc_backoff++; if (sc->sc_backoff > hz/LPTOUTMAX) sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX; - timeout(lptout, (caddr_t)sc, sc->sc_backoff); + timeout(lptout, (caddr_t)dev, sc->sc_backoff); } else sc->sc_state &= ~TOUT; @@ -451,15 +459,13 @@ lptout(void *arg) sc->sc_state &= ~EERROR; /* - * Avoid possible hangs do to missed interrupts + * Avoid possible hangs due to missed interrupts */ if (sc->sc_xfercnt) { - pl = spltty(); - lpt_intr(sc->lpt_unit); - splx(pl); + lptintr(dev); } else { sc->sc_state &= ~OBUSY; - wakeup((caddr_t)sc); + wakeup((caddr_t)dev); } } @@ -472,17 +478,16 @@ lptout(void *arg) static int lptopen(dev_t dev, int flags, int fmt, struct proc *p) { - struct lpt_data *sc; - int s; int trys, err; u_int unit = LPTUNIT(minor(dev)); + struct lpt_data *sc = UNITOSOFTC(unit); + device_t lptdev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(lptdev); - if ((unit >= nlpt)) + if (!sc) return (ENXIO); - sc = lptdata[unit]; - if (sc->sc_state) { lprintf((LPT_NAME ": still open %x\n", sc->sc_state)); return(EBUSY); @@ -498,13 +503,17 @@ lptopen(dev_t dev, int flags, int fmt, struct proc *p) } /* request the ppbus only if we don't have it already */ - if ((err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)) != 0) + if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { + /* give it a chance to try later */ + sc->sc_state = 0; return (err); + } s = spltty(); lprintf((LPT_NAME " flags 0x%x\n", sc->sc_flags)); - /* set IRQ status according to ENABLE_IRQ flag */ + /* set IRQ status according to ENABLE_IRQ flag + */ if (sc->sc_irq & LP_ENABLE_IRQ) sc->sc_irq |= LP_USE_IRQ; else @@ -513,13 +522,13 @@ lptopen(dev_t dev, int flags, int fmt, struct proc *p) /* init printer */ if ((sc->sc_flags & LP_NO_PRIME) == 0) { if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { - ppb_wctr(&sc->lpt_dev, 0); + ppb_wctr(ppbus, 0); sc->sc_primed++; DELAY(500); } } - ppb_wctr(&sc->lpt_dev, LPC_SEL|LPC_NINIT); + ppb_wctr(ppbus, LPC_SEL|LPC_NINIT); /* wait till ready (printer running diagnostics) */ trys = 0; @@ -528,24 +537,24 @@ lptopen(dev_t dev, int flags, int fmt, struct proc *p) if (trys++ >= LPINITRDY*4) { splx(s); sc->sc_state = 0; - lprintf(("status %x\n", ppb_rstr(&sc->lpt_dev))); + lprintf(("status %x\n", ppb_rstr(ppbus))); - lpt_release_ppbus(sc); + lpt_release_ppbus(lptdev); return (EBUSY); } /* wait 1/4 second, give up if we get a signal */ - if (tsleep((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) != + if (tsleep((caddr_t)lptdev, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) { sc->sc_state = 0; splx(s); - lpt_release_ppbus(sc); + lpt_release_ppbus(lptdev); return (EBUSY); } /* is printer online and ready for output */ - } while ((ppb_rstr(&sc->lpt_dev) & + } while ((ppb_rstr(ppbus) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR)); @@ -557,7 +566,7 @@ lptopen(dev_t dev, int flags, int fmt, struct proc *p) if (sc->sc_irq & LP_USE_IRQ) sc->sc_control |= LPC_ENA; - ppb_wctr(&sc->lpt_dev, sc->sc_control); + ppb_wctr(ppbus, sc->sc_control); sc->sc_state = OPEN; sc->sc_inbuf = geteblk(BUFSIZE); @@ -566,13 +575,13 @@ lptopen(dev_t dev, int flags, int fmt, struct proc *p) splx(s); /* release the ppbus */ - lpt_release_ppbus(sc); + lpt_release_ppbus(lptdev); /* only use timeout if using interrupt */ lprintf(("irq %x\n", sc->sc_irq)); if (sc->sc_irq & LP_USE_IRQ) { sc->sc_state |= TOUT; - timeout(lptout, (caddr_t)sc, + timeout(lptout, (caddr_t)lptdev, (sc->sc_backoff = hz/LPTOUTINITIAL)); } @@ -589,34 +598,39 @@ lptopen(dev_t dev, int flags, int fmt, struct proc *p) static int lptclose(dev_t dev, int flags, int fmt, struct proc *p) { - struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))]; + u_int unit = LPTUNIT(minor(dev)); + struct lpt_data *sc = UNITOSOFTC(unit); + device_t lptdev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(lptdev); int err; if(sc->sc_flags & LP_BYPASS) goto end_close; - if ((err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)) != 0) + if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) return (err); sc->sc_state &= ~OPEN; /* if the last write was interrupted, don't complete it */ if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) - while ((ppb_rstr(&sc->lpt_dev) & + while ((ppb_rstr(ppbus) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) /* wait 1/4 second, give up if we get a signal */ - if (tsleep((caddr_t)sc, LPPRI|PCATCH, + if (tsleep((caddr_t)lptdev, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK) break; - ppb_wctr(&sc->lpt_dev, LPC_NINIT); + ppb_wctr(ppbus, LPC_NINIT); brelse(sc->sc_inbuf); brelse(sc->sc_statbuf); end_close: - /* release the bus anyway */ - lpt_release_ppbus(sc); + /* release the bus anyway + * unregistration of interrupt forced by release + */ + lpt_release_ppbus(lptdev); sc->sc_state = 0; sc->sc_xfercnt = 0; @@ -633,8 +647,10 @@ end_close: * This code is only used when we are polling the port */ static int -lpt_pushbytes(struct lpt_data *sc) +lpt_pushbytes(device_t dev) { + struct lpt_data *sc = DEVTOSOFTC(dev); + device_t ppbus = device_get_parent(dev); int spin, err, tic; char ch; @@ -651,11 +667,11 @@ lpt_pushbytes(struct lpt_data *sc) * Loop 20 usecs testing BUSY bit, then sleep * for exponentially increasing timeout. (vak) */ - for (spin = 0; NOT_READY(sc) && spin < MAX_SPIN; ++spin) + for (spin = 0; NOT_READY(ppbus) && spin < MAX_SPIN; ++spin) DELAY(1); /* XXX delay is NOT this accurate! */ if (spin >= MAX_SPIN) { tic = 0; - while (NOT_READY(sc)) { + while (NOT_READY(ppbus)) { /* * Now sleep, every cycle a * little longer .. @@ -666,7 +682,7 @@ lpt_pushbytes(struct lpt_data *sc) */ if (tic > MAX_SLEEP) tic = MAX_SLEEP; - err = tsleep((caddr_t)sc, LPPRI, + err = tsleep((caddr_t)dev, LPPRI, LPT_NAME "poll", tic); if (err != EWOULDBLOCK) { return (err); @@ -675,10 +691,10 @@ lpt_pushbytes(struct lpt_data *sc) } /* output data */ - ppb_wdtr(&sc->lpt_dev, ch); + ppb_wdtr(ppbus, ch); /* strobe */ - ppb_wctr(&sc->lpt_dev, sc->sc_control|LPC_STB); - ppb_wctr(&sc->lpt_dev, sc->sc_control); + ppb_wctr(ppbus, sc->sc_control|LPC_STB); + ppb_wctr(ppbus, sc->sc_control); } return(0); @@ -691,16 +707,19 @@ lpt_pushbytes(struct lpt_data *sc) static int lptread(dev_t dev, struct uio *uio, int ioflag) { - struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))]; + u_int unit = LPTUNIT(minor(dev)); + struct lpt_data *sc = UNITOSOFTC(unit); + device_t lptdev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(lptdev); int error = 0, len; - if ((error = ppb_1284_negociate(&sc->lpt_dev, PPB_NIBBLE, 0))) + if ((error = ppb_1284_negociate(ppbus, PPB_NIBBLE, 0))) return (error); /* read data in an other buffer, read/write may be simultaneous */ len = 0; while (uio->uio_resid) { - if ((error = ppb_1284_read(&sc->lpt_dev, PPB_NIBBLE, + if ((error = ppb_1284_read(ppbus, PPB_NIBBLE, sc->sc_statbuf->b_data, min(BUFSTATSIZE, uio->uio_resid), &len))) { goto error; @@ -714,7 +733,7 @@ lptread(dev_t dev, struct uio *uio, int ioflag) } error: - ppb_1284_terminate(&sc->lpt_dev); + ppb_1284_terminate(ppbus); return (error); } @@ -729,9 +748,11 @@ static int lptwrite(dev_t dev, struct uio *uio, int ioflag) { register unsigned n; - int pl, err; + int err; u_int unit = LPTUNIT(minor(dev)); - struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))]; + struct lpt_data *sc = UNITOSOFTC(unit); + device_t lptdev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(lptdev); if(sc->sc_flags & LP_BYPASS) { /* we can't do writes in bypass mode */ @@ -739,9 +760,22 @@ lptwrite(dev_t dev, struct uio *uio, int ioflag) } /* request the ppbus only if we don't have it already */ - if ((err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)) != 0) + /* XXX interrupt registration?! */ + if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) return (err); + /* if interrupts are working, register the handler */ + if (sc->sc_irq & LP_USE_IRQ) { + /* register our interrupt handler */ + err = BUS_SETUP_INTR(ppbus, lptdev, sc->intr_resource, + INTR_TYPE_TTY, lpt_intr, lptdev, + &sc->intr_cookie); + if (err) { + device_printf(lptdev, "handler registration failed, polled mode.\n"); + sc->sc_irq &= ~LP_USE_IRQ; + } + } + sc->sc_state &= ~INTERRUPTED; while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { sc->sc_cp = sc->sc_inbuf->b_data ; @@ -750,8 +784,8 @@ lptwrite(dev_t dev, struct uio *uio, int ioflag) if (sc->sc_irq & LP_ENABLE_EXT) { /* try any extended mode */ - err = ppb_write(&sc->lpt_dev, sc->sc_cp, - sc->sc_xfercnt, 0); + err = ppb_write(ppbus, sc->sc_cp, + sc->sc_xfercnt, 0); switch (err) { case 0: /* if not all data was sent, we could rely @@ -774,13 +808,11 @@ lptwrite(dev_t dev, struct uio *uio, int ioflag) /* give it one */ if ((sc->sc_state & OBUSY) == 0){ lprintf(("\nC %d. ", sc->sc_xfercnt)); - pl = spltty(); - lpt_intr(sc->lpt_unit); - (void) splx(pl); + lptintr(lptdev); } lprintf(("W ")); if (sc->sc_state & OBUSY) - if ((err = tsleep((caddr_t)sc, + if ((err = tsleep((caddr_t)lptdev, LPPRI|PCATCH, LPT_NAME "write", 0))) { sc->sc_state |= INTERRUPTED; return(err); @@ -791,7 +823,7 @@ lptwrite(dev_t dev, struct uio *uio, int ioflag) if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { lprintf(("p")); - err = lpt_pushbytes(sc); + err = lpt_pushbytes(lptdev); if (err) return(err); @@ -799,7 +831,7 @@ lptwrite(dev_t dev, struct uio *uio, int ioflag) } /* we have not been interrupted, release the ppbus */ - lpt_release_ppbus(sc); + lpt_release_ppbus(lptdev); return(0); } @@ -812,9 +844,11 @@ lptwrite(dev_t dev, struct uio *uio, int ioflag) */ static void -lpt_intr(int unit) +lpt_intr(void *arg) { - struct lpt_data *sc = lptdata[unit]; + device_t lptdev = (device_t)arg; + device_t ppbus = device_get_parent(lptdev); + struct lpt_data *sc = DEVTOSOFTC(lptdev); int sts; int i; @@ -829,7 +863,7 @@ lpt_intr(int unit) * to see if the printer will become ready ``really soon now''. */ for (i = 0; i < 100 && - ((sts=ppb_rstr(&sc->lpt_dev)) & RDY_MASK) != LP_READY; i++) ; + ((sts=ppb_rstr(ppbus)) & RDY_MASK) != LP_READY; i++) ; if ((sts & RDY_MASK) == LP_READY) { sc->sc_state = (sc->sc_state | OBUSY) & ~EERROR; @@ -838,10 +872,10 @@ lpt_intr(int unit) if (sc->sc_xfercnt) { /* send char */ /*lprintf(("%x ", *sc->sc_cp)); */ - ppb_wdtr(&sc->lpt_dev, *sc->sc_cp++) ; - ppb_wctr(&sc->lpt_dev, sc->sc_control|LPC_STB); + ppb_wdtr(ppbus, *sc->sc_cp++) ; + ppb_wctr(ppbus, sc->sc_control|LPC_STB); /* DELAY(X) */ - ppb_wctr(&sc->lpt_dev, sc->sc_control); + ppb_wctr(ppbus, sc->sc_control); /* any more data for printer */ if(--(sc->sc_xfercnt) > 0) return; @@ -867,12 +901,12 @@ lpt_intr(int unit) } static void -lptintr(int unit) +lptintr(device_t dev) { /* call the interrupt at required spl level */ int s = spltty(); - lpt_intr(unit); + lpt_intr(dev); splx(s); return; @@ -882,12 +916,10 @@ static int lptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { int error = 0; - struct lpt_data *sc; u_int unit = LPTUNIT(minor(dev)); + struct lpt_data *sc = UNITOSOFTC(unit); u_char old_sc_irq; /* old printer IRQ status */ - sc = lptdata[unit]; - switch (cmd) { case LPT_IRQ : if(sc->sc_irq & LP_HAS_IRQ) { @@ -939,3 +971,8 @@ lptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) return(error); } + +DRIVER_MODULE(lpt, ppbus, lpt_driver, lpt_devclass, 0, 0); + +#endif + diff --git a/sys/dev/ppbus/ppb_1284.c b/sys/dev/ppbus/ppb_1284.c index 3022174..2040874 100644 --- a/sys/dev/ppbus/ppb_1284.c +++ b/sys/dev/ppbus/ppb_1284.c @@ -35,27 +35,34 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/bus.h> #include <machine/clock.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_1284.h> +#include "ppbus_if.h" + +#include <dev/ppbus/ppbio.h> + +#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) + /* * do_1284_wait() * * Wait for the peripherial up to 40ms */ static int -do_1284_wait(struct ppb_device *dev, char mask, char status) +do_1284_wait(device_t bus, char mask, char status) { - return (ppb_poll_device(dev, 4, mask, status, PPB_NOINTR | PPB_POLL)); + return (ppb_poll_bus(bus, 4, mask, status, PPB_NOINTR | PPB_POLL)); } static int -do_peripheral_wait(struct ppb_device *dev, char mask, char status) +do_peripheral_wait(device_t bus, char mask, char status) { - return (ppb_poll_device(dev, 100, mask, status, PPB_NOINTR | PPB_POLL)); + return (ppb_poll_bus(bus, 100, mask, status, PPB_NOINTR | PPB_POLL)); } #define nibble2char(s) (((s & ~nACK) >> 3) | (~s & nBUSY) >> 4) @@ -66,10 +73,12 @@ do_peripheral_wait(struct ppb_device *dev, char mask, char status) * Unconditionaly reset the error field */ static int -ppb_1284_reset_error(struct ppb_device *dev, int state) +ppb_1284_reset_error(device_t bus, int state) { - dev->ppb->error = PPB_NO_ERROR; - dev->ppb->state = state; + struct ppb_data *ppb = DEVTOSOFTC(bus); + + ppb->error = PPB_NO_ERROR; + ppb->state = state; return (0); } @@ -80,9 +89,9 @@ ppb_1284_reset_error(struct ppb_device *dev, int state) * Get IEEE1284 state */ static int -ppb_1284_get_state(struct ppb_device *dev) +ppb_1284_get_state(device_t bus) { - return (dev->ppb->state); + return (DEVTOSOFTC(bus)->state); } /* @@ -91,32 +100,36 @@ ppb_1284_get_state(struct ppb_device *dev) * Change IEEE1284 state if no error occured */ static int -ppb_1284_set_state(struct ppb_device *dev, int state) +ppb_1284_set_state(device_t bus, int state) { + struct ppb_data *ppb = DEVTOSOFTC(bus); + /* call ppb_1284_reset_error() if you absolutly want to change * the state from PPB_ERROR to another */ - if ((dev->ppb->state != PPB_ERROR) && - (dev->ppb->error == PPB_NO_ERROR)) { - dev->ppb->state = state; - dev->ppb->error = PPB_NO_ERROR; + if ((ppb->state != PPB_ERROR) && + (ppb->error == PPB_NO_ERROR)) { + ppb->state = state; + ppb->error = PPB_NO_ERROR; } return (0); } static int -ppb_1284_set_error(struct ppb_device *dev, int error, int event) +ppb_1284_set_error(device_t bus, int error, int event) { + struct ppb_data *ppb = DEVTOSOFTC(bus); + /* do not accumulate errors */ - if ((dev->ppb->error == PPB_NO_ERROR) && - (dev->ppb->state != PPB_ERROR)) { - dev->ppb->error = error; - dev->ppb->state = PPB_ERROR; + if ((ppb->error == PPB_NO_ERROR) && + (ppb->state != PPB_ERROR)) { + ppb->error = error; + ppb->state = PPB_ERROR; } #ifdef DEBUG_1284 printf("ppb1284: error=%d status=0x%x event=%d\n", error, - ppb_rstr(dev) & 0xff, event); + ppb_rstr(bus) & 0xff, event); #endif return (0); @@ -174,54 +187,54 @@ ppb_request_mode(int mode, int options) * Negociate the peripheral side */ int -ppb_peripheral_negociate(struct ppb_device *dev, int mode, int options) +ppb_peripheral_negociate(device_t bus, int mode, int options) { int spin, request_mode, error = 0; char r; - ppb_set_mode(dev, PPB_COMPATIBLE); - ppb_1284_set_state(dev, PPB_PERIPHERAL_NEGOCIATION); + ppb_set_mode(bus, PPB_COMPATIBLE); + ppb_1284_set_state(bus, PPB_PERIPHERAL_NEGOCIATION); /* compute ext. value */ request_mode = ppb_request_mode(mode, options); /* wait host */ spin = 10; - while (spin-- && (ppb_rstr(dev) & nBUSY)) + while (spin-- && (ppb_rstr(bus) & nBUSY)) DELAY(1); /* check termination */ - if (!(ppb_rstr(dev) & SELECT) || !spin) { + if (!(ppb_rstr(bus) & SELECT) || !spin) { error = ENODEV; goto error; } /* Event 4 - read ext. value */ - r = ppb_rdtr(dev); + r = ppb_rdtr(bus); /* nibble mode is not supported */ if ((r == (char)request_mode) || (r == NIBBLE_1284_NORMAL)) { /* Event 5 - restore direction bit, no data avail */ - ppb_wctr(dev, (STROBE | nINIT) & ~(SELECTIN)); + ppb_wctr(bus, (STROBE | nINIT) & ~(SELECTIN)); DELAY(1); /* Event 6 */ - ppb_wctr(dev, (nINIT) & ~(SELECTIN | STROBE)); + ppb_wctr(bus, (nINIT) & ~(SELECTIN | STROBE)); if (r == NIBBLE_1284_NORMAL) { #ifdef DEBUG_1284 printf("R"); #endif - ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 4); + ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 4); error = EINVAL; goto error; } else { - ppb_1284_set_state(dev, PPB_PERIPHERAL_IDLE); + ppb_1284_set_state(bus, PPB_PERIPHERAL_IDLE); switch (r) { case BYTE_1284_NORMAL: - ppb_set_mode(dev, PPB_BYTE); + ppb_set_mode(bus, PPB_BYTE); break; default: break; @@ -233,12 +246,12 @@ ppb_peripheral_negociate(struct ppb_device *dev, int mode, int options) } } else { /* Event 5 - mode not supported */ - ppb_wctr(dev, SELECTIN); + ppb_wctr(bus, SELECTIN); DELAY(1); /* Event 6 */ - ppb_wctr(dev, (SELECTIN) & ~(STROBE | nINIT)); - ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 4); + ppb_wctr(bus, (SELECTIN) & ~(STROBE | nINIT)); + ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 4); #ifdef DEBUG_1284 printf("r"); @@ -250,7 +263,7 @@ ppb_peripheral_negociate(struct ppb_device *dev, int mode, int options) return (0); error: - ppb_peripheral_terminate(dev, PPB_WAIT); + ppb_peripheral_terminate(bus, PPB_WAIT); return (error); } @@ -262,7 +275,7 @@ error: * Always return 0 in compatible mode */ int -ppb_peripheral_terminate(struct ppb_device *dev, int how) +ppb_peripheral_terminate(device_t bus, int how) { int error = 0; @@ -270,38 +283,38 @@ ppb_peripheral_terminate(struct ppb_device *dev, int how) printf("t"); #endif - ppb_1284_set_state(dev, PPB_PERIPHERAL_TERMINATION); + ppb_1284_set_state(bus, PPB_PERIPHERAL_TERMINATION); /* Event 22 - wait up to host response time (1s) */ - if ((error = do_peripheral_wait(dev, SELECT | nBUSY, 0))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 22); + if ((error = do_peripheral_wait(bus, SELECT | nBUSY, 0))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 22); goto error; } /* Event 24 */ - ppb_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); + ppb_wctr(bus, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); /* Event 25 - wait up to host response time (1s) */ - if ((error = do_peripheral_wait(dev, nBUSY, nBUSY))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 25); + if ((error = do_peripheral_wait(bus, nBUSY, nBUSY))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 25); goto error; } /* Event 26 */ - ppb_wctr(dev, (SELECTIN | nINIT | STROBE) & ~(AUTOFEED)); + ppb_wctr(bus, (SELECTIN | nINIT | STROBE) & ~(AUTOFEED)); DELAY(1); /* Event 27 */ - ppb_wctr(dev, (SELECTIN | nINIT) & ~(STROBE | AUTOFEED)); + ppb_wctr(bus, (SELECTIN | nINIT) & ~(STROBE | AUTOFEED)); /* Event 28 - wait up to host response time (1s) */ - if ((error = do_peripheral_wait(dev, nBUSY, 0))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 28); + if ((error = do_peripheral_wait(bus, nBUSY, 0))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 28); goto error; } error: - ppb_set_mode(dev, PPB_COMPATIBLE); - ppb_1284_set_state(dev, PPB_FORWARD_IDLE); + ppb_set_mode(bus, PPB_COMPATIBLE); + ppb_1284_set_state(bus, PPB_FORWARD_IDLE); return (0); } @@ -312,19 +325,19 @@ error: * Write 1 byte in BYTE mode */ static int -byte_peripheral_outbyte(struct ppb_device *dev, char *buffer, int last) +byte_peripheral_outbyte(device_t bus, char *buffer, int last) { int error = 0; /* Event 7 */ - if ((error = do_1284_wait(dev, nBUSY, nBUSY))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 7); + if ((error = do_1284_wait(bus, nBUSY, nBUSY))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 7); goto error; } /* check termination */ - if (!(ppb_rstr(dev) & SELECT)) { - ppb_peripheral_terminate(dev, PPB_WAIT); + if (!(ppb_rstr(bus) & SELECT)) { + ppb_peripheral_terminate(bus, PPB_WAIT); goto error; } @@ -332,35 +345,35 @@ byte_peripheral_outbyte(struct ppb_device *dev, char *buffer, int last) #ifdef DEBUG_1284 printf("B"); #endif - ppb_wdtr(dev, *buffer); + ppb_wdtr(bus, *buffer); /* Event 9 */ - ppb_wctr(dev, (AUTOFEED | STROBE) & ~(nINIT | SELECTIN)); + ppb_wctr(bus, (AUTOFEED | STROBE) & ~(nINIT | SELECTIN)); /* Event 10 - wait data read */ - if ((error = do_peripheral_wait(dev, nBUSY, 0))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 16); + if ((error = do_peripheral_wait(bus, nBUSY, 0))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 16); goto error; } /* Event 11 */ if (!last) { - ppb_wctr(dev, (AUTOFEED) & ~(nINIT | STROBE | SELECTIN)); + ppb_wctr(bus, (AUTOFEED) & ~(nINIT | STROBE | SELECTIN)); } else { - ppb_wctr(dev, (nINIT) & ~(STROBE | SELECTIN | AUTOFEED)); + ppb_wctr(bus, (nINIT) & ~(STROBE | SELECTIN | AUTOFEED)); } #if 0 /* Event 16 - wait strobe */ - if ((error = do_peripheral_wait(dev, nACK | nBUSY, 0))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 16); + if ((error = do_peripheral_wait(bus, nACK | nBUSY, 0))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 16); goto error; } #endif /* check termination */ - if (!(ppb_rstr(dev) & SELECT)) { - ppb_peripheral_terminate(dev, PPB_WAIT); + if (!(ppb_rstr(bus) & SELECT)) { + ppb_peripheral_terminate(bus, PPB_WAIT); goto error; } @@ -374,12 +387,12 @@ error: * Write n bytes in BYTE mode */ int -byte_peripheral_write(struct ppb_device *dev, char *buffer, int len, int *sent) +byte_peripheral_write(device_t bus, char *buffer, int len, int *sent) { int error = 0, i; char r; - ppb_1284_set_state(dev, PPB_PERIPHERAL_TRANSFER); + ppb_1284_set_state(bus, PPB_PERIPHERAL_TRANSFER); /* wait forever, the remote host is master and should initiate * termination @@ -388,14 +401,14 @@ byte_peripheral_write(struct ppb_device *dev, char *buffer, int len, int *sent) /* force remote nFAULT low to release the remote waiting * process, if any */ - r = ppb_rctr(dev); - ppb_wctr(dev, r & ~nINIT); + r = ppb_rctr(bus); + ppb_wctr(bus, r & ~nINIT); #ifdef DEBUG_1284 printf("y"); #endif /* Event 7 */ - error = ppb_poll_device(dev, PPB_FOREVER, nBUSY, nBUSY, + error = ppb_poll_bus(bus, PPB_FOREVER, nBUSY, nBUSY, PPB_INTR); if (error && error != EWOULDBLOCK) @@ -404,12 +417,12 @@ byte_peripheral_write(struct ppb_device *dev, char *buffer, int len, int *sent) #ifdef DEBUG_1284 printf("b"); #endif - if ((error = byte_peripheral_outbyte(dev, buffer+i, (i == len-1)))) + if ((error = byte_peripheral_outbyte(bus, buffer+i, (i == len-1)))) goto error; } error: if (!error) - ppb_1284_set_state(dev, PPB_PERIPHERAL_IDLE); + ppb_1284_set_state(bus, PPB_PERIPHERAL_IDLE); *sent = i; return (error); @@ -421,35 +434,35 @@ error: * Read 1 byte in BYTE mode */ int -byte_1284_inbyte(struct ppb_device *dev, char *buffer) +byte_1284_inbyte(device_t bus, char *buffer) { int error = 0; /* Event 7 - ready to take data (nAUTO low) */ - ppb_wctr(dev, (PCD | nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); + ppb_wctr(bus, (PCD | nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); /* Event 9 - peripheral set nAck low */ - if ((error = do_1284_wait(dev, nACK, 0))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 9); + if ((error = do_1284_wait(bus, nACK, 0))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 9); goto error; } /* read the byte */ - *buffer = ppb_rdtr(dev); + *buffer = ppb_rdtr(bus); /* Event 10 - data received, can't accept more */ - ppb_wctr(dev, (nINIT) & ~(AUTOFEED | STROBE | SELECTIN)); + ppb_wctr(bus, (nINIT) & ~(AUTOFEED | STROBE | SELECTIN)); /* Event 11 - peripheral ack */ - if ((error = do_1284_wait(dev, nACK, nACK))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 11); + if ((error = do_1284_wait(bus, nACK, nACK))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 11); goto error; } /* Event 16 - strobe */ - ppb_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); + ppb_wctr(bus, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); DELAY(3); - ppb_wctr(dev, (nINIT) & ~(AUTOFEED | STROBE | SELECTIN)); + ppb_wctr(bus, (nINIT) & ~(AUTOFEED | STROBE | SELECTIN)); error: return (error); @@ -461,7 +474,7 @@ error: * Read 1 byte in NIBBLE mode */ int -nibble_1284_inbyte(struct ppb_device *dev, char *buffer) +nibble_1284_inbyte(device_t bus, char *buffer) { char nibble[2]; int i, error; @@ -469,25 +482,25 @@ nibble_1284_inbyte(struct ppb_device *dev, char *buffer) for (i = 0; i < 2; i++) { /* Event 7 - ready to take data (nAUTO low) */ - ppb_wctr(dev, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); + ppb_wctr(bus, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); /* Event 8 - peripheral writes the first nibble */ /* Event 9 - peripheral set nAck low */ - if ((error = do_1284_wait(dev, nACK, 0))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 9); + if ((error = do_1284_wait(bus, nACK, 0))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 9); goto error; } /* read nibble */ - nibble[i] = ppb_rstr(dev); + nibble[i] = ppb_rstr(bus); /* Event 10 - ack, nibble received */ - ppb_wctr(dev, nINIT & ~(AUTOFEED | STROBE | SELECTIN)); + ppb_wctr(bus, nINIT & ~(AUTOFEED | STROBE | SELECTIN)); /* Event 11 - wait ack from peripherial */ - if ((error = do_1284_wait(dev, nACK, nACK))) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 11); + if ((error = do_1284_wait(bus, nACK, nACK))) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 11); goto error; } } @@ -505,7 +518,7 @@ error: * Read in IEEE1284 NIBBLE/BYTE mode */ int -spp_1284_read(struct ppb_device *dev, int mode, char *buffer, int max, int *read) +spp_1284_read(device_t bus, int mode, char *buffer, int max, int *read) { int error = 0, len = 0; int terminate_after_transfer = 1; @@ -513,11 +526,11 @@ spp_1284_read(struct ppb_device *dev, int mode, char *buffer, int max, int *read *read = len = 0; - state = ppb_1284_get_state(dev); + state = ppb_1284_get_state(bus); switch (state) { case PPB_FORWARD_IDLE: - if ((error = ppb_1284_negociate(dev, mode, 0))) + if ((error = ppb_1284_negociate(bus, mode, 0))) return (error); break; @@ -526,15 +539,15 @@ spp_1284_read(struct ppb_device *dev, int mode, char *buffer, int max, int *read break; default: - ppb_1284_terminate(dev); - if ((error = ppb_1284_negociate(dev, mode, 0))) + ppb_1284_terminate(bus); + if ((error = ppb_1284_negociate(bus, mode, 0))) return (error); break; } - while ((len < max) && !(ppb_rstr(dev) & (nFAULT))) { + while ((len < max) && !(ppb_rstr(bus) & (nFAULT))) { - ppb_1284_set_state(dev, PPB_REVERSE_TRANSFER); + ppb_1284_set_state(bus, PPB_REVERSE_TRANSFER); #ifdef DEBUG_1284 printf("B"); @@ -543,11 +556,11 @@ spp_1284_read(struct ppb_device *dev, int mode, char *buffer, int max, int *read switch (mode) { case PPB_NIBBLE: /* read a byte, error means no more data */ - if (nibble_1284_inbyte(dev, buffer+len)) + if (nibble_1284_inbyte(bus, buffer+len)) goto end_while; break; case PPB_BYTE: - if (byte_1284_inbyte(dev, buffer+len)) + if (byte_1284_inbyte(bus, buffer+len)) goto end_while; break; default: @@ -559,12 +572,12 @@ spp_1284_read(struct ppb_device *dev, int mode, char *buffer, int max, int *read end_while: if (!error) - ppb_1284_set_state(dev, PPB_REVERSE_IDLE); + ppb_1284_set_state(bus, PPB_REVERSE_IDLE); *read = len; if (terminate_after_transfer || error) - ppb_1284_terminate(dev); + ppb_1284_terminate(bus); return (error); } @@ -574,7 +587,7 @@ end_while: * */ int -ppb_1284_read_id(struct ppb_device *dev, int mode, char *buffer, +ppb_1284_read_id(device_t bus, int mode, char *buffer, int max, int *read) { int error = 0; @@ -585,20 +598,20 @@ ppb_1284_read_id(struct ppb_device *dev, int mode, char *buffer, switch (mode) { case PPB_NIBBLE: case PPB_ECP: - if ((error = ppb_1284_negociate(dev, PPB_NIBBLE, PPB_REQUEST_ID))) + if ((error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID))) return (error); - error = spp_1284_read(dev, PPB_NIBBLE, buffer, max, read); + error = spp_1284_read(bus, PPB_NIBBLE, buffer, max, read); break; case PPB_BYTE: - if ((error = ppb_1284_negociate(dev, PPB_BYTE, PPB_REQUEST_ID))) + if ((error = ppb_1284_negociate(bus, PPB_BYTE, PPB_REQUEST_ID))) return (error); - error = spp_1284_read(dev, PPB_BYTE, buffer, max, read); + error = spp_1284_read(bus, PPB_BYTE, buffer, max, read); break; default: panic("%s: unsupported mode %d\n", __FUNCTION__, mode); } - ppb_1284_terminate(dev); + ppb_1284_terminate(bus); return (error); } @@ -608,7 +621,7 @@ ppb_1284_read_id(struct ppb_device *dev, int mode, char *buffer, * IEEE1284 read */ int -ppb_1284_read(struct ppb_device *dev, int mode, char *buffer, +ppb_1284_read(device_t bus, int mode, char *buffer, int max, int *read) { int error = 0; @@ -616,7 +629,7 @@ ppb_1284_read(struct ppb_device *dev, int mode, char *buffer, switch (mode) { case PPB_NIBBLE: case PPB_BYTE: - error = spp_1284_read(dev, mode, buffer, max, read); + error = spp_1284_read(bus, mode, buffer, max, read); break; default: return (EINVAL); @@ -635,7 +648,7 @@ ppb_1284_read(struct ppb_device *dev, int mode, char *buffer, * After negociation, nFAULT is low if data is available */ int -ppb_1284_negociate(struct ppb_device *dev, int mode, int options) +ppb_1284_negociate(device_t bus, int mode, int options) { int error; int request_mode; @@ -644,77 +657,77 @@ ppb_1284_negociate(struct ppb_device *dev, int mode, int options) printf("n"); #endif - if (ppb_1284_get_state(dev) >= PPB_PERIPHERAL_NEGOCIATION) - ppb_peripheral_terminate(dev, PPB_WAIT); + if (ppb_1284_get_state(bus) >= PPB_PERIPHERAL_NEGOCIATION) + ppb_peripheral_terminate(bus, PPB_WAIT); - if (ppb_1284_get_state(dev) != PPB_FORWARD_IDLE) - ppb_1284_terminate(dev); + if (ppb_1284_get_state(bus) != PPB_FORWARD_IDLE) + ppb_1284_terminate(bus); #ifdef DEBUG_1284 printf("%d", mode); #endif /* ensure the host is in compatible mode */ - ppb_set_mode(dev, PPB_COMPATIBLE); + ppb_set_mode(bus, PPB_COMPATIBLE); /* reset error to catch the actual negociation error */ - ppb_1284_reset_error(dev, PPB_FORWARD_IDLE); + ppb_1284_reset_error(bus, PPB_FORWARD_IDLE); /* calculate ext. value */ request_mode = ppb_request_mode(mode, options); /* default state */ - ppb_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); + ppb_wctr(bus, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); DELAY(1); /* enter negociation phase */ - ppb_1284_set_state(dev, PPB_NEGOCIATION); + ppb_1284_set_state(bus, PPB_NEGOCIATION); /* Event 0 - put the exten. value on the data lines */ - ppb_wdtr(dev, request_mode); + ppb_wdtr(bus, request_mode); #ifdef PERIPH_1284 /* request remote host attention */ - ppb_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); + ppb_wctr(bus, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); DELAY(1); - ppb_wctr(dev, (nINIT) & ~(STROBE | AUTOFEED | SELECTIN)); + ppb_wctr(bus, (nINIT) & ~(STROBE | AUTOFEED | SELECTIN)); #else DELAY(1); #endif /* !PERIPH_1284 */ /* Event 1 - enter IEEE1284 mode */ - ppb_wctr(dev, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); + ppb_wctr(bus, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); #ifdef PERIPH_1284 /* ignore the PError line, wait a bit more, remote host's * interrupts don't respond fast enough */ - if (ppb_poll_device(dev, 40, nACK | SELECT | nFAULT, + if (ppb_poll_bus(bus, 40, nACK | SELECT | nFAULT, SELECT | nFAULT, PPB_NOINTR | PPB_POLL)) { - ppb_1284_set_error(dev, PPB_NOT_IEEE1284, 2); + ppb_1284_set_error(bus, PPB_NOT_IEEE1284, 2); error = ENODEV; goto error; } #else /* Event 2 - trying IEEE1284 dialog */ - if (do_1284_wait(dev, nACK | PERROR | SELECT | nFAULT, + if (do_1284_wait(bus, nACK | PERROR | SELECT | nFAULT, PERROR | SELECT | nFAULT)) { - ppb_1284_set_error(dev, PPB_NOT_IEEE1284, 2); + ppb_1284_set_error(bus, PPB_NOT_IEEE1284, 2); error = ENODEV; goto error; } #endif /* !PERIPH_1284 */ /* Event 3 - latch the ext. value to the peripheral */ - ppb_wctr(dev, (nINIT | STROBE | AUTOFEED) & ~SELECTIN); + ppb_wctr(bus, (nINIT | STROBE | AUTOFEED) & ~SELECTIN); DELAY(1); /* Event 4 - IEEE1284 device recognized */ - ppb_wctr(dev, nINIT & ~(SELECTIN | AUTOFEED | STROBE)); + ppb_wctr(bus, nINIT & ~(SELECTIN | AUTOFEED | STROBE)); /* Event 6 - waiting for status lines */ - if (do_1284_wait(dev, nACK, nACK)) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 6); + if (do_1284_wait(bus, nACK, nACK)) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 6); error = EBUSY; goto error; } @@ -724,19 +737,19 @@ ppb_1284_negociate(struct ppb_device *dev, int mode, int options) if (options & PPB_EXTENSIBILITY_LINK) { /* XXX not fully supported yet */ - ppb_1284_terminate(dev); + ppb_1284_terminate(bus); return (0); } if (request_mode == NIBBLE_1284_NORMAL) { - if (do_1284_wait(dev, nACK | SELECT, nACK)) { - ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 7); + if (do_1284_wait(bus, nACK | SELECT, nACK)) { + ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 7); error = ENODEV; goto error; } } else { - if (do_1284_wait(dev, nACK | SELECT, SELECT | nACK)) { - ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 7); + if (do_1284_wait(bus, nACK | SELECT, SELECT | nACK)) { + ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 7); error = ENODEV; goto error; } @@ -746,46 +759,46 @@ ppb_1284_negociate(struct ppb_device *dev, int mode, int options) case PPB_NIBBLE: case PPB_PS2: /* enter reverse idle phase */ - ppb_1284_set_state(dev, PPB_REVERSE_IDLE); + ppb_1284_set_state(bus, PPB_REVERSE_IDLE); break; case PPB_ECP: /* negociation ok, now setup the communication */ - ppb_1284_set_state(dev, PPB_SETUP); - ppb_wctr(dev, (nINIT | AUTOFEED) & ~(SELECTIN | STROBE)); + ppb_1284_set_state(bus, PPB_SETUP); + ppb_wctr(bus, (nINIT | AUTOFEED) & ~(SELECTIN | STROBE)); #ifdef PERIPH_1284 /* ignore PError line */ - if (do_1284_wait(dev, nACK | SELECT | nBUSY, + if (do_1284_wait(bus, nACK | SELECT | nBUSY, nACK | SELECT | nBUSY)) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 30); + ppb_1284_set_error(bus, PPB_TIMEOUT, 30); error = ENODEV; goto error; } #else - if (do_1284_wait(dev, nACK | SELECT | PERROR | nBUSY, + if (do_1284_wait(bus, nACK | SELECT | PERROR | nBUSY, nACK | SELECT | PERROR | nBUSY)) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 30); + ppb_1284_set_error(bus, PPB_TIMEOUT, 30); error = ENODEV; goto error; } #endif /* !PERIPH_1284 */ /* ok, the host enters the ForwardIdle state */ - ppb_1284_set_state(dev, PPB_ECP_FORWARD_IDLE); + ppb_1284_set_state(bus, PPB_ECP_FORWARD_IDLE); break; case PPB_EPP: - ppb_1284_set_state(dev, PPB_EPP_IDLE); + ppb_1284_set_state(bus, PPB_EPP_IDLE); break; default: panic("%s: unknown mode (%d)!", __FUNCTION__, mode); } - ppb_set_mode(dev, mode); + ppb_set_mode(bus, mode); return (0); error: - ppb_1284_terminate(dev); + ppb_1284_terminate(bus); return (error); } @@ -797,7 +810,7 @@ error: * is _always_ in compatible mode after ppb_1284_terminate() */ int -ppb_1284_terminate(struct ppb_device *dev) +ppb_1284_terminate(device_t bus) { #ifdef DEBUG_1284 @@ -806,40 +819,40 @@ ppb_1284_terminate(struct ppb_device *dev) /* do not reset error here to keep the error that * may occured before the ppb_1284_terminate() call */ - ppb_1284_set_state(dev, PPB_TERMINATION); + ppb_1284_set_state(bus, PPB_TERMINATION); #ifdef PERIPH_1284 /* request remote host attention */ - ppb_wctr(dev, (nINIT | STROBE | SELECTIN) & ~(AUTOFEED)); + ppb_wctr(bus, (nINIT | STROBE | SELECTIN) & ~(AUTOFEED)); DELAY(1); #endif /* PERIPH_1284 */ /* Event 22 - set nSelectin low and nAutoFeed high */ - ppb_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); + ppb_wctr(bus, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); /* Event 24 - waiting for peripheral, Xflag ignored */ - if (do_1284_wait(dev, nACK | nBUSY | nFAULT, nFAULT)) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 24); + if (do_1284_wait(bus, nACK | nBUSY | nFAULT, nFAULT)) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 24); goto error; } /* Event 25 - set nAutoFd low */ - ppb_wctr(dev, (nINIT | SELECTIN | AUTOFEED) & ~STROBE); + ppb_wctr(bus, (nINIT | SELECTIN | AUTOFEED) & ~STROBE); /* Event 26 - compatible mode status is set */ /* Event 27 - peripheral set nAck high */ - if (do_1284_wait(dev, nACK, nACK)) { - ppb_1284_set_error(dev, PPB_TIMEOUT, 27); + if (do_1284_wait(bus, nACK, nACK)) { + ppb_1284_set_error(bus, PPB_TIMEOUT, 27); } /* Event 28 - end termination, return to idle phase */ - ppb_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); + ppb_wctr(bus, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); error: /* return to compatible mode */ - ppb_set_mode(dev, PPB_COMPATIBLE); - ppb_1284_set_state(dev, PPB_FORWARD_IDLE); + ppb_set_mode(bus, PPB_COMPATIBLE); + ppb_1284_set_state(bus, PPB_FORWARD_IDLE); return (0); } diff --git a/sys/dev/ppbus/ppb_1284.h b/sys/dev/ppbus/ppb_1284.h index f975c26..de1f270 100644 --- a/sys/dev/ppbus/ppb_1284.h +++ b/sys/dev/ppbus/ppb_1284.h @@ -108,17 +108,17 @@ #define PPB_PERIPHERAL_TRANSFER 13 #define PPB_PERIPHERAL_TERMINATION 14 -extern int nibble_1284_inbyte(struct ppb_device *, char *); -extern int byte_1284_inbyte(struct ppb_device *, char *); -extern int spp_1284_read(struct ppb_device *, int, char *, int, int *); - -extern int ppb_1284_negociate(struct ppb_device *, int, int); -extern int ppb_1284_terminate(struct ppb_device *); -extern int ppb_1284_read_id(struct ppb_device *, int, char *, int, int *); -extern int ppb_1284_read(struct ppb_device *, int, char *, int, int *); - -extern int ppb_peripheral_terminate(struct ppb_device *, int); -extern int ppb_peripheral_negociate(struct ppb_device *, int, int); -extern int byte_peripheral_write(struct ppb_device *, char *, int, int *); +extern int nibble_1284_inbyte(device_t, char *); +extern int byte_1284_inbyte(device_t, char *); +extern int spp_1284_read(device_t, int, char *, int, int *); + +extern int ppb_1284_negociate(device_t, int, int); +extern int ppb_1284_terminate(device_t); +extern int ppb_1284_read_id(device_t, int, char *, int, int *); +extern int ppb_1284_read(device_t, int, char *, int, int *); + +extern int ppb_peripheral_terminate(device_t, int); +extern int ppb_peripheral_negociate(device_t, int, int); +extern int byte_peripheral_write(device_t, char *, int, int *); #endif diff --git a/sys/dev/ppbus/ppb_base.c b/sys/dev/ppbus/ppb_base.c index 250999b..c2f1d9b 100644 --- a/sys/dev/ppbus/ppb_base.c +++ b/sys/dev/ppbus/ppb_base.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu + * Copyright (c) 1997, 1998, 1999 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,49 +29,29 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> + #include <machine/clock.h> #include <dev/ppbus/ppbconf.h> + +#include "ppbus_if.h" +#include <dev/ppbus/ppbio.h> + +#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) + /* - * ppb_intr() + * ppb_poll_bus() * - * Function called by ppcintr() when an intr occurs. - */ -void -ppb_intr(struct ppb_link *pl) -{ - struct ppb_data *ppb = pl->ppbus; - - /* - * Call chipset dependent code. - * Should be filled at chipset initialisation if needed. - */ - if (pl->adapter->intr_handler) - (*pl->adapter->intr_handler)(pl->adapter_unit); - - /* - * Call upper handler iff the bus is owned by a device and - * this device has specified an interrupt handler. - */ - if (ppb->ppb_owner && ppb->ppb_owner->intr) - (*ppb->ppb_owner->intr)(ppb->ppb_owner->id_unit); - if (ppb->ppb_owner && ppb->ppb_owner->bintr) - (*ppb->ppb_owner->bintr)(ppb->ppb_owner); - - return; -} - -/* - * ppb_poll_device() - * - * Polls the device + * Polls the bus * * max is a delay in 10-milliseconds */ int -ppb_poll_device(struct ppb_device *dev, int max, - char mask, char status, int how) +ppb_poll_bus(device_t bus, int max, + char mask, char status, int how) { int i, j, error; char r; @@ -79,7 +59,7 @@ ppb_poll_device(struct ppb_device *dev, int max, /* try at least up to 10ms */ for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) { for (i = 0; i < 10000; i++) { - r = ppb_rstr(dev); + r = ppb_rstr(bus); DELAY(1); if ((r & mask) == status) return (0); @@ -88,19 +68,19 @@ ppb_poll_device(struct ppb_device *dev, int max, if (!(how & PPB_POLL)) { for (i = 0; max == PPB_FOREVER || i < max-1; i++) { - if ((ppb_rstr(dev) & mask) == status) + if ((ppb_rstr(bus) & mask) == status) return (0); switch (how) { case PPB_NOINTR: /* wait 10 ms */ - tsleep((caddr_t)dev, PPBPRI, "ppbpoll", hz/100); + tsleep((caddr_t)bus, PPBPRI, "ppbpoll", hz/100); break; case PPB_INTR: default: /* wait 10 ms */ - if (((error = tsleep((caddr_t)dev, PPBPRI | PCATCH, + if (((error = tsleep((caddr_t)bus, PPBPRI | PCATCH, "ppbpoll", hz/100)) != EWOULDBLOCK) != 0) { return (error); } @@ -113,22 +93,48 @@ ppb_poll_device(struct ppb_device *dev, int max, } /* - * ppb_set_mode() + * ppb_get_epp_protocol() * - * Set the operating mode of the chipset + * Return the chipset EPP protocol */ int -ppb_set_mode(struct ppb_device *dev, int mode) +ppb_get_epp_protocol(device_t bus) { - struct ppb_data *ppb = dev->ppb; - int old_mode = ppb_get_mode(dev); + uintptr_t protocol; + + BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_EPP_PROTO, &protocol); - if ((*ppb->ppb_link->adapter->setmode)( - ppb->ppb_link->adapter_unit, mode)) - return (-1); + return (protocol); +} + +/* + * ppb_get_mode() + * + */ +int +ppb_get_mode(device_t bus) +{ + struct ppb_data *ppb = DEVTOSOFTC(bus); /* XXX yet device mode = ppbus mode = chipset mode */ - dev->mode = ppb->mode = (mode & PPB_MASK); + return (ppb->mode); +} + +/* + * ppb_set_mode() + * + * Set the operating mode of the chipset, return the previous mode + */ +int +ppb_set_mode(device_t bus, int mode) +{ + struct ppb_data *ppb = DEVTOSOFTC(bus); + int old_mode = ppb_get_mode(bus); + + if (!PPBUS_SETMODE(device_get_parent(bus), mode)) { + /* XXX yet device mode = ppbus mode = chipset mode */ + ppb->mode = (mode & PPB_MASK); + } return (old_mode); } @@ -139,12 +145,9 @@ ppb_set_mode(struct ppb_device *dev, int mode) * Write charaters to the port */ int -ppb_write(struct ppb_device *dev, char *buf, int len, int how) +ppb_write(device_t bus, char *buf, int len, int how) { - struct ppb_data *ppb = dev->ppb; - - return (ppb->ppb_link->adapter->write(ppb->ppb_link->adapter_unit, - buf, len, how)); + return (PPBUS_WRITE(device_get_parent(bus), buf, len, how)); } /* @@ -153,16 +156,9 @@ ppb_write(struct ppb_device *dev, char *buf, int len, int how) * Reset the EPP timeout bit in the status register */ int -ppb_reset_epp_timeout(struct ppb_device *dev) +ppb_reset_epp_timeout(device_t bus) { - struct ppb_data *ppb = dev->ppb; - - if (ppb->ppb_owner != dev) - return (EACCES); - - (*ppb->ppb_link->adapter->reset_epp_timeout)(ppb->ppb_link->adapter_unit); - - return (0); + return(PPBUS_RESET_EPP(device_get_parent(bus))); } /* @@ -171,16 +167,9 @@ ppb_reset_epp_timeout(struct ppb_device *dev) * Wait for the ECP FIFO to be empty */ int -ppb_ecp_sync(struct ppb_device *dev) +ppb_ecp_sync(device_t bus) { - struct ppb_data *ppb = dev->ppb; - - if (ppb->ppb_owner != dev) - return (EACCES); - - (*ppb->ppb_link->adapter->ecp_sync)(ppb->ppb_link->adapter_unit); - - return (0); + return (PPBUS_ECP_SYNC(device_get_parent(bus))); } /* @@ -189,15 +178,11 @@ ppb_ecp_sync(struct ppb_device *dev) * Read the status register and update the status info */ int -ppb_get_status(struct ppb_device *dev, struct ppb_status *status) +ppb_get_status(device_t bus, struct ppb_status *status) { - struct ppb_data *ppb = dev->ppb; register char r; - if (ppb->ppb_owner != dev) - return (EACCES); - - r = status->status = ppb_rstr(dev); + r = status->status = ppb_rstr(bus); status->timeout = r & TIMEOUT; status->error = !(r & nFAULT); diff --git a/sys/dev/ppbus/ppb_msq.c b/sys/dev/ppbus/ppb_msq.c index a98b254..074dd07 100644 --- a/sys/dev/ppbus/ppb_msq.c +++ b/sys/dev/ppbus/ppb_msq.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 Nicolas Souchu + * Copyright (c) 1998, 1999 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,10 +31,13 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/bus.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> +#include "ppbus_if.h" + /* msq index (see PPB_MAX_XFER) * These are device modes */ @@ -49,18 +52,18 @@ * Device mode to submsq conversion */ static struct ppb_xfer * -mode2xfer(struct ppb_device *dev, int opcode) +mode2xfer(device_t bus, struct ppb_device *ppbdev, int opcode) { int index, epp; struct ppb_xfer *table; switch (opcode) { case MS_OP_GET: - table = dev->get_xfer; + table = ppbdev->get_xfer; break; case MS_OP_PUT: - table = dev->put_xfer; + table = ppbdev->put_xfer; break; default: @@ -68,7 +71,7 @@ mode2xfer(struct ppb_device *dev, int opcode) } /* retrieve the device operating mode */ - switch (ppb_get_mode(dev)) { + switch (ppb_get_mode(bus)) { case PPB_COMPATIBLE: index = COMPAT_MSQ; break; @@ -79,7 +82,7 @@ mode2xfer(struct ppb_device *dev, int opcode) index = PS2_MSQ; break; case PPB_EPP: - switch ((epp = ppb_get_epp_protocol(dev))) { + switch ((epp = ppb_get_epp_protocol(bus))) { case EPP_1_7: index = EPP17_MSQ; break; @@ -95,7 +98,7 @@ mode2xfer(struct ppb_device *dev, int opcode) index = ECP_MSQ; break; default: - panic("%s: unknown mode (%d)", __FUNCTION__, dev->mode); + panic("%s: unknown mode (%d)", __FUNCTION__, ppbdev->mode); } return (&table[index]); @@ -108,9 +111,10 @@ mode2xfer(struct ppb_device *dev, int opcode) * */ int -ppb_MS_init(struct ppb_device *dev, struct ppb_microseq *loop, int opcode) +ppb_MS_init(device_t bus, device_t dev, struct ppb_microseq *loop, int opcode) { - struct ppb_xfer *xfer = mode2xfer(dev, opcode); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + struct ppb_xfer *xfer = mode2xfer(bus, ppbdev, opcode); xfer->loop = loop; @@ -124,7 +128,7 @@ ppb_MS_init(struct ppb_device *dev, struct ppb_microseq *loop, int opcode) * */ int -ppb_MS_exec(struct ppb_device *dev, int opcode, union ppb_insarg param1, +ppb_MS_exec(device_t bus, device_t dev, int opcode, union ppb_insarg param1, union ppb_insarg param2, union ppb_insarg param3, int *ret) { struct ppb_microseq msq[] = { @@ -139,7 +143,7 @@ ppb_MS_exec(struct ppb_device *dev, int opcode, union ppb_insarg param1, msq[0].arg[2] = param3; /* execute the microseq */ - return (ppb_MS_microseq(dev, msq, ret)); + return (ppb_MS_microseq(bus, dev, msq, ret)); } /* @@ -149,7 +153,7 @@ ppb_MS_exec(struct ppb_device *dev, int opcode, union ppb_insarg param1, * */ int -ppb_MS_loop(struct ppb_device *dev, struct ppb_microseq *prolog, +ppb_MS_loop(device_t bus, device_t dev, struct ppb_microseq *prolog, struct ppb_microseq *body, struct ppb_microseq *epilog, int iter, int *ret) { @@ -172,7 +176,7 @@ ppb_MS_loop(struct ppb_device *dev, struct ppb_microseq *prolog, loop_microseq[4].arg[0].p = (void *)epilog; /* execute the loop */ - return (ppb_MS_microseq(dev, loop_microseq, ret)); + return (ppb_MS_microseq(bus, dev, loop_microseq, ret)); } /* @@ -242,9 +246,11 @@ ppb_MS_init_msq(struct ppb_microseq *msq, int nbparam, ...) * level to avoid function call overhead between ppbus and the adapter */ int -ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret) +ppb_MS_microseq(device_t bus, device_t dev, struct ppb_microseq *msq, int *ret) { - struct ppb_data *ppb = dev->ppb; + struct ppb_data *ppb = (struct ppb_data *)device_get_softc(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + struct ppb_microseq *mi; /* current microinstruction */ int error; @@ -269,13 +275,13 @@ ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret) case MS_OP_GET: /* attempt to choose the best mode for the device */ - xfer = mode2xfer(dev, mi->opcode); + xfer = mode2xfer(bus, ppbdev, mi->opcode); /* figure out if we should use ieee1284 code */ if (!xfer->loop) { if (mi->opcode == MS_OP_PUT) { - if ((error = ppb->ppb_link->adapter->write( - ppb->ppb_link->adapter_unit, + if ((error = PPBUS_WRITE( + device_get_parent(bus), (char *)mi->arg[0].p, mi->arg[1].i, 0))) goto error; @@ -291,7 +297,7 @@ ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret) initxfer[1].arg[0].i = mi->arg[1].i; /* initialize transfer */ - ppb_MS_microseq(dev, initxfer, &error); + ppb_MS_microseq(bus, dev, initxfer, &error); if (error) goto error; @@ -299,7 +305,7 @@ ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret) /* the xfer microsequence should not contain any * MS_OP_PUT or MS_OP_GET! */ - ppb_MS_microseq(dev, xfer->loop, &error); + ppb_MS_microseq(bus, dev, xfer->loop, &error); if (error) goto error; @@ -318,9 +324,8 @@ ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret) * faster. This is the default if the microinstr * is unknown here */ - if ((error = ppb->ppb_link->adapter->exec_microseq( - ppb->ppb_link->adapter_unit, - &mi))) + if ((error = PPBUS_EXEC_MICROSEQ( + device_get_parent(bus), &mi))) goto error; break; } diff --git a/sys/dev/ppbus/ppb_msq.h b/sys/dev/ppbus/ppb_msq.h index 25b55fd..64d16d895 100644 --- a/sys/dev/ppbus/ppb_msq.h +++ b/sys/dev/ppbus/ppb_msq.h @@ -158,12 +158,13 @@ * Function abstraction level */ -#define ppb_MS_GET_init(dev,body) ppb_MS_init(dev, body, MS_OP_GET) +#define ppb_MS_GET_init(bus,dev,body) ppb_MS_init(bus, dev, body, MS_OP_GET) -#define ppb_MS_PUT_init(dev,body) ppb_MS_init(dev, body, MS_OP_PUT) +#define ppb_MS_PUT_init(bus,dev,body) ppb_MS_init(bus, dev, body, MS_OP_PUT) extern int ppb_MS_init( - struct ppb_device *, /* ppbus device */ + device_t, /* ppbus bus */ + device_t, /* ppbus device */ struct ppb_microseq *, /* loop msq to assign */ int opcode /* MS_OP_GET, MS_OP_PUT */ ); @@ -175,7 +176,8 @@ extern int ppb_MS_init_msq( ); extern int ppb_MS_exec( - struct ppb_device *, /* ppbus device */ + device_t, /* ppbus bus */ + device_t, /* ppbus device */ int, /* microseq opcode */ union ppb_insarg, /* param1 */ union ppb_insarg, /* param2 */ @@ -184,7 +186,8 @@ extern int ppb_MS_exec( ); extern int ppb_MS_loop( - struct ppb_device *, /* ppbus device */ + device_t, /* ppbus bus */ + device_t, /* ppbus device */ struct ppb_microseq *, /* prologue msq of loop */ struct ppb_microseq *, /* body msq of loop */ struct ppb_microseq *, /* epilogue msq of loop */ @@ -193,7 +196,8 @@ extern int ppb_MS_loop( ); extern int ppb_MS_microseq( - struct ppb_device *, /* ppbus device */ + device_t, /* ppbus bus */ + device_t, /* ppbus device */ struct ppb_microseq *, /* msq to execute */ int * /* returned value */ ); diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c index f98fcf2..2d7aa1a 100644 --- a/sys/dev/ppbus/ppbconf.c +++ b/sys/dev/ppbus/ppbconf.c @@ -26,61 +26,154 @@ * $FreeBSD$ * */ +#include "opt_ppb_1284.h" + #include <sys/param.h> #include <sys/systm.h> -#include <sys/linker_set.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/malloc.h> -#include <vm/vm.h> -#include <vm/pmap.h> - #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_1284.h> -#include "opt_ppb_1284.h" +#include "ppbus_if.h" + +#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) + +MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device"); -static LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ +static devclass_t ppbus_devclass; /* - * Add a null driver so that the linker set always exists. + * Device methods */ - -static struct ppb_driver nulldriver = { - NULL, NULL, "null" +static int ppbus_probe(device_t); +static int ppbus_attach(device_t); +static void ppbus_print_child(device_t bus, device_t dev); +static int ppbus_read_ivar(device_t, device_t, int, uintptr_t *); +static int ppbus_write_ivar(device_t, device_t, int, u_long); +static int ppbus_setup_intr(device_t, device_t, struct resource *, int, + void (*)(void *), void *, void **); +static int ppbus_teardown_intr(device_t, device_t, struct resource *, void *); + +static device_method_t ppbus_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppbus_probe), + DEVMETHOD(device_attach, ppbus_attach), + + /* bus interface */ + DEVMETHOD(bus_print_child, ppbus_print_child), + DEVMETHOD(bus_read_ivar, ppbus_read_ivar), + DEVMETHOD(bus_write_ivar, ppbus_write_ivar), + DEVMETHOD(bus_setup_intr, ppbus_setup_intr), + DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + + { 0, 0 } }; -DATA_SET(ppbdriver_set, nulldriver); +static driver_t ppbus_driver = { + "ppbus", + ppbus_methods, + sizeof(struct ppb_data), + }; + +static void +ppbus_print_child(device_t bus, device_t dev) +{ + struct ppb_device *ppbdev; + + bus_print_child_header(bus, dev); + + ppbdev = (struct ppb_device *)device_get_ivars(dev); + + if (ppbdev->flags != 0) + printf(" flags 0x%x", ppbdev->flags); + + printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus)); + + return; +} + +static int +ppbus_probe(device_t dev) +{ + device_set_desc(dev, "Parallel port bus"); + + return (0); +} /* - * ppb_alloc_bus() + * ppb_add_device() * - * Allocate area to store the ppbus description. + * Add a ppbus device, allocate/initialize the ivars */ -struct ppb_data * -ppb_alloc_bus(void) +static void +ppbus_add_device(device_t dev, const char *name, int unit) { - struct ppb_data *ppb; - static int ppbdata_initted = 0; /* done-init flag */ - - ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), - M_TEMP, M_NOWAIT); + struct ppb_device *ppbdev; + device_t child; + + /* allocate ivars for the new ppbus child */ + ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV, M_NOWAIT); + if (!ppbdev) + return; + bzero(ppbdev, sizeof *ppbdev); + + /* initialize the ivars */ + ppbdev->name = name; + + /* add the device as a child to the ppbus bus with the allocated + * ivars */ + child = device_add_child(dev, name, unit); + device_set_ivars(child, ppbdev); - /* - * Add the new parallel port bus to the list of existing ppbus. - */ - if (ppb) { - bzero(ppb, sizeof(struct ppb_data)); + return; +} - if (!ppbdata_initted) { /* list not initialised */ - LIST_INIT(&ppbdata); - ppbdata_initted = 1; - } - LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); - } else { - printf("ppb_alloc_bus: cannot malloc!\n"); +static int +ppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val) + { + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + + switch (index) { + case PPBUS_IVAR_MODE: + /* XXX yet device mode = ppbus mode = chipset mode */ + *val = (u_long)ppb_get_mode(bus); + ppbdev->mode = (u_short)*val; + break; + case PPBUS_IVAR_AVM: + *val = (u_long)ppbdev->avm; + break; + case PPBUS_IVAR_IRQ: + BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val); + break; + default: + return (ENOENT); } - return(ppb); + + return (0); } + +static int +ppbus_write_ivar(device_t bus, device_t dev, int index, u_long val) +{ + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + + switch (index) { + case PPBUS_IVAR_MODE: + /* XXX yet device mode = ppbus mode = chipset mode */ + ppb_set_mode(bus,val); + ppbdev->mode = ppb_get_mode(bus); + break; + default: + return (ENOENT); + } + + return (0); + } #define PPB_PNP_PRINTER 0 #define PPB_PNP_MODEM 1 @@ -151,17 +244,17 @@ search_token(char *str, int slen, char *token) * Returns the class id. of the peripherial, -1 otherwise */ static int -ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev) +ppb_pnp_detect(device_t bus) { char *token, *class = 0; int i, len, error; int class_id = -1; char str[PPB_PnP_STRING_SIZE+1]; + int unit = device_get_unit(bus); - printf("Probing for PnP devices on ppbus%d:\n", - ppb->ppb_link->adapter_unit); + printf("Probing for PnP devices on ppbus%d:\n", unit); - if ((error = ppb_1284_read_id(pnpdev, PPB_NIBBLE, str, + if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str, PPB_PnP_STRING_SIZE, &len))) goto end_detect; @@ -178,10 +271,10 @@ ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev) if ((token = search_token(str, len, "MFG")) != NULL || (token = search_token(str, len, "MANUFACTURER")) != NULL) - printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit, + printf("ppbus%d: <%s", unit, search_token(token, UNKNOWN_LENGTH, ":") + 1); else - printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit); + printf("ppbus%d: <unknown", unit); if ((token = search_token(str, len, "MDL")) != NULL || (token = search_token(str, len, "MODEL")) != NULL) @@ -233,21 +326,11 @@ end_detect: * Scan the ppbus for IEEE1284 compliant devices */ static int -ppb_scan_bus(struct ppb_data *ppb) +ppb_scan_bus(device_t bus) { - struct ppb_device pnpdev; /* temporary device to perform I/O */ + struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus); int error = 0; - - /* initialize the pnpdev structure for future use */ - bzero(&pnpdev, sizeof(pnpdev)); - pnpdev.ppb = ppb; - - if ((error = ppb_request_bus(&pnpdev, PPB_DONTWAIT))) { - if (bootverbose) - printf("ppb: cannot allocate ppbus!\n"); - - return (error); - } + int unit = device_get_unit(bus); /* try all IEEE1284 modes, for one device only * @@ -255,207 +338,175 @@ ppb_scan_bus(struct ppb_data *ppb) * daisy chained devices */ - error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID); + error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID); if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284)) goto end_scan; - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); - printf("ppb%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit); + printf("ppbus%d: IEEE1284 device found ", unit); - if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) { printf("/NIBBLE"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) { printf("/PS2"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) { printf("/ECP"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) { + if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) { printf("/ECP_RLE"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) { printf("/EPP"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } /* try more IEEE1284 modes */ if (bootverbose) { - if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, + if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID))) { printf("/NIBBLE_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, + if (!(error = ppb_1284_negociate(bus, PPB_PS2, PPB_REQUEST_ID))) { printf("/PS2_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, + if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_REQUEST_ID))) { printf("/ECP_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, + if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_REQUEST_ID | PPB_USE_RLE))) { printf("/ECP_RLE_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE, + if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE, PPB_EXTENSIBILITY_LINK))) { printf("/Extensibility Link"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } } printf("\n"); /* detect PnP devices */ - ppb->class_id = ppb_pnp_detect(ppb, &pnpdev); - - ppb_release_bus(&pnpdev); + ppb->class_id = ppb_pnp_detect(bus); return (0); end_scan: - ppb_release_bus(&pnpdev); return (error); } #endif /* !DONTPROBE_1284 */ -/* - * ppb_attachdevs() - * - * Called by ppcattach(), this function probes the ppbus and - * attaches found devices. - */ -int -ppb_attachdevs(struct ppb_data *ppb) +static int +ppbus_attach(device_t dev) { - struct ppb_device *dev; - struct ppb_driver **p_drvpp, *p_drvp; + int i; + int unit, disabled; + char *name; - LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ - p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; - -#ifndef DONTPROBE_1284 - /* detect IEEE1284 compliant devices */ - ppb_scan_bus(ppb); -#endif /* !DONTPROBE_1284 */ - /* - * Blindly try all probes here. Later we should look at - * the parallel-port PnP standard, and intelligently seek - * drivers based on configuration first. + * Add all devices configured to be attached to ppbus0. */ - while ((p_drvp = *p_drvpp++) != NULL) { - if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { - /* - * Add the device to the list of probed devices. - */ - LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); - - /* Call the device's attach routine */ - (void)p_drvp->attach(dev); - } + for (i = resource_query_string(-1, "at", "ppbus0"); + i != -1; + i = resource_query_string(i, "at", "ppbus0")) { + unit = resource_query_unit(i); + name = resource_query_name(i); + if (resource_int_value(name, unit, "disabled", &disabled) == 0) { + if (disabled) + continue; + } + ppbus_add_device(dev, name, unit); } - return (0); -} - -/* - * ppb_next_bus() - * - * Return the next bus in ppbus queue - */ -struct ppb_data * -ppb_next_bus(struct ppb_data *ppb) -{ - if (ppb == NULL) - return (ppbdata.lh_first); - - return (ppb->ppb_chain.le_next); -} + /* + * and ppbus? + */ + for (i = resource_query_string(-1, "at", "ppbus"); + i != -1; + i = resource_query_string(i, "at", "ppbus")) { + unit = resource_query_unit(i); + name = resource_query_name(i); + if (resource_int_value(name, unit, "disabled", &disabled) == 0) { + if (disabled) + continue; + } + ppbus_add_device(dev, name, unit); + } -/* - * ppb_lookup_bus() - * - * Get ppb_data structure pointer according to the base address of the ppbus - */ -struct ppb_data * -ppb_lookup_bus(int base_port) -{ - struct ppb_data *ppb; +#ifndef DONTPROBE_1284 + /* detect IEEE1284 compliant devices */ + ppb_scan_bus(dev); +#endif /* !DONTPROBE_1284 */ - for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) - if (ppb->ppb_link->base == base_port) - break; + /* launch attachement of the added children */ + bus_generic_attach(dev); - return (ppb); + return 0; } -/* - * ppb_lookup_link() - * - * Get ppb_data structure pointer according to the unit value - * of the corresponding link structure - */ -struct ppb_data * -ppb_lookup_link(int unit) +static int +ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, + void (*ihand)(void *), void *arg, void **cookiep) { - struct ppb_data *ppb; + int error; + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); - for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) - if (ppb->ppb_link->adapter_unit == unit) - break; + /* a device driver must own the bus to register an interrupt */ + if (ppb->ppb_owner != child) + return (EINVAL); - return (ppb); -} - -/* - * ppb_attach_device() - * - * Called by loadable kernel modules to add a device - */ -int -ppb_attach_device(struct ppb_device *dev) -{ - struct ppb_data *ppb = dev->ppb; + if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags, + ihand, arg, cookiep))) + return (error); - /* add the device to the list of probed devices */ - LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); + /* store the resource and the cookie for eventually forcing + * handler unregistration + */ + ppbdev->intr_cookie = *cookiep; + ppbdev->intr_resource = r; return (0); } -/* - * ppb_remove_device() - * - * Called by loadable kernel modules to remove a device - */ -void -ppb_remove_device(struct ppb_device *dev) +static int +ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) { + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); + + /* a device driver must own the bus to unregister an interrupt */ + if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) || + (ppbdev->intr_resource != r)) + return (EINVAL); - /* remove the device from the list of probed devices */ - LIST_REMOVE(dev, chain); + ppbdev->intr_cookie = 0; + ppbdev->intr_resource = 0; - return; + /* pass unregistration to the upper layer */ + return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih)); } /* @@ -466,10 +517,11 @@ ppb_remove_device(struct ppb_device *dev) * how : PPB_WAIT or PPB_DONTWAIT */ int -ppb_request_bus(struct ppb_device *dev, int how) +ppb_request_bus(device_t bus, device_t dev, int how) { int s, error = 0; - struct ppb_data *ppb = dev->ppb; + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); while (!error) { s = splhigh(); @@ -499,8 +551,8 @@ ppb_request_bus(struct ppb_device *dev, int how) * drivers that do not set there operating mode * during attachement */ - if (dev->ctx.valid) - ppb_set_mode(dev, dev->ctx.mode); + if (ppbdev->ctx.valid) + ppb_set_mode(bus, ppbdev->ctx.mode); splx(s); return (0); @@ -516,10 +568,17 @@ ppb_request_bus(struct ppb_device *dev, int how) * Release the device allocated with ppb_request_dev() */ int -ppb_release_bus(struct ppb_device *dev) +ppb_release_bus(device_t bus, device_t dev) { - int s; - struct ppb_data *ppb = dev->ppb; + int s, error; + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + + if (ppbdev->intr_resource != 0) + /* force interrupt handler unregistration when the ppbus is released */ + if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource, + ppbdev->intr_cookie))) + return (error); s = splhigh(); if (ppb->ppb_owner != dev) { @@ -531,13 +590,15 @@ ppb_release_bus(struct ppb_device *dev) splx(s); /* save the context of the device */ - dev->ctx.mode = ppb_get_mode(dev); + ppbdev->ctx.mode = ppb_get_mode(bus); /* ok, now the context of the device is valid */ - dev->ctx.valid = 1; + ppbdev->ctx.valid = 1; /* wakeup waiting processes */ wakeup(ppb); return (0); } + +DRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0); diff --git a/sys/dev/ppbus/ppbconf.h b/sys/dev/ppbus/ppbconf.h index 4160f0c..93fc886 100644 --- a/sys/dev/ppbus/ppbconf.h +++ b/sys/dev/ppbus/ppbconf.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu + * Copyright (c) 1997, 1998, 1999 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,9 +55,9 @@ #define PPB_OPTIONS_MASK 0xf0 #define PPB_IS_EPP(mode) (mode & PPB_EPP) -#define PPB_IN_EPP_MODE(dev) (PPB_IS_EPP (ppb_get_mode (dev))) -#define PPB_IN_NIBBLE_MODE(dev) (ppb_get_mode (dev) & PPB_NIBBLE) -#define PPB_IN_PS2_MODE(dev) (ppb_get_mode (dev) & PPB_PS2) +#define PPB_IN_EPP_MODE(bus) (PPB_IS_EPP (ppb_get_mode (bus))) +#define PPB_IN_NIBBLE_MODE(bus) (ppb_get_mode (bus) & PPB_NIBBLE) +#define PPB_IN_PS2_MODE(bus) (ppb_get_mode (bus) & PPB_PS2) #define n(flags) (~(flags) & (flags)) @@ -101,6 +101,28 @@ struct ppb_status { unsigned int busy:1; }; +/* Parallel port bus I/O opcodes */ +#define PPB_OUTSB_EPP 1 +#define PPB_OUTSW_EPP 2 +#define PPB_OUTSL_EPP 3 +#define PPB_INSB_EPP 4 +#define PPB_INSW_EPP 5 +#define PPB_INSL_EPP 6 +#define PPB_RDTR 7 +#define PPB_RSTR 8 +#define PPB_RCTR 9 +#define PPB_REPP_A 10 +#define PPB_REPP_D 11 +#define PPB_RECR 12 +#define PPB_RFIFO 13 +#define PPB_WDTR 14 +#define PPB_WSTR 15 +#define PPB_WCTR 16 +#define PPB_WEPP_A 17 +#define PPB_WEPP_D 18 +#define PPB_WECR 19 +#define PPB_WFIFO 20 + /* * How tsleep() is called in ppb_request_bus(). */ @@ -152,14 +174,23 @@ struct ppb_context { struct microseq *curmsq; /* currently executed microseqence */ }; +/* + * List of IVARS available to ppb device drivers + */ +#define PPBUS_IVAR_MODE 0 +#define PPBUS_IVAR_AVM 1 +#define PPBUS_IVAR_IRQ 2 + +/* other fields are reserved to the ppbus internals */ + struct ppb_device { - int id_unit; /* unit of the device */ - char *name; /* name of the device */ + const char *name; /* name of the device */ ushort mode; /* current mode of the device */ ushort avm; /* available IEEE1284 modes of * the device */ + uint flags; /* flags */ struct ppb_context ctx; /* context of the device */ @@ -172,76 +203,21 @@ struct ppb_device { * IEEE1284 code is used */ struct ppb_xfer put_xfer[PPB_MAX_XFER]; - - void (*intr)(int); /* interrupt handler */ - void (*bintr)(struct ppb_device *); /* interrupt handler */ + + struct resource *intr_resource; + void *intr_cookie; void *drv1, *drv2; /* drivers private data */ - - struct ppb_data *ppb; /* link to the ppbus */ - - LIST_ENTRY(ppb_device) chain; /* list of devices on the bus */ }; -/* - * Parallel Port Bus Adapter structure. - */ -struct ppb_adapter { - - void (*intr_handler)(int); - void (*reset_epp_timeout)(int); - void (*ecp_sync)(int); - - int (*exec_microseq)(int, struct ppb_microseq **); - - int (*setmode)(int, int); - int (*read)(int, char *, int, int); - int (*write)(int, char *, int, int); - - void (*outsb_epp)(int, char *, int); - void (*outsw_epp)(int, char *, int); - void (*outsl_epp)(int, char *, int); - void (*insb_epp)(int, char *, int); - void (*insw_epp)(int, char *, int); - void (*insl_epp)(int, char *, int); - - u_char (*r_dtr)(int); - u_char (*r_str)(int); - u_char (*r_ctr)(int); - u_char (*r_epp_A)(int); - u_char (*r_epp_D)(int); - u_char (*r_ecr)(int); - u_char (*r_fifo)(int); - - void (*w_dtr)(int, char); - void (*w_str)(int, char); - void (*w_ctr)(int, char); - void (*w_epp_A)(int, char); - void (*w_epp_D)(int, char); - void (*w_ecr)(int, char); - void (*w_fifo)(int, char); -}; - -/* - * ppb_link structure. - */ -struct ppb_link { - - int adapter_unit; /* unit of the adapter */ - int base; /* base address of the port */ - int id_irq; /* != 0 if irq enabled */ - int accum; /* microseq accum */ - char *ptr; /* current buffer pointer */ - +/* EPP standards */ #define EPP_1_9 0x0 /* default */ #define EPP_1_7 0x1 - - int epp_protocol; /* EPP protocol: 0=1.9, 1=1.7 */ - - struct ppb_adapter *adapter; /* link to the ppc adapter */ - struct ppb_data *ppbus; /* link to the ppbus */ -}; - + +/* Parallel Port Chipset IVARS */ /* elsewhere XXX */ +#define PPC_IVAR_EPP_PROTO 0 +#define PPC_IVAR_IRQ 1 + /* * Maximum size of the PnP info string */ @@ -263,113 +239,36 @@ struct ppb_data { #define PPB_PnP_SCANNER 8 #define PPB_PnP_DIGICAM 9 #define PPB_PnP_UNKNOWN 10 - int class_id; /* not a PnP device if class_id < 0 */ - - int state; /* current IEEE1284 state */ - int error; /* last IEEE1284 error */ + int class_id; /* not a PnP device if class_id < 0 */ - ushort mode; /* IEEE 1284-1994 mode - * NIBBLE, PS2, EPP or ECP */ + int state; /* current IEEE1284 state */ + int error; /* last IEEE1284 error */ - struct ppb_link *ppb_link; /* link to the adapter */ - struct ppb_device *ppb_owner; /* device which owns the bus */ - LIST_HEAD(, ppb_device) ppb_devs; /* list of devices on the bus */ - LIST_ENTRY(ppb_data) ppb_chain; /* list of busses */ -}; + int mode; /* IEEE 1284-1994 mode + * NIBBLE, PS2, EPP or ECP */ -/* - * Parallel Port Bus driver structure. - */ -struct ppb_driver -{ - struct ppb_device *(*probe)(struct ppb_data *ppb); - int (*attach)(struct ppb_device *pdp); - char *name; + void *ppb_owner; /* device which owns the bus */ }; -extern struct linker_set ppbdriver_set; - -extern struct ppb_data *ppb_alloc_bus(void); -extern struct ppb_data *ppb_next_bus(struct ppb_data *); -extern struct ppb_data *ppb_lookup_bus(int); -extern struct ppb_data *ppb_lookup_link(int); +extern int ppb_attach_device(device_t); +extern int ppb_request_bus(device_t, device_t, int); +extern int ppb_release_bus(device_t, device_t); -extern int ppb_attach_device(struct ppb_device *); -extern void ppb_remove_device(struct ppb_device *); -extern int ppb_attachdevs(struct ppb_data *); - -extern int ppb_request_bus(struct ppb_device *, int); -extern int ppb_release_bus(struct ppb_device *); - -extern void ppb_intr(struct ppb_link *); - -extern int ppb_poll_device(struct ppb_device *, int, char, char, int); - -extern int ppb_reset_epp_timeout(struct ppb_device *); -extern int ppb_ecp_sync(struct ppb_device *); -extern int ppb_get_status(struct ppb_device *, struct ppb_status *); - -extern int ppb_set_mode(struct ppb_device *, int); -extern int ppb_write(struct ppb_device *, char *, int, int); +/* bus related functions */ +extern int ppb_get_status(device_t, struct ppb_status *); +extern int ppb_poll_bus(device_t, int, char, char, int); +extern int ppb_reset_epp_timeout(device_t); +extern int ppb_ecp_sync(device_t); +extern int ppb_get_epp_protocol(device_t); +extern int ppb_set_mode(device_t, int); /* returns old mode */ +extern int ppb_get_mode(device_t); /* returns current mode */ +extern int ppb_write(device_t, char *, int, int); /* * These are defined as macros for speedup. - */ #define ppb_get_base_addr(dev) ((dev)->ppb->ppb_link->base) #define ppb_get_epp_protocol(dev) ((dev)->ppb->ppb_link->epp_protocol) #define ppb_get_irq(dev) ((dev)->ppb->ppb_link->id_irq) - -#define ppb_get_mode(dev) ((dev)->mode) - -/* This set of function access only to the EPP _data_ registers - * in 8, 16 and 32 bit modes */ -#define ppb_outsb_epp(dev,buf,cnt) \ - (*(dev)->ppb->ppb_link->adapter->outsb_epp) \ - ((dev)->ppb->ppb_link->adapter_unit, buf, cnt) -#define ppb_outsw_epp(dev,buf,cnt) \ - (*(dev)->ppb->ppb_link->adapter->outsw_epp) \ - ((dev)->ppb->ppb_link->adapter_unit, buf, cnt) -#define ppb_outsl_epp(dev,buf,cnt) \ - (*(dev)->ppb->ppb_link->adapter->outsl_epp) \ - ((dev)->ppb->ppb_link->adapter_unit, buf, cnt) -#define ppb_insb_epp(dev,buf,cnt) \ - (*(dev)->ppb->ppb_link->adapter->insb_epp) \ - ((dev)->ppb->ppb_link->adapter_unit, buf, cnt) -#define ppb_insw_epp(dev,buf,cnt) \ - (*(dev)->ppb->ppb_link->adapter->insw_epp) \ - ((dev)->ppb->ppb_link->adapter_unit, buf, cnt) -#define ppb_insl_epp(dev,buf,cnt) \ - (*(dev)->ppb->ppb_link->adapter->insl_epp) \ - ((dev)->ppb->ppb_link->adapter_unit, buf, cnt) - -#define ppb_repp_A(dev) (*(dev)->ppb->ppb_link->adapter->r_epp_A) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_repp_D(dev) (*(dev)->ppb->ppb_link->adapter->r_epp_D) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_recr(dev) (*(dev)->ppb->ppb_link->adapter->r_ecr) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_rfifo(dev) (*(dev)->ppb->ppb_link->adapter->r_fifo) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_wepp_A(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_epp_A) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) -#define ppb_wepp_D(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_epp_D) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) -#define ppb_wecr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ecr) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) -#define ppb_wfifo(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_fifo) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) - -#define ppb_rdtr(dev) (*(dev)->ppb->ppb_link->adapter->r_dtr) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_rstr(dev) (*(dev)->ppb->ppb_link->adapter->r_str) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_rctr(dev) (*(dev)->ppb->ppb_link->adapter->r_ctr) \ - ((dev)->ppb->ppb_link->adapter_unit) -#define ppb_wdtr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_dtr) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) -#define ppb_wstr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_str) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) -#define ppb_wctr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ctr) \ - ((dev)->ppb->ppb_link->adapter_unit, byte) + */ #endif diff --git a/sys/dev/ppbus/ppbio.h b/sys/dev/ppbus/ppbio.h new file mode 100644 index 0000000..2794edd --- /dev/null +++ b/sys/dev/ppbus/ppbio.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 1999 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 __PPBIO_H +#define __PPBIO_H + +/* + * Set of ppbus i/o routines callable from ppbus device drivers + */ + +#define ppb_outsb_epp(dev,buf,cnt) \ + (PPBUS_IO(device_get_parent(dev), PPB_OUTSB_EPP, buf, cnt, 0)) +#define ppb_outsw_epp(dev,buf,cnt) \ + (PPBUS_IO(device_get_parent(dev), PPB_OUTSW_EPP, buf, cnt, 0)) +#define ppb_outsl_epp(dev,buf,cnt) \ + (PPBUS_IO(device_get_parent(dev), PPB_OUTSL_EPP, buf, cnt, 0)) + +#define ppb_insb_epp(dev,buf,cnt) \ + (PPBUS_IO(device_get_parent(dev), PPB_INSB_EPP, buf, cnt, 0)) +#define ppb_insw_epp(dev,buf,cnt) \ + (PPBUS_IO(device_get_parent(dev), PPB_INSW_EPP, buf, cnt, 0)) +#define ppb_insl_epp(dev,buf,cnt) \ + (PPBUS_IO(device_get_parent(dev), PPB_INSL_EPP, buf, cnt, 0)) + +#define ppb_repp_A(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_REPP_A, 0, 0, 0)) +#define ppb_repp_D(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_REPP_D, 0, 0, 0)) +#define ppb_recr(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_RECR, 0, 0, 0)) +#define ppb_rfifo(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_RFIFO, 0, 0, 0)) + +#define ppb_wepp_A(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WEPP_A, 0, 0, byte)) +#define ppb_wepp_D(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WEPP_D, 0, 0, byte)) +#define ppb_wecr(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WECR, 0, 0, byte)) +#define ppb_wfifo(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WFIFO, 0, 0, byte)) + +#define ppb_rdtr(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_RDTR, 0, 0, 0)) +#define ppb_rstr(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_RSTR, 0, 0, 0)) +#define ppb_rctr(dev) \ + (PPBUS_IO(device_get_parent(dev), PPB_RCTR, 0, 0, 0)) + +#define ppb_wdtr(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WDTR, 0, 0, byte)) +#define ppb_wstr(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WSTR, 0, 0, byte)) +#define ppb_wctr(dev,byte) \ + (PPBUS_IO(device_get_parent(dev), PPB_WCTR, 0, 0, byte)) + +#endif diff --git a/sys/dev/ppbus/ppbus_if.m b/sys/dev/ppbus/ppbus_if.m new file mode 100644 index 0000000..00af081 --- /dev/null +++ b/sys/dev/ppbus/ppbus_if.m @@ -0,0 +1,92 @@ +# +# Copyright (c) 1999 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 <dev/ppbus/ppbconf.h> + +INTERFACE ppbus; + +# +# Do low level i/o operations +# +METHOD u_char io { + device_t dev; + int opcode; + u_char *addr; + int cnt; + u_char byte; +}; + +# +# Execution of a microsequence +# +METHOD int exec_microseq { + device_t dev; + struct ppb_microseq **ppb_microseq; +}; + +# +# Reset EPP timeout +# +METHOD int reset_epp { + device_t dev; +} + +# +# Set chipset mode +# +METHOD int setmode { + device_t dev; + int mode; +} + +# +# Synchronize ECP FIFO +# +METHOD int ecp_sync { + device_t dev; +} + +# +# Do chipset dependent low level read +# +METHOD int read { + device_t dev; + char *buf; + int len; + int how; +} + +# +# Do chipset dependent low level write +# +METHOD int write { + device_t dev; + char *buf; + int len; + int how; +} diff --git a/sys/dev/ppbus/ppi.c b/sys/dev/ppbus/ppi.c index c610e7f..bd0a638 100644 --- a/sys/dev/ppbus/ppi.c +++ b/sys/dev/ppbus/ppi.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu, Michael Smith + * Copyright (c) 1997, 1998, 1999 Nicolas Souchu, Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,27 +30,35 @@ #if NPPI > 0 +#include "opt_ppb_1284.h" + #include <sys/param.h> #include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/uio.h> -#include <sys/malloc.h> #include <sys/fcntl.h> #include <machine/clock.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> -#include "opt_ppb_1284.h" - #ifdef PERIPH_1284 #include <dev/ppbus/ppb_1284.h> #endif #include <dev/ppbus/ppi.h> +#include "ppbus_if.h" + +#include <dev/ppbus/ppbio.h> + #define BUFSIZE 512 struct ppi_data { @@ -64,25 +72,36 @@ struct ppi_data { int ppi_mode; /* IEEE1284 mode */ char ppi_buffer[BUFSIZE]; - struct ppb_device ppi_dev; + struct resource *intr_resource; /* interrupt resource */ + void *intr_cookie; /* interrupt registration cookie */ }; -#define MAXPPI 8 /* XXX not much better! */ -static int nppi = 0; -static struct ppi_data *ppidata[MAXPPI]; +#define DEVTOSOFTC(dev) \ + ((struct ppi_data *)device_get_softc(dev)) +#define UNITOSOFTC(unit) \ + ((struct ppi_data *)devclass_get_softc(ppi_devclass, (unit))) +#define UNITODEVICE(unit) \ + (devclass_get_device(ppi_devclass, (unit))) -/* - * Make ourselves visible as a ppbus driver - */ +static int ppi_probe(device_t); +static int ppi_attach(device_t); +static void ppiintr(void *arg); + +static devclass_t ppi_devclass; -static struct ppb_device *ppiprobe(struct ppb_data *ppb); -static int ppiattach(struct ppb_device *dev); -static void ppiintr(int unit); +static device_method_t ppi_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppi_probe), + DEVMETHOD(device_attach, ppi_attach), -static struct ppb_driver ppidriver = { - ppiprobe, ppiattach, "ppi" + { 0, 0 } +}; + +static driver_t ppi_driver = { + "ppi", + ppi_methods, + sizeof(struct ppi_data), }; -DATA_SET(ppbdriver_set, ppidriver); static d_open_t ppiopen; static d_close_t ppiclose; @@ -111,23 +130,25 @@ static struct cdevsw ppi_cdevsw = { #ifdef PERIPH_1284 static void -ppi_enable_intr(struct ppi_data *ppi) +ppi_enable_intr(device_t ppidev) { char r; + device_t ppbus = device_get_parent(ppidev); - r = ppb_rctr(&ppi->ppi_dev); - ppb_wctr(&ppi->ppi_dev, r | IRQENABLE); + r = ppb_rctr(ppbus); + ppb_wctr(ppbus, r | IRQENABLE); return; } static void -ppi_disable_intr(struct ppi_data *ppi) +ppi_disable_intr(device_t ppidev) { char r; + device_t ppbus = device_get_parent(ppidev); - r = ppb_rctr(&ppi->ppi_dev); - ppb_wctr(&ppi->ppi_dev, r & ~IRQENABLE); + r = ppb_rctr(ppbus); + ppb_wctr(ppbus, r & ~IRQENABLE); return; } @@ -135,55 +156,48 @@ ppi_disable_intr(struct ppi_data *ppi) #endif /* PERIPH_1284 */ /* - * ppiprobe() + * ppi_probe() */ -static struct ppb_device * -ppiprobe(struct ppb_data *ppb) +static int +ppi_probe(device_t dev) { struct ppi_data *ppi; static int once; + /* probe is always ok */ + device_set_desc(dev, "Parallel I/O"); + if (!once++) cdevsw_add(&ppi_cdevsw); - ppi = (struct ppi_data *) malloc(sizeof(struct ppi_data), - M_TEMP, M_NOWAIT); - if (!ppi) { - printf("ppi: cannot malloc!\n"); - return 0; - } + ppi = DEVTOSOFTC(dev); bzero(ppi, sizeof(struct ppi_data)); - ppidata[nppi] = ppi; - - /* - * ppi dependent initialisation. - */ - ppi->ppi_unit = nppi; - - /* - * ppbus dependent initialisation. - */ - ppi->ppi_dev.id_unit = ppi->ppi_unit; - ppi->ppi_dev.ppb = ppb; - ppi->ppi_dev.intr = ppiintr; - - /* Ok, go to next device on next probe */ - nppi ++; - - return &ppi->ppi_dev; + return (0); } +/* + * ppi_attach() + */ static int -ppiattach(struct ppb_device *dev) +ppi_attach(device_t dev) { - /* - * Report ourselves - */ - printf("ppi%d: <generic parallel i/o> on ppbus %d\n", - dev->id_unit, dev->ppb->ppb_link->adapter_unit); + uintptr_t irq; + int zero = 0; + struct ppi_data *ppi = DEVTOSOFTC(dev); + + /* retrive the irq */ + BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq); - return (1); + /* declare our interrupt handler */ + ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, + &zero, irq, irq, 1, RF_ACTIVE); + + make_dev(&ppi_cdevsw, device_get_unit(dev), /* XXX cleanup */ + UID_ROOT, GID_WHEEL, + 0600, "ppi%d", device_get_unit(dev)); + + return (0); } /* @@ -199,20 +213,22 @@ ppiattach(struct ppb_device *dev) * */ static void -ppiintr(int unit) +ppiintr(void *arg) { #ifdef PERIPH_1284 - struct ppi_data *ppi = ppidata[unit]; + device_t ppidev = (device_t)arg; + device_t ppbus = device_get_parent(ppidev); + struct ppi_data *ppi = DEVTOSOFTC(ppidev); - ppi_disable_intr(ppi); + ppi_disable_intr(ppidev); - switch (ppi->ppi_dev.ppb->state) { + switch (ppb_1284_get_state(ppbus)) { /* accept IEEE1284 negociation then wakeup an waiting process to * continue negociation at process level */ case PPB_FORWARD_IDLE: /* Event 1 */ - if ((ppb_rstr(&ppi->ppi_dev) & (SELECT | nBUSY)) == + if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) == (SELECT | nBUSY)) { /* IEEE1284 negociation */ #ifdef DEBUG_1284 @@ -220,15 +236,15 @@ ppiintr(int unit) #endif /* Event 2 - prepare for reading the ext. value */ - ppb_wctr(&ppi->ppi_dev, (PCD | STROBE | nINIT) & ~SELECTIN); + ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN); - ppi->ppi_dev.ppb->state = PPB_NEGOCIATION; + ppb_1284_set_state(ppbus, PPB_NEGOCIATION); } else { #ifdef DEBUG_1284 - printf("0x%x", ppb_rstr(&ppi->ppi_dev)); + printf("0x%x", ppb_rstr(ppbus)); #endif - ppb_peripheral_terminate(&ppi->ppi_dev, PPB_DONTWAIT); + ppb_peripheral_terminate(ppbus, PPB_DONTWAIT); break; } @@ -242,14 +258,14 @@ ppiintr(int unit) break; default: #ifdef DEBUG_1284 - printf("?%d", ppi->ppi_dev.ppb->state); + printf("?%d", ppb_1284_get_state(ppbus); #endif - ppi->ppi_dev.ppb->state = PPB_FORWARD_IDLE; - ppb_set_mode(&ppi->ppi_dev, PPB_COMPATIBLE); + ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE); + ppb_set_mode(ppbus, PPB_COMPATIBLE); break; } - ppi_enable_intr(ppi); + ppi_enable_intr(ppidev); #endif /* PERIPH_1284 */ return; @@ -259,19 +275,25 @@ static int ppiopen(dev_t dev, int flags, int fmt, struct proc *p) { u_int unit = minor(dev); - struct ppi_data *ppi = ppidata[unit]; + struct ppi_data *ppi = UNITOSOFTC(unit); + device_t ppidev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppidev); int res; - if (unit >= nppi) + if (!ppi) return (ENXIO); if (!(ppi->ppi_flags & HAVE_PPBUS)) { - if ((res = ppb_request_bus(&ppi->ppi_dev, + if ((res = ppb_request_bus(ppbus, ppidev, (flags & O_NONBLOCK) ? PPB_DONTWAIT : (PPB_WAIT | PPB_INTR)))) return (res); ppi->ppi_flags |= HAVE_PPBUS; + + /* register our interrupt handler */ + BUS_SETUP_INTR(device_get_parent(ppidev), ppidev, ppi->intr_resource, + INTR_TYPE_TTY, ppiintr, dev, &ppi->intr_cookie); } ppi->ppi_count += 1; @@ -282,26 +304,30 @@ static int ppiclose(dev_t dev, int flags, int fmt, struct proc *p) { u_int unit = minor(dev); - struct ppi_data *ppi = ppidata[unit]; + struct ppi_data *ppi = UNITOSOFTC(unit); + device_t ppidev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppidev); ppi->ppi_count --; if (!ppi->ppi_count) { #ifdef PERIPH_1284 - switch (ppi->ppi_dev.ppb->state) { + switch (ppb_1284_get_state(ppbus)) { case PPB_PERIPHERAL_IDLE: - ppb_peripheral_terminate(&ppi->ppi_dev, 0); + ppb_peripheral_terminate(ppbus, 0); break; case PPB_REVERSE_IDLE: case PPB_EPP_IDLE: case PPB_ECP_FORWARD_IDLE: default: - ppb_1284_terminate(&ppi->ppi_dev); + ppb_1284_terminate(ppbus); break; } #endif /* PERIPH_1284 */ - ppb_release_bus(&ppi->ppi_dev); + /* unregistration of interrupt forced by release */ + ppb_release_bus(ppbus, ppidev); + ppi->ppi_flags &= ~HAVE_PPBUS; } @@ -321,19 +347,21 @@ ppiread(dev_t dev, struct uio *uio, int ioflag) { #ifdef PERIPH_1284 u_int unit = minor(dev); - struct ppi_data *ppi = ppidata[unit]; + struct ppi_data *ppi = UNITOSOFTC(unit); + device_t ppidev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppidev); int len, error = 0; - switch (ppi->ppi_dev.ppb->state) { + switch (ppb_1284_get_state(ppbus)) { case PPB_PERIPHERAL_IDLE: - ppb_peripheral_terminate(&ppi->ppi_dev, 0); + ppb_peripheral_terminate(ppbus, 0); /* fall throught */ case PPB_FORWARD_IDLE: /* if can't negociate NIBBLE mode then try BYTE mode, * the peripheral may be a computer */ - if ((ppb_1284_negociate(&ppi->ppi_dev, + if ((ppb_1284_negociate(ppbus, ppi->ppi_mode = PPB_NIBBLE, 0))) { /* XXX Wait 2 seconds to let the remote host some @@ -341,7 +369,7 @@ ppiread(dev_t dev, struct uio *uio, int ioflag) */ tsleep(ppi, PPBPRI, "ppiread", 2*hz); - if ((error = ppb_1284_negociate(&ppi->ppi_dev, + if ((error = ppb_1284_negociate(ppbus, ppi->ppi_mode = PPB_BYTE, 0))) return (error); } @@ -360,7 +388,7 @@ ppiread(dev_t dev, struct uio *uio, int ioflag) /* read data */ len = 0; while (uio->uio_resid) { - if ((error = ppb_1284_read(&ppi->ppi_dev, ppi->ppi_mode, + if ((error = ppb_1284_read(ppbus, ppi->ppi_mode, ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid), &len))) { goto error; @@ -403,8 +431,9 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) { #ifdef PERIPH_1284 u_int unit = minor(dev); - struct ppi_data *ppi = ppidata[unit]; - struct ppb_data *ppb = ppi->ppi_dev.ppb; + struct ppi_data *ppi = UNITOSOFTC(unit); + device_t ppidev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppidev); int len, error = 0, sent; #if 0 @@ -419,7 +448,7 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) }; /* negociate ECP mode */ - if (ppb_1284_negociate(&ppi->ppi_dev, PPB_ECP, 0)) { + if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) { printf("ppiwrite: ECP negociation failed\n"); } @@ -428,7 +457,7 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len); - error = ppb_MS_microseq(&ppi->ppi_dev, msq, &ret); + error = ppb_MS_microseq(ppbus, msq, &ret); } #endif @@ -436,7 +465,7 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) * wait for the appropriate state */ if (ppb->state < PPB_PERIPHERAL_NEGOCIATION) - ppb_1284_terminate(&ppi->ppi_dev); + ppb_1284_terminate(ppbus); while (ppb->state != PPB_PERIPHERAL_IDLE) { /* XXX should check a variable before sleeping */ @@ -444,7 +473,7 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) printf("s"); #endif - ppi_enable_intr(ppi); + ppi_enable_intr(ppidev); /* sleep until IEEE1284 negociation starts */ error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0); @@ -452,7 +481,7 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) switch (error) { case 0: /* negociate peripheral side with BYTE mode */ - ppb_peripheral_negociate(&ppi->ppi_dev, PPB_BYTE, 0); + ppb_peripheral_negociate(ppbus, PPB_BYTE, 0); break; case EWOULDBLOCK: break; @@ -467,7 +496,7 @@ ppiwrite(dev_t dev, struct uio *uio, int ioflag) /* negociation done, write bytes to master host */ while ((len = min(uio->uio_resid, BUFSIZE)) != 0) { uiomove(ppi->ppi_buffer, len, uio); - if ((error = byte_peripheral_write(&ppi->ppi_dev, + if ((error = byte_peripheral_write(ppbus, ppi->ppi_buffer, len, &sent))) goto error; #ifdef DEBUG_1284 @@ -488,55 +517,54 @@ static int ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { u_int unit = minor(dev); - struct ppi_data *ppi = ppidata[unit]; + device_t ppidev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppidev); int error = 0; u_int8_t *val = (u_int8_t *)data; switch (cmd) { case PPIGDATA: /* get data register */ - *val = ppb_rdtr(&ppi->ppi_dev); + *val = ppb_rdtr(ppbus); break; case PPIGSTATUS: /* get status bits */ - *val = ppb_rstr(&ppi->ppi_dev); + *val = ppb_rstr(ppbus); break; case PPIGCTRL: /* get control bits */ - *val = ppb_rctr(&ppi->ppi_dev); + *val = ppb_rctr(ppbus); break; case PPIGEPPD: /* get EPP data bits */ - *val = ppb_repp_D(&ppi->ppi_dev); + *val = ppb_repp_D(ppbus); break; case PPIGECR: /* get ECP bits */ - *val = ppb_recr(&ppi->ppi_dev); + *val = ppb_recr(ppbus); break; case PPIGFIFO: /* read FIFO */ - *val = ppb_rfifo(&ppi->ppi_dev); + *val = ppb_rfifo(ppbus); break; - case PPISDATA: /* set data register */ - ppb_wdtr(&ppi->ppi_dev, *val); + ppb_wdtr(ppbus, *val); break; case PPISSTATUS: /* set status bits */ - ppb_wstr(&ppi->ppi_dev, *val); + ppb_wstr(ppbus, *val); break; case PPISCTRL: /* set control bits */ - ppb_wctr(&ppi->ppi_dev, *val); + ppb_wctr(ppbus, *val); break; case PPISEPPD: /* set EPP data bits */ - ppb_wepp_D(&ppi->ppi_dev, *val); + ppb_wepp_D(ppbus, *val); break; case PPISECR: /* set ECP bits */ - ppb_wecr(&ppi->ppi_dev, *val); + ppb_wecr(ppbus, *val); break; case PPISFIFO: /* write FIFO */ - ppb_wfifo(&ppi->ppi_dev, *val); + ppb_wfifo(ppbus, *val); break; - case PPIGEPPA: /* get EPP address bits */ - *val = ppb_repp_A(&ppi->ppi_dev); + *val = ppb_repp_A(ppbus); break; case PPISEPPA: /* set EPP address bits */ - ppb_wepp_A(&ppi->ppi_dev, *val); + ppb_wepp_A(ppbus, *val); break; default: error = ENOTTY; @@ -546,4 +574,6 @@ ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) return (error); } +DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0); + #endif /* NPPI */ diff --git a/sys/dev/ppbus/pps.c b/sys/dev/ppbus/pps.c index 1189c58..9a540dc 100644 --- a/sys/dev/ppbus/pps.c +++ b/sys/dev/ppbus/pps.c @@ -18,11 +18,18 @@ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/conf.h> #include <sys/timepps.h> #include <sys/malloc.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> #include <dev/ppbus/ppbconf.h> +#include "ppbus_if.h" +#include <dev/ppbus/ppbio.h> #include "pps.h" #define PPS_NAME "pps" /* our official name */ @@ -31,23 +38,37 @@ struct pps_data { int pps_open; struct ppb_device pps_dev; struct pps_state pps; + + struct resource *intr_resource; /* interrupt resource */ + void *intr_cookie; /* interrupt registration cookie */ }; -static int npps; +static int ppsprobe(device_t dev); +static int ppsattach(device_t dev); +static void ppsintr(void *arg); -/* - * Make ourselves visible as a ppbus driver - */ +#define DEVTOSOFTC(dev) \ + ((struct pps_data *)device_get_softc(dev)) +#define UNITOSOFTC(unit) \ + ((struct pps_data *)devclass_get_softc(pps_devclass, (unit))) +#define UNITODEVICE(unit) \ + (devclass_get_device(pps_devclass, (unit))) -static struct ppb_device *ppsprobe(struct ppb_data *ppb); -static int ppsattach(struct ppb_device *dev); -static void ppsintr(struct ppb_device *ppd); +static devclass_t pps_devclass; -static struct ppb_driver ppsdriver = { - ppsprobe, ppsattach, PPS_NAME +static device_method_t pps_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppsprobe), + DEVMETHOD(device_attach, ppsattach), + + { 0, 0 } }; -DATA_SET(ppbdriver_set, ppsdriver); +static driver_t pps_driver = { + PPS_NAME, + pps_methods, + sizeof(struct pps_data), +}; static d_open_t ppsopen; static d_close_t ppsclose; @@ -71,71 +92,76 @@ static struct cdevsw pps_cdevsw = { /* bmaj */ -1 }; - -static struct ppb_device * -ppsprobe(struct ppb_data *ppb) +static int +ppsprobe(device_t ppsdev) { struct pps_data *sc; static int once; dev_t dev; + int unit; if (!once++) cdevsw_add(&pps_cdevsw); - sc = (struct pps_data *) malloc(sizeof(struct pps_data), - M_TEMP, M_NOWAIT); - if (!sc) { - printf(PPS_NAME ": cannot malloc!\n"); - return (0); - } + sc = DEVTOSOFTC(ppsdev); bzero(sc, sizeof(struct pps_data)); - dev = make_dev(&pps_cdevsw, npps, - UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps); + unit = device_get_unit(ppsdev); + dev = make_dev(&pps_cdevsw, unit, + UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", unit); - dev->si_drv1 = sc; - - sc->pps_dev.id_unit = npps++; - sc->pps_dev.ppb = ppb; - sc->pps_dev.name = ppsdriver.name; - sc->pps_dev.bintr = ppsintr; - sc->pps_dev.drv1 = sc; + device_set_desc(ppsdev, "Pulse per second Timing Interface"); sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; pps_init(&sc->pps); - return (&sc->pps_dev); + return (0); } static int -ppsattach(struct ppb_device *dev) +ppsattach(device_t dev) { + struct pps_data *sc = DEVTOSOFTC(dev); + device_t ppbus = device_get_parent(dev); + int irq, zero = 0; - /* - * Report ourselves - */ - printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", - dev->id_unit, dev->ppb->ppb_link->adapter_unit); + /* retrieve the ppbus irq */ + BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); - return (1); + if (irq > 0) { + /* declare our interrupt handler */ + sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, + &zero, irq, irq, 1, RF_SHAREABLE); + } + /* interrupts seem mandatory */ + if (sc->intr_resource == 0) + return (ENXIO); + + return (0); } static int ppsopen(dev_t dev, int flags, int fmt, struct proc *p) { - struct pps_data *sc; u_int unit = minor(dev); - - if ((unit >= npps)) - return (ENXIO); - - sc = dev->si_drv1; + struct pps_data *sc = UNITOSOFTC(unit); + device_t ppsdev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppsdev); + int error; if (!sc->pps_open) { - if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) + if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) return (EINTR); - ppb_wctr(&sc->pps_dev, 0); - ppb_wctr(&sc->pps_dev, IRQENABLE); + /* attach the interrupt handler */ + if ((error = BUS_SETUP_INTR(ppbus, ppsdev, sc->intr_resource, + INTR_TYPE_TTY, ppsintr, ppsdev, + &sc->intr_cookie))) { + ppb_release_bus(ppbus, ppsdev); + return (error); + } + + ppb_wctr(ppbus, 0); + ppb_wctr(ppbus, IRQENABLE); sc->pps_open = 1; } @@ -145,41 +171,49 @@ ppsopen(dev_t dev, int flags, int fmt, struct proc *p) static int ppsclose(dev_t dev, int flags, int fmt, struct proc *p) { - struct pps_data *sc = dev->si_drv1; + u_int unit = minor(dev); + struct pps_data *sc = UNITOSOFTC(unit); + device_t ppsdev = UNITODEVICE(unit); + device_t ppbus = device_get_parent(ppsdev); sc->pps.ppsparam.mode = 0; /* PHK ??? */ - ppb_wdtr(&sc->pps_dev, 0); - ppb_wctr(&sc->pps_dev, 0); + ppb_wdtr(ppbus, 0); + ppb_wctr(ppbus, 0); - ppb_release_bus(&sc->pps_dev); + /* Note: the interrupt handler is automatically detached */ + ppb_release_bus(ppbus, ppsdev); sc->pps_open = 0; return(0); } static void -ppsintr(struct ppb_device *ppd) +ppsintr(void *arg) { - struct pps_data *sc = ppd->drv1; + device_t ppsdev = (device_t)arg; + device_t ppbus = device_get_parent(ppsdev); + struct pps_data *sc = DEVTOSOFTC(ppsdev); struct timecounter *tc; unsigned count; tc = timecounter; count = timecounter->tc_get_timecount(tc); - if (!(ppb_rstr(&sc->pps_dev) & nACK)) + if (!(ppb_rstr(ppbus) & nACK)) return; if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) - ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); + ppb_wctr(ppbus, IRQENABLE | AUTOFEED); pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) - ppb_wctr(&sc->pps_dev, IRQENABLE); + ppb_wctr(ppbus, IRQENABLE); } static int ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { - struct pps_data *sc = dev->si_drv1; + u_int unit = minor(dev); + struct pps_data *sc = UNITOSOFTC(unit); return (pps_ioctl(cmd, data, &sc->pps)); } +DRIVER_MODULE(pps, ppbus, pps_driver, pps_devclass, 0, 0); diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c index 23e6058..51ccacf 100644 --- a/sys/dev/ppbus/vpo.c +++ b/sys/dev/ppbus/vpo.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu + * Copyright (c) 1997, 1998, 1999 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,8 +30,8 @@ #ifdef _KERNEL #include <sys/param.h> #include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/buf.h> +#include <sys/module.h> +#include <sys/bus.h> #include <machine/clock.h> @@ -56,6 +56,8 @@ #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/vpoio.h> +#include "ppbus_if.h" + struct vpo_sense { struct scsi_sense cmd; unsigned int stat; @@ -79,96 +81,84 @@ struct vpo_data { struct vpoio_data vpo_io; /* interface to low level functions */ }; -/* cam related functions */ -static void vpo_action(struct cam_sim *sim, union ccb *ccb); -static void vpo_poll(struct cam_sim *sim); +static int vpo_probe(device_t); +static int vpo_attach(device_t); -static int nvpo = 0; -#define MAXVP0 8 /* XXX not much better! */ -static struct vpo_data *vpodata[MAXVP0]; +#define DEVTOSOFTC(dev) \ + ((struct vpo_data *)device_get_softc(dev)) -#ifdef _KERNEL +static devclass_t vpo_devclass; -/* - * Make ourselves visible as a ppbus driver - */ -static struct ppb_device *vpoprobe(struct ppb_data *ppb); -static int vpoattach(struct ppb_device *dev); +static device_method_t vpo_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, vpo_probe), + DEVMETHOD(device_attach, vpo_attach), -static struct ppb_driver vpodriver = { - vpoprobe, vpoattach, "vpo" + { 0, 0 } }; -DATA_SET(ppbdriver_set, vpodriver); -#endif +static driver_t vpo_driver = { + "vpo", + vpo_methods, + sizeof(struct vpo_data), +}; + +/* cam related functions */ +static void vpo_action(struct cam_sim *sim, union ccb *ccb); +static void vpo_poll(struct cam_sim *sim); /* - * vpoprobe() - * - * Called by ppb_attachdevs(). + * vpo_probe() */ -static struct ppb_device * -vpoprobe(struct ppb_data *ppb) +static int +vpo_probe(device_t dev) { struct vpo_data *vpo; - struct ppb_device *dev; - - if (nvpo >= MAXVP0) { - printf("vpo: Too many devices (max %d)\n", MAXVP0); - return(NULL); - } + int error; - vpo = (struct vpo_data *)malloc(sizeof(struct vpo_data), - M_DEVBUF, M_NOWAIT); - if (!vpo) { - printf("vpo: cannot malloc!\n"); - return(NULL); - } + vpo = DEVTOSOFTC(dev); bzero(vpo, sizeof(struct vpo_data)); - vpodata[nvpo] = vpo; - /* vpo dependent initialisation */ - vpo->vpo_unit = nvpo; - - /* ok, go to next device on next probe */ - nvpo ++; + vpo->vpo_unit = device_get_unit(dev); /* low level probe */ vpoio_set_unit(&vpo->vpo_io, vpo->vpo_unit); /* check ZIP before ZIP+ or imm_probe() will send controls to * the printer or whatelse connected to the port */ - if ((dev = vpoio_probe(ppb, &vpo->vpo_io))) { + if ((error = vpoio_probe(dev, &vpo->vpo_io)) == 0) { vpo->vpo_isplus = 0; - } else if ((dev = imm_probe(ppb, &vpo->vpo_io))) { + device_set_desc(dev, + "Iomega VPI0 Parallel to SCSI interface"); + } else if ((error = imm_probe(dev, &vpo->vpo_io)) == 0) { vpo->vpo_isplus = 1; + device_set_desc(dev, + "Iomega Matchmaker Parallel to SCSI interface"); } else { - free(vpo, M_DEVBUF); - return (NULL); + return (error); } - return (dev); + return (0); } /* - * vpoattach() - * - * Called by ppb_attachdevs(). + * vpo_attach() */ static int -vpoattach(struct ppb_device *dev) +vpo_attach(device_t dev) { - struct vpo_data *vpo = vpodata[dev->id_unit]; + struct vpo_data *vpo = DEVTOSOFTC(dev); struct cam_devq *devq; + int error; /* low level attachment */ if (vpo->vpo_isplus) { - if (!imm_attach(&vpo->vpo_io)) - return (0); + if ((error = imm_attach(&vpo->vpo_io))) + return (error); } else { - if (!vpoio_attach(&vpo->vpo_io)) - return (0); + if ((error = vpoio_attach(&vpo->vpo_io))) + return (error); } /* @@ -178,18 +168,19 @@ vpoattach(struct ppb_device *dev) devq = cam_simq_alloc(/*maxopenings*/1); /* XXX What about low-level detach on error? */ if (devq == NULL) - return (0); + return (ENXIO); - vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, dev->id_unit, + vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, + device_get_unit(dev), /*untagged*/1, /*tagged*/0, devq); if (vpo->sim == NULL) { cam_simq_free(devq); - return (0); + return (ENXIO); } if (xpt_bus_register(vpo->sim, /*bus*/0) != CAM_SUCCESS) { cam_sim_free(vpo->sim, /*free_devq*/TRUE); - return (0); + return (ENXIO); } if (xpt_create_path(&vpo->path, /*periph*/NULL, @@ -197,12 +188,12 @@ vpoattach(struct ppb_device *dev) CAM_LUN_WILDCARD) != CAM_REQ_CMP) { xpt_bus_deregister(cam_sim_path(vpo->sim)); cam_sim_free(vpo->sim, /*free_devq*/TRUE); - return (0); + return (ENXIO); } /* all went ok */ - return (1); + return (0); } /* @@ -445,3 +436,5 @@ vpo_poll(struct cam_sim *sim) /* The ZIP is actually always polled throw vpo_action() */ return; } + +DRIVER_MODULE(vpo, ppbus, vpo_driver, vpo_devclass, 0, 0); diff --git a/sys/dev/ppbus/vpoio.c b/sys/dev/ppbus/vpoio.c index 73e4adb..e5fd445 100644 --- a/sys/dev/ppbus/vpoio.c +++ b/sys/dev/ppbus/vpoio.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 Nicolas Souchu + * Copyright (c) 1998, 1999 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,6 +30,8 @@ #ifdef _KERNEL #include <sys/param.h> #include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/malloc.h> #include <sys/buf.h> @@ -43,10 +45,13 @@ #include "opt_vpo.h" +#include <dev/ppbus/ppbio.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> #include <dev/ppbus/vpoio.h> +#include "ppbus_if.h" + /* * The driver pools the drive. We may add a timeout queue to avoid * active polling on nACK. I've tried this but it leads to unreliable @@ -271,10 +276,11 @@ static struct ppb_microseq in_disk_mode[] = { static int vpoio_disconnect(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; - ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret); - return (ppb_release_bus(&vpo->vpo_dev)); + ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); + return (ppb_release_bus(ppbus, vpo->vpo_dev)); } /* @@ -283,10 +289,11 @@ vpoio_disconnect(struct vpoio_data *vpo) static int vpoio_connect(struct vpoio_data *vpo, int how) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int error; int ret; - if ((error = ppb_request_bus(&vpo->vpo_dev, how))) { + if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, how))) { #ifdef VP0_DEBUG printf("%s: can't request bus!\n", __FUNCTION__); @@ -294,10 +301,10 @@ vpoio_connect(struct vpoio_data *vpo, int how) return error; } - if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) - ppb_MS_microseq(&vpo->vpo_dev, connect_epp_microseq, &ret); + if (PPB_IN_EPP_MODE(ppbus)) + ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret); else - ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret); return (0); } @@ -310,6 +317,7 @@ vpoio_connect(struct vpoio_data *vpo, int how) static void vpoio_reset (struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; struct ppb_microseq reset_microseq[] = { @@ -324,7 +332,7 @@ vpoio_reset (struct vpoio_data *vpo) }; ppb_MS_init_msq(reset_microseq, 1, INITIATOR, 1 << VP0_INITIATOR); - ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, &ret); return; } @@ -335,9 +343,10 @@ vpoio_reset (struct vpoio_data *vpo) static int vpoio_in_disk_mode(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; - ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret); return (ret); } @@ -350,37 +359,38 @@ vpoio_in_disk_mode(struct vpoio_data *vpo) static int vpoio_detect(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int error, ret; /* allocate the bus, then apply microsequences */ - if ((error = ppb_request_bus(&vpo->vpo_dev, PPB_DONTWAIT))) + if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_DONTWAIT))) return (error); - ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); - if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) - ppb_MS_microseq(&vpo->vpo_dev, connect_epp_microseq, &ret); + if (PPB_IN_EPP_MODE(ppbus)) + ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret); else - ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret); - ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret); if (!ret) { /* try spp mode (maybe twice or because previous mode was PS2) * NIBBLE mode will be restored on next transfers if detection * succeed */ - ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE); - ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret); + ppb_set_mode(ppbus, PPB_NIBBLE); + ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret); - ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret); if (!ret) { if (bootverbose) printf("vpo%d: can't connect to the drive\n", vpo->vpo_unit); /* disconnect and release the bus */ - ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, + ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); goto error; } @@ -389,12 +399,12 @@ vpoio_detect(struct vpoio_data *vpo) /* send SCSI reset signal */ vpoio_reset(vpo); - ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); /* ensure we are disconnected or daisy chained peripheral * may cause serious problem to the disk */ - ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret); if (ret) { if (bootverbose) printf("vpo%d: can't disconnect from the drive\n", @@ -402,11 +412,11 @@ vpoio_detect(struct vpoio_data *vpo) goto error; } - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); return (0); error: - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); return (VP0_EINITFAILED); } @@ -416,37 +426,35 @@ error: static int vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size) { - + device_t ppbus = device_get_parent(vpo->vpo_dev); int error = 0; - ppb_MS_exec(&vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer, + ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer, (union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error); #if 0 /* XXX EPP 1.9 not implemented with microsequences */ else { - ppb_reset_epp_timeout(&vpo->vpo_dev); - ppb_wctr(&vpo->vpo_dev, - H_AUTO | H_SELIN | H_INIT | H_STROBE); + ppb_reset_epp_timeout(ppbus); + ppb_wctr(ppbus, H_AUTO | H_SELIN | H_INIT | H_STROBE); if (((long) buffer | size) & 0x03) - ppb_outsb_epp(&vpo->vpo_dev, + ppb_outsb_epp(ppbus, buffer, size); else - ppb_outsl_epp(&vpo->vpo_dev, + ppb_outsl_epp(ppbus, buffer, size/4); - if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) { + if ((ppb_rstr(ppbus) & TIMEOUT)) { error = VP0_EPPDATA_TIMEOUT; goto error; } - ppb_wctr(&vpo->vpo_dev, - H_AUTO | H_nSELIN | H_INIT | H_STROBE); + ppb_wctr(ppbus, H_AUTO | H_nSELIN | H_INIT | H_STROBE); } #endif - ppb_ecp_sync(&vpo->vpo_dev); + ppb_ecp_sync(ppbus); return (error); } @@ -457,36 +465,37 @@ vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size) static int vpoio_instr(struct vpoio_data *vpo, char *buffer, int size) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int error = 0; - ppb_MS_exec(&vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer, + ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer, (union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error); #if 0 /* XXX EPP 1.9 not implemented with microsequences */ else { - ppb_reset_epp_timeout(&vpo->vpo_dev); - ppb_wctr(&vpo->vpo_dev, PCD | + ppb_reset_epp_timeout(ppbus); + ppb_wctr(ppbus, PCD | H_AUTO | H_SELIN | H_INIT | H_STROBE); if (((long) buffer | size) & 0x03) - ppb_insb_epp(&vpo->vpo_dev, + ppb_insb_epp(ppbus, buffer, size); else - ppb_insl_epp(&vpo->vpo_dev, + ppb_insl_epp(ppbus, buffer, size/4); - if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) { + if ((ppb_rstr(ppbus) & TIMEOUT)) { error = VP0_EPPDATA_TIMEOUT; goto error; } - ppb_wctr(&vpo->vpo_dev, PCD | + ppb_wctr(ppbus, PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE); } #endif - ppb_ecp_sync(&vpo->vpo_dev); + ppb_ecp_sync(ppbus); return (error); } @@ -494,6 +503,7 @@ vpoio_instr(struct vpoio_data *vpo, char *buffer, int size) static char vpoio_select(struct vpoio_data *vpo, int initiator, int target) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; struct ppb_microseq select_microseq[] = { @@ -523,7 +533,7 @@ vpoio_select(struct vpoio_data *vpo, int initiator, int target) SELECT_TARGET, 1 << target, SELECT_INITIATOR, 1 << initiator); - ppb_MS_microseq(&vpo->vpo_dev, select_microseq, &ret); + ppb_MS_microseq(ppbus, vpo->vpo_dev, select_microseq, &ret); if (ret) return (VP0_ESELECT_TIMEOUT); @@ -541,20 +551,20 @@ vpoio_select(struct vpoio_data *vpo, int initiator, int target) static char vpoio_wait(struct vpoio_data *vpo, int tmo) { - + device_t ppbus = device_get_parent(vpo->vpo_dev); register int k; register char r; #if 0 /* broken */ - if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR)) + if (ppb_poll_device(ppbus, 150, nBUSY, nBUSY, PPB_INTR)) return (0); - return (ppb_rstr(&vpo->vpo_dev) & 0xf0); + return (ppb_rstr(ppbus) & 0xf0); #endif /* XXX should be ported to microseq */ k = 0; - while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo)) + while (!((r = ppb_rstr(ppbus)) & nBUSY) && (k++ < tmo)) ; /* @@ -576,14 +586,13 @@ vpoio_wait(struct vpoio_data *vpo, int tmo) * Low level probe of vpo device * */ -struct ppb_device * -vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo) +int +vpoio_probe(device_t dev, struct vpoio_data *vpo) { + int error; /* ppbus dependent initialisation */ - vpo->vpo_dev.id_unit = vpo->vpo_unit; - vpo->vpo_dev.name = "vpo"; - vpo->vpo_dev.ppb = ppb; + vpo->vpo_dev = dev; /* * Initialize microsequence code @@ -591,11 +600,11 @@ vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo) INIT_TRIG_MICROSEQ; /* now, try to initialise the drive */ - if (vpoio_detect(vpo)) { - return (NULL); + if ((error = vpoio_detect(vpo))) { + return (error); } - return (&vpo->vpo_dev); + return (0); } /* @@ -607,19 +616,14 @@ vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo) int vpoio_attach(struct vpoio_data *vpo) { + device_t ppbus = device_get_parent(vpo->vpo_dev); int epp; - /* - * Report ourselves - */ - printf("vpo%d: <Iomega VPI0 Parallel to SCSI interface> on ppbus %d\n", - vpo->vpo_dev.id_unit, vpo->vpo_dev.ppb->ppb_link->adapter_unit); - vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc( sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT); if (!vpo->vpo_nibble_inbyte_msq) - return (0); + return (ENXIO); bcopy((void *)nibble_inbyte_submicroseq, (void *)vpo->vpo_nibble_inbyte_msq, @@ -630,36 +634,36 @@ vpoio_attach(struct vpoio_data *vpo) /* * Initialize mode dependent in/out microsequences */ - ppb_request_bus(&vpo->vpo_dev, PPB_WAIT); + ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT); /* enter NIBBLE mode to configure submsq */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) { + if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) { - ppb_MS_GET_init(&vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq); + ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq); - ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq); + ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq); } /* enter PS2 mode to configure submsq */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) { + if (ppb_set_mode(ppbus, PPB_PS2) != -1) { - ppb_MS_GET_init(&vpo->vpo_dev, ps2_inbyte_submicroseq); + ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq); - ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq); + ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq); } - epp = ppb_get_epp_protocol(&vpo->vpo_dev); + epp = ppb_get_epp_protocol(ppbus); /* enter EPP mode to configure submsq */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) { + if (ppb_set_mode(ppbus, PPB_EPP) != -1) { switch (epp) { case EPP_1_9: /* XXX EPP 1.9 support should be improved */ case EPP_1_7: - ppb_MS_GET_init(&vpo->vpo_dev, epp17_instr_body); + ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr_body); - ppb_MS_PUT_init(&vpo->vpo_dev, epp17_outstr_body); + ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr_body); break; default: panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__, @@ -668,7 +672,7 @@ vpoio_attach(struct vpoio_data *vpo) } /* try to enter EPP or PS/2 mode, NIBBLE otherwise */ - if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) { + if (ppb_set_mode(ppbus, PPB_EPP) != -1) { switch (epp) { case EPP_1_9: printf("vpo%d: EPP 1.9 mode\n", vpo->vpo_unit); @@ -680,25 +684,25 @@ vpoio_attach(struct vpoio_data *vpo) panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__, epp); } - } else if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) + } else if (ppb_set_mode(ppbus, PPB_PS2) != -1) printf("vpo%d: PS2 mode\n", vpo->vpo_unit); - else if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) + else if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) printf("vpo%d: NIBBLE mode\n", vpo->vpo_unit); else { printf("vpo%d: can't enter NIBBLE, PS2 or EPP mode\n", vpo->vpo_unit); - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF); - return (0); + return (ENXIO); } - ppb_release_bus(&vpo->vpo_dev); + ppb_release_bus(ppbus, vpo->vpo_dev); - return (1); + return (0); } /* @@ -739,7 +743,7 @@ vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, int clen, char *buffer, int blen, int *result, int *count, int *ret) { - + device_t ppbus = device_get_parent(vpo->vpo_dev); register char r; char l, h = 0; int len, error = 0; @@ -768,7 +772,7 @@ vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, * * set H_SELIN low for vpoio_wait(). */ - ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); + ppb_wctr(ppbus, H_AUTO | H_nSELIN | H_INIT | H_STROBE); for (k = 0; k < clen; k++) { if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) { @@ -804,7 +808,7 @@ vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, /* if in EPP mode or writing bytes, try to transfer a sector * otherwise, just send one byte */ - if (PPB_IN_EPP_MODE(&vpo->vpo_dev) || r == (char)0xc0) + if (PPB_IN_EPP_MODE(ppbus) || r == (char)0xc0) len = (((blen - *count) >= VP0_SECTOR_SIZE)) ? VP0_SECTOR_SIZE : 1; else diff --git a/sys/dev/ppbus/vpoio.h b/sys/dev/ppbus/vpoio.h index e007d3e..211ca00 100644 --- a/sys/dev/ppbus/vpoio.h +++ b/sys/dev/ppbus/vpoio.h @@ -67,12 +67,12 @@ struct vpoio_data { /* each device must have its own nibble inbyte microsequence */ struct ppb_microseq *vpo_nibble_inbyte_msq; - struct ppb_device vpo_dev; + device_t vpo_dev; }; #define vpoio_set_unit(vpo,unit) ((vpo)->vpo_unit = unit) -struct ppb_device *vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo); +int vpoio_probe(device_t dev, struct vpoio_data *vpo); int vpoio_attach(struct vpoio_data *vpo); int vpoio_reset_bus(struct vpoio_data *vpo); @@ -81,7 +81,7 @@ int vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command, int clen, char *buffer, int blen, int *result, int *count, int *ret); -struct ppb_device *imm_probe(struct ppb_data *ppb, struct vpoio_data *vpo); +int imm_probe(device_t dev, struct vpoio_data *vpo); int imm_attach(struct vpoio_data *vpo); int imm_reset_bus(struct vpoio_data *vpo); diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c index 436caeb..0ee1eb6 100644 --- a/sys/dev/ppc/ppc.c +++ b/sys/dev/ppc/ppc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu + * Copyright (c) 1997-2000 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,42 +30,90 @@ #if NPPC > 0 +#include "opt_ppc.h" + #include <sys/param.h> #include <sys/systm.h> -#include <sys/conf.h> -#include <sys/malloc.h> #include <sys/kernel.h> - -#include <machine/clock.h> - +#include <sys/bus.h> +#include <sys/malloc.h> + #include <vm/vm.h> -#include <vm/vm_param.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 <i386/isa/isa_device.h> -#include <i386/isa/isa.h> +#include <isa/isareg.h> +#include <isa/isavar.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> #include <i386/isa/ppcreg.h> -#include "opt_ppc.h" +#include "ppbus_if.h" #define LOG_PPC(function, ppc, string) \ if (bootverbose) printf("%s: %s\n", function, string) -static int ppcprobe(struct isa_device *); -static int ppcattach(struct isa_device *); -struct isa_driver ppcdriver = { - ppcprobe, ppcattach, "ppc" +#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) + +devclass_t ppc_devclass; + +static int ppc_probe(device_t dev); +static int ppc_attach(device_t dev); +static int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val); + +static void ppc_reset_epp(device_t); +static void ppc_ecp_sync(device_t); +static void ppcintr(void *arg); + +static int ppc_exec_microseq(device_t, struct ppb_microseq **); +static int ppc_setmode(device_t, int); + +static int ppc_read(device_t, char *, int, int); +static int ppc_write(device_t, char *, int, int); + +static u_char ppc_io(device_t, int, u_char *, int, u_char); + +static int ppc_setup_intr(device_t, device_t, struct resource *, int, + void (*)(void *), void *, void **); +static int ppc_teardown_intr(device_t, device_t, struct resource *, void *); + +static device_method_t ppc_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppc_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 struct ppc_data *ppcdata[NPPC]; -static int nppc = 0; - -static char *ppc_types[] = { + +static char *ppc_models[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 }; @@ -98,91 +146,13 @@ static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; #define BIOS_MAX_PPC 4 /* - * All these functions are default actions for IN/OUT operations. - * They may be redefined if needed. - */ -static void ppc_outsb_epp(int unit, char *addr, int cnt) { - outsb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsw_epp(int unit, char *addr, int cnt) { - outsw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsl_epp(int unit, char *addr, int cnt) { - outsl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insb_epp(int unit, char *addr, int cnt) { - insb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insw_epp(int unit, char *addr, int cnt) { - insw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insl_epp(int unit, char *addr, int cnt) { - insl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } - -static u_char ppc_rdtr(int unit) { return r_dtr(ppcdata[unit]); } -static u_char ppc_rstr(int unit) { return r_str(ppcdata[unit]); } -static u_char ppc_rctr(int unit) { return r_ctr(ppcdata[unit]); } -static u_char ppc_repp_A(int unit) { return r_epp_A(ppcdata[unit]); } -static u_char ppc_repp_D(int unit) { return r_epp_D(ppcdata[unit]); } -static u_char ppc_recr(int unit) { return r_ecr(ppcdata[unit]); } -static u_char ppc_rfifo(int unit) { return r_fifo(ppcdata[unit]); } - -static void ppc_wdtr(int unit, char byte) { w_dtr(ppcdata[unit], byte); } -static void ppc_wstr(int unit, char byte) { w_str(ppcdata[unit], byte); } -static void ppc_wctr(int unit, char byte) { w_ctr(ppcdata[unit], byte); } -static void ppc_wepp_A(int unit, char byte) { w_epp_A(ppcdata[unit], byte); } -static void ppc_wepp_D(int unit, char byte) { w_epp_D(ppcdata[unit], byte); } -static void ppc_wecr(int unit, char byte) { w_ecr(ppcdata[unit], byte); } -static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); } - -static void ppc_reset_epp_timeout(int); -static void ppc_ecp_sync(int); -static ointhand2_t ppcintr; - -static int ppc_exec_microseq(int, struct ppb_microseq **); -static int ppc_generic_setmode(int, int); -static int ppc_smclike_setmode(int, int); - -static int ppc_read(int, char *, int, int); -static int ppc_write(int, char *, int, int); - -static struct ppb_adapter ppc_smclike_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_smclike_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp_A, ppc_repp_D, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp_A, ppc_wepp_D, ppc_wecr, ppc_wfifo -}; - -static struct ppb_adapter ppc_generic_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_generic_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp_A, ppc_repp_D, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp_A, ppc_wepp_D, ppc_wecr, ppc_wfifo -}; - -/* * ppc_ecp_sync() XXX */ static void -ppc_ecp_sync(int unit) { +ppc_ecp_sync(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; int i, r; + struct ppc_data *ppc = DEVTOSOFTC(dev); if (!(ppc->ppc_avm & PPB_ECP)) return; @@ -199,7 +169,7 @@ ppc_ecp_sync(int unit) { } printf("ppc%d: ECP sync failed as data still " \ - "present in FIFO.\n", unit); + "present in FIFO.\n", ppc->ppc_unit); return; } @@ -328,6 +298,121 @@ ppc_detect_port(struct ppc_data *ppc) } /* + * 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) { + /* 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) { + /* 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. @@ -381,11 +466,11 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for outb(idport, PC873_SID); val = inb(idport + 1); if ((val & 0xf0) == 0x10) { - ppc->ppc_type = NS_PC87332; + ppc->ppc_model = NS_PC87332; } else if ((val & 0xf8) == 0x70) { - ppc->ppc_type = NS_PC87306; + ppc->ppc_model = NS_PC87306; } else if ((val & 0xf8) == 0x50) { - ppc->ppc_type = NS_PC87334; + ppc->ppc_model = NS_PC87334; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); @@ -484,7 +569,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for else ppc->ppc_epp = EPP_1_7; - if ((ppc->ppc_type == NS_PC87332) && bootverbose) { + if ((ppc->ppc_model == NS_PC87332) && bootverbose) { outb(idport, PC873_PTR); ptr = inb(idport + 1); if (ptr & PC873_EPPRDIR) @@ -539,7 +624,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for printf(", EPP1.9"); /* enable automatic direction turnover */ - if (ppc->ppc_type == NS_PC87332) { + if (ppc->ppc_model == NS_PC87332) { outb(idport, PC873_PTR); ptr = inb(idport + 1); ptr &= ~PC873_EPPRDIR; @@ -581,22 +666,14 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for if (bootverbose) printf("\n"); - ppc->ppc_link.adapter = &ppc_generic_adapter; - ppc_generic_setmode(ppc->ppc_unit, chipset_mode); + ppc->ppc_type = PPC_TYPE_GENERIC; + ppc_generic_setmode(ppc, chipset_mode); return(chipset_mode); } return(-1); } -static int -ppc_check_epp_timeout(struct ppc_data *ppc) -{ - ppc_reset_epp_timeout(ppc->ppc_unit); - - return (!(r_str(ppc) & TIMEOUT)); -} - /* * ppc_smc37c66xgt_detect * @@ -661,7 +738,7 @@ config: if (port_address[(int)r] != ppc->ppc_base) return (-1); - ppc->ppc_type = type; + ppc->ppc_model = type; /* * CR1 and CR4 registers bits 3 and 0/1 for mode configuration @@ -800,8 +877,8 @@ end_detect: /* end config mode */ outb(csr, 0xaa); - ppc->ppc_link.adapter = &ppc_smclike_adapter; - ppc_smclike_setmode(ppc->ppc_unit, chipset_mode); + ppc->ppc_type = PPC_TYPE_SMCLIKE; + ppc_smclike_setmode(ppc, chipset_mode); return (chipset_mode); } @@ -866,15 +943,15 @@ found: switch (inb(efdr) & WINB_CHIPID) { case WINB_W83877F_ID: - ppc->ppc_type = WINB_W83877F; + ppc->ppc_model = WINB_W83877F; break; case WINB_W83877AF_ID: - ppc->ppc_type = WINB_W83877AF; + ppc->ppc_model = WINB_W83877AF; break; default: - ppc->ppc_type = WINB_UNKNOWN; + ppc->ppc_model = WINB_UNKNOWN; } if (bootverbose) { @@ -898,7 +975,7 @@ found: printf("ppc%d:", ppc->ppc_unit); } - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; if (!chipset_mode) { /* autodetect mode */ @@ -940,7 +1017,7 @@ found: case (WINB_PARALLEL | WINB_ECP_EPP): ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP SPP"); @@ -966,7 +1043,7 @@ found: if (bootverbose) printf(" ECP+EPP"); - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_type = PPC_TYPE_SMCLIKE; } else { outb(efdr, inb(efdr) | WINB_ECP); @@ -988,10 +1065,18 @@ found: /* exit configuration mode */ outb(efer, 0xaa); - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); + 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 @@ -1000,7 +1085,7 @@ static int ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) { /* default to generic */ - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; if (bootverbose) printf("ppc%d:", ppc->ppc_unit); @@ -1023,8 +1108,8 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) if (ppc->ppc_avm & PPB_ECP) { /* SMC like chipset found */ - ppc->ppc_type = SMC_LIKE; - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_model = SMC_LIKE; + ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP"); @@ -1050,7 +1135,14 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) if (bootverbose) printf("\n"); - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); + 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); } @@ -1063,6 +1155,7 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) static int ppc_detect(struct ppc_data *ppc, int chipset_mode) { +#ifdef PPC_PROBE_CHIPSET int i, mode; /* list of supported chipsets */ @@ -1073,6 +1166,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { 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) @@ -1081,6 +1175,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { /* 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 * @@ -1089,9 +1184,11 @@ ppc_detect(struct ppc_data *ppc, int chipset_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) { @@ -1100,6 +1197,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { } } } +#endif /* configure/detect ECP FIFO */ if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) @@ -1115,9 +1213,9 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { * Microsequence mechanism is supposed to handle fast I/O operations. */ static int -ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) +ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) { - struct ppc_data *ppc = ppcdata[unit]; + struct ppc_data *ppc = DEVTOSOFTC(dev); struct ppb_microseq *mi; char cc, *p; int i, iter, len; @@ -1326,9 +1424,10 @@ ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) } static void -ppcintr(int unit) +ppcintr(void *arg) { - struct ppc_data *ppc = ppcdata[unit]; + 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); @@ -1341,8 +1440,6 @@ ppcintr(int unit) /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { - /* call upper code */ - ppb_intr(&ppc->ppc_link); return; } @@ -1356,8 +1453,7 @@ ppcintr(int unit) w_ecr(ppc, ecr | PPC_nFAULT_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { - /* call upper code */ - ppb_intr(&ppc->ppc_link); + /* shall be handled by underlying layers XXX */ return; } } @@ -1397,14 +1493,13 @@ ppcintr(int unit) /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; - } return; } static int -ppc_read(int unit, char *buf, int len, int mode) +ppc_read(device_t dev, char *buf, int len, int mode) { return (EINVAL); } @@ -1417,9 +1512,9 @@ ppc_read(int unit, char *buf, int len, int mode) * EINVAL is returned */ static int -ppc_write(int unit, char *buf, int len, int how) +ppc_write(device_t dev, char *buf, int len, int how) { - struct ppc_data *ppc = ppcdata[unit]; + struct ppc_data *ppc = DEVTOSOFTC(dev); char ecr, ecr_sav, ctr, ctr_sav; int s, error = 0; int spin; @@ -1434,7 +1529,7 @@ ppc_write(int unit, char *buf, int len, int how) /* * Send buffer with DMA, FIFO and interrupts */ - if (ppc->ppc_avm & PPB_ECP) { + if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) { if (ppc->ppc_dmachan >= 0) { @@ -1568,231 +1663,334 @@ error: return (error); } -/* - * Configure current operating mode - */ -static int -ppc_generic_setmode(int unit, int mode) +static void +ppc_reset_epp(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; - u_char ecr = 0; + struct ppc_data *ppc = DEVTOSOFTC(dev); + + ppc_reset_epp_timeout(ppc); - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); + return; +} - /* if ECP mode, configure ecr register */ - if (ppc->ppc_avm & 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; +static int +ppc_setmode(device_t dev, int mode) +{ + struct ppc_data *ppc = DEVTOSOFTC(dev); - 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; + switch (ppc->ppc_type) { + case PPC_TYPE_SMCLIKE: + return (ppc_smclike_setmode(ppc, mode)); + break; - w_ecr(ppc, ecr); + case PPC_TYPE_GENERIC: + default: + return (ppc_generic_setmode(ppc, mode)); + break; } - ppc->ppc_mode = mode; - - return (0); + /* not reached */ + return (ENXIO); } -/* - * 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. - */ -int -ppc_smclike_setmode(int unit, int mode) +static int +ppc_probe(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; - 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) { - /* 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; + static short next_bios_ppc = 0; + struct ppc_data *ppc; + device_t parent; + int port; - 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; + device_set_desc(dev, "Parallel port"); - w_ecr(ppc, ecr); - } + /* XXX shall be connected to pnpbios - from Peter Wemm */ + if (isa_get_logicalid(dev)) + return ENXIO; - ppc->ppc_mode = mode; + parent = device_get_parent(dev); - return (0); -} - -/* - * 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(int unit) -{ - struct ppc_data *ppc = ppcdata[unit]; - register char r; + /* + * Allocate the ppc_data structure. + */ + ppc = DEVTOSOFTC(dev); + bzero(ppc, sizeof(struct ppc_data)); - r = r_str(ppc); - w_str(ppc, r | 0x1); - w_str(ppc, r & 0xfe); + ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0; + ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0; - return; -} - -static int -ppcprobe(struct isa_device *dvp) -{ - static short next_bios_ppc = 0; - struct ppc_data *ppc; + /* retrieve ISA parameters */ + BUS_READ_IVAR(parent, dev, ISA_IVAR_PORT, &port); /* * If port not specified, use bios list. */ - if(dvp->id_iobase < 0) { + if (port < 0) { if((next_bios_ppc < BIOS_MAX_PPC) && (*(BIOS_PORTS+next_bios_ppc) != 0) ) { - dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++); + port = *(BIOS_PORTS+next_bios_ppc++); if (bootverbose) - printf("ppc: parallel port found at 0x%x\n", - dvp->id_iobase); - } else - return (0); + device_printf(dev, "parallel port found at 0x%x\n", + port); + } else { + device_printf(dev, "parallel port not found.\n"); + return ENXIO; + } } - - /* - * Port was explicitly specified. - * This allows probing of ports unknown to the BIOS. - */ - - /* - * Allocate the ppc_data structure. - */ - ppc = malloc(sizeof(struct ppc_data), M_DEVBUF, M_NOWAIT); - if (!ppc) { - printf("ppc: cannot malloc!\n"); + ppc->ppc_base = port; + + /* IO port is mandatory */ + ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, + &ppc->rid_ioport, port, port, + IO_LPTSIZE, RF_ACTIVE); + if (ppc->res_ioport == 0) { + device_printf(dev, "cannot reserve I/O port range\n"); goto error; } - bzero(ppc, sizeof(struct ppc_data)); - ppc->ppc_base = dvp->id_iobase; - ppc->ppc_unit = dvp->id_unit; - ppc->ppc_type = GENERIC; + ppc->ppc_flags = device_get_flags(dev); - /* store boot flags */ - ppc->ppc_flags = dvp->id_flags; + if (!(ppc->ppc_flags & 0x20)) { + ppc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ppc->rid_irq, + 0ul, ~0ul, 1, RF_SHAREABLE); + ppc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ, &ppc->rid_drq, + 0ul, ~0ul, 1, RF_ACTIVE); + } - ppc->ppc_mode = PPB_COMPATIBLE; - ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; + if (ppc->res_irq) + BUS_READ_IVAR(parent, dev, ISA_IVAR_IRQ, &ppc->ppc_irq); + if (ppc->res_drq) + BUS_READ_IVAR(parent, dev, ISA_IVAR_DRQ, &ppc->ppc_dmachan); - /* - * XXX Try and detect if interrupts are working - */ - if (!(dvp->id_flags & 0x20) && dvp->id_irq) - ppc->ppc_irq = ffs(dvp->id_irq) - 1; + ppc->ppc_unit = device_get_unit(dev); + ppc->ppc_model = GENERIC; - ppc->ppc_dmachan = dvp->id_drq; + ppc->ppc_mode = PPB_COMPATIBLE; + ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; - ppcdata[ppc->ppc_unit] = ppc; - nppc ++; - - /* - * Link the Parallel Port Chipset (adapter) to - * the future ppbus. Default to a generic chipset - */ - ppc->ppc_link.adapter_unit = ppc->ppc_unit; - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; /* * Try to detect the chipset and its mode. */ - if (ppc_detect(ppc, dvp->id_flags & 0xf)) + if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) goto error; - return (IO_LPTSIZE); + return (0); error: - return (0); + 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); } static int -ppcattach(struct isa_device *isdp) +ppc_attach(device_t dev) { - struct ppc_data *ppc = ppcdata[isdp->id_unit]; - struct ppb_data *ppbus; + struct ppc_data *ppc = DEVTOSOFTC(dev); - printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit, - ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm], - ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? - ppc_epp_protocol[ppc->ppc_epp] : ""); + device_t ppbus; + device_t parent = device_get_parent(dev); + 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) - printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n", - ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr, - ppc->ppc_rthr); + device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", + ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); - isdp->id_ointr = ppcintr; + 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); /* - * Prepare ppbus data area for upper level code. + * Probe the ppbus and attach devices found. */ - ppbus = ppb_alloc_bus(); + device_probe_and_attach(ppbus); - if (!ppbus) - return (0); + /* register the ppc interrupt handler as default */ + if (ppc->res_irq) { + /* default to the tty mask for registration */ /* XXX */ + if (BUS_SETUP_INTR(parent, dev, ppc->res_irq, INTR_TYPE_TTY, + ppcintr, dev, &ppc->intr_cookie) == 0) { - ppc->ppc_link.ppbus = ppbus; - ppbus->ppb_link = &ppc->ppc_link; + /* remember the ppcintr is registered */ + ppc->ppc_registered = 1; + } + } - if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { + return (0); +} - /* acquire the DMA channel forever */ - isa_dma_acquire(ppc->ppc_dmachan); - isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ +static 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: + outsb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_OUTSW_EPP: + outsw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_OUTSL_EPP: + outsl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSB_EPP: + insb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSW_EPP: + insw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSL_EPP: + insl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_RDTR: + return (r_dtr(ppc)); + break; + case PPB_RSTR: + return (r_str(ppc)); + break; + case PPB_RCTR: + return (r_ctr(ppc)); + break; + case PPB_REPP_A: + return (r_epp_A(ppc)); + break; + case PPB_REPP_D: + return (r_epp_D(ppc)); + break; + case PPB_RECR: + return (r_ecr(ppc)); + break; + case PPB_RFIFO: + return (r_fifo(ppc)); + break; + 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", __FUNCTION__); + break; } - /* - * Probe the ppbus and attach devices found. - */ - ppb_attachdevs(ppbus); + return (0); /* not significative */ +} - return (1); +static 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: + BUS_READ_IVAR(device_get_parent(bus), bus, ISA_IVAR_IRQ, val); + 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 + */ +static 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 + */ +static 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); #endif diff --git a/sys/dev/ppc/ppcreg.h b/sys/dev/ppc/ppcreg.h index faecb97..ec17806 100644 --- a/sys/dev/ppc/ppcreg.h +++ b/sys/dev/ppc/ppcreg.h @@ -45,12 +45,19 @@ #define NS_PC87334 10 /* + * 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_type; + 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 */ @@ -83,16 +90,22 @@ struct ppc_data { short ppc_wthr; /* writeIntrThresold */ short ppc_rthr; /* readIntrThresold */ -#define ppc_base ppc_link.base -#define ppc_epp ppc_link.epp_protocol -#define ppc_irq ppc_link.id_irq -#define ppc_subm ppc_link.submicroseq -#define ppc_ptr ppc_link.ptr -#define ppc_accum ppc_link.accum + 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; - struct ppb_link ppc_link; + device_t ppbus; /* parallel port chipset corresponding ppbus */ + + int rid_irq, rid_drq, rid_ioport; + struct resource *res_irq, *res_drq, *res_ioport; + + void *intr_cookie; + + int ppc_registered; /* 1 if ppcintr() is the registered interrupt */ }; /* diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index a651ccb..3a284bd 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -2131,6 +2131,8 @@ pseudo-device "i4bisppp" 4 # ppc ISA-bus parallel port interfaces. # +options PPC_PROBE_CHIPSET # Enable chipset specific detection + # (see flags in ppc(4)) options DEBUG_1284 # IEEE1284 signaling protocol debug options PERIPH_1284 # Makes your computer act as a IEEE1284 # compliant peripheral diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index a651ccb..3a284bd 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -2131,6 +2131,8 @@ pseudo-device "i4bisppp" 4 # ppc ISA-bus parallel port interfaces. # +options PPC_PROBE_CHIPSET # Enable chipset specific detection + # (see flags in ppc(4)) options DEBUG_1284 # IEEE1284 signaling protocol debug options PERIPH_1284 # Makes your computer act as a IEEE1284 # compliant peripheral diff --git a/sys/i386/isa/isa_compat.h b/sys/i386/isa/isa_compat.h index c504b52..98bf519 100644 --- a/sys/i386/isa/isa_compat.h +++ b/sys/i386/isa/isa_compat.h @@ -77,9 +77,7 @@ #include "stl.h" #include "stli.h" #include "loran.h" -#include "pcf.h" #include "tina.h" -#include "ppc.h" #include "fla.h" struct old_isa_driver { @@ -138,9 +136,7 @@ extern struct isa_driver ascdriver; extern struct isa_driver stldriver; extern struct isa_driver stlidriver; extern struct isa_driver lorandriver; -extern struct isa_driver pcfdriver; extern struct isa_driver tinadriver; -extern struct isa_driver ppcdriver; static struct old_isa_driver old_drivers[] = { @@ -212,9 +208,6 @@ static struct old_isa_driver old_drivers[] = { #if NLORAN > 0 { INTR_TYPE_TTY, &lorandriver }, #endif -#if NPPC > 0 - { INTR_TYPE_TTY, &ppcdriver }, -#endif /* BIO */ @@ -263,9 +256,6 @@ static struct old_isa_driver old_drivers[] = { #if NWL > 0 { INTR_TYPE_NET, &wldriver }, #endif -#if NPCF > 0 - { INTR_TYPE_NET, &pcfdriver }, -#endif #if NTINA > 0 { INTR_TYPE_NET, &tinadriver }, #endif diff --git a/sys/i386/isa/pcf.c b/sys/i386/isa/pcf.c index 1aeb7e6..e37823e 100644 --- a/sys/i386/isa/pcf.c +++ b/sys/i386/isa/pcf.c @@ -34,12 +34,20 @@ #include <sys/malloc.h> #include <machine/clock.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <isa/isareg.h> +#include <isa/isavar.h> #include <i386/isa/isa_device.h> #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" +#define IO_PCFSIZE 2 + #define TIMEOUT 9999 /* XXX */ /* Status bits of S1 register (read only) */ @@ -71,37 +79,23 @@ struct pcf_softc { int pcf_base; /* isa port */ + int pcf_flags; u_char pcf_addr; /* interface I2C address */ int pcf_slave_mode; /* receiver or transmitter */ int pcf_started; /* 1 if start condition sent */ device_t iicbus; /* the corresponding iicbus */ -}; - -struct pcf_isa_softc { - - int pcf_unit; /* unit of the isa device */ - int pcf_base; /* isa port */ - int pcf_irq; /* isa irq or null if polled */ - - unsigned int pcf_flags; /* boot flags */ -}; - -#define MAXPCF 2 - -static struct pcf_isa_softc *pcfdata[MAXPCF]; -static int npcf = 0; - -static int pcfprobe_isa(struct isa_device *); -static int pcfattach_isa(struct isa_device *); -struct isa_driver pcfdriver = { - pcfprobe_isa, pcfattach_isa, "pcf" + int rid_irq, rid_ioport; + struct resource *res_irq, *res_ioport; + void *intr_cookie; }; static int pcf_probe(device_t); static int pcf_attach(device_t); +static void pcfintr(void *arg); + static int pcf_print_child(device_t, device_t); static int pcf_repeated_start(device_t, u_char, int); @@ -109,7 +103,6 @@ static int pcf_start(device_t, u_char, int); static int pcf_stop(device_t); static int pcf_write(device_t, char *, int, int *, int); static int pcf_read(device_t, char *, int, int *, int, int); -static ointhand2_t pcfintr; static int pcf_rst_card(device_t, u_char, u_char, u_char *); static device_method_t pcf_methods[] = { @@ -143,72 +136,68 @@ static devclass_t pcf_devclass; #define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) static int -pcfprobe_isa(struct isa_device *dvp) +pcf_probe(device_t pcfdev) { - device_t pcfdev; - struct pcf_isa_softc *pcf; - - if (npcf >= MAXPCF) - return (0); - - if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc), - M_DEVBUF, M_NOWAIT)) == NULL) - return (0); - - pcf->pcf_base = dvp->id_iobase; /* XXX should be ivars */ - pcf->pcf_unit = dvp->id_unit; + struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); + device_t parent = device_get_parent(pcfdev); - if (!(dvp->id_flags & IIC_POLLED)) - pcf->pcf_irq = (dvp->id_irq); + device_set_desc(pcfdev, "PCF8584 I2C bus controller"); - pcfdata[npcf++] = pcf; + pcf = DEVTOSOFTC(pcfdev); + bzero(pcf, sizeof(struct pcf_softc)); - /* XXX add the pcf device to the root_bus until isa bus exists */ - pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit); + pcf->rid_irq = pcf->rid_ioport = 0; + pcf->res_irq = pcf->res_ioport = 0; - if (!pcfdev) + /* IO port is mandatory */ + pcf->res_ioport = bus_alloc_resource(pcfdev, SYS_RES_IOPORT, + &pcf->rid_ioport, 0ul, ~0ul, + IO_PCFSIZE, RF_ACTIVE); + if (pcf->res_ioport == 0) { + device_printf(pcfdev, "cannot reserve I/O port range\n"); goto error; + } + BUS_READ_IVAR(parent, pcfdev, ISA_IVAR_PORT, &pcf->pcf_base); - return (1); - -error: - free(pcf, M_DEVBUF); - return (0); -} - -static int -pcfattach_isa(struct isa_device *isdp) -{ - isdp->id_ointr = pcfintr; - return (1); /* ok */ -} + pcf->pcf_flags = device_get_flags(pcfdev); -static int -pcf_probe(device_t pcfdev) -{ - struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); - int unit = device_get_unit(pcfdev); - - /* retrieve base address from isa initialization - * - * XXX should use ivars with isabus - */ - pcf->pcf_base = pcfdata[unit]->pcf_base; + if (!(pcf->pcf_flags & IIC_POLLED)) { + pcf->res_irq = bus_alloc_resource(pcfdev, SYS_RES_IRQ, &pcf->rid_irq, + 0ul, ~0ul, 1, RF_ACTIVE); + if (pcf->res_irq == 0) { + device_printf(pcfdev, "can't reserve irq, polled mode.\n"); + pcf->pcf_flags |= IIC_POLLED; + } + } /* reset the chip */ pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); - /* XXX try do detect chipset */ - - device_set_desc(pcfdev, "PCF8584 I2C bus controller"); - return (0); +error: + if (pcf->res_ioport != 0) { + bus_deactivate_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport, + pcf->res_ioport); + bus_release_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport, + pcf->res_ioport); + } + return (ENXIO); } static int pcf_attach(device_t pcfdev) { - struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); + struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); + device_t parent = device_get_parent(pcfdev); + int error = 0; + + if (pcf->res_irq) { + /* default to the tty mask for registration */ /* XXX */ + error = BUS_SETUP_INTR(parent, pcfdev, pcf->res_irq, INTR_TYPE_NET, + pcfintr, pcfdev, &pcf->intr_cookie); + if (error) + return (error); + } pcf->iicbus = iicbus_alloc_bus(pcfdev); @@ -392,10 +381,10 @@ error: } static void -pcfintr(unit) +pcfintr(void *arg) { - struct pcf_softc *pcf = - (struct pcf_softc *)devclass_get_softc(pcf_devclass, unit); + device_t pcfdev = (device_t)arg; + struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); char data, status, addr; char error = 0; @@ -403,14 +392,13 @@ pcfintr(unit) status = PCF_GET_S1(pcf); if (status & PIN) { - printf("pcf%d: spurious interrupt, status=0x%x\n", unit, - status & 0xff); + device_printf(pcfdev, "spurious interrupt, status=0x%x\n", status & 0xff); goto error; } if (status & LAB) - printf("pcf%d: bus arbitration lost!\n", unit); + device_printf(pcfdev, "bus arbitration lost!\n"); if (status & BER) { error = IIC_EBUSERR; @@ -643,4 +631,4 @@ error: return (error); } -DRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0); +DRIVER_MODULE(pcf, isa, pcf_driver, pcf_devclass, 0, 0); diff --git a/sys/i386/isa/ppc.c b/sys/i386/isa/ppc.c index 436caeb..0ee1eb6 100644 --- a/sys/i386/isa/ppc.c +++ b/sys/i386/isa/ppc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu + * Copyright (c) 1997-2000 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,42 +30,90 @@ #if NPPC > 0 +#include "opt_ppc.h" + #include <sys/param.h> #include <sys/systm.h> -#include <sys/conf.h> -#include <sys/malloc.h> #include <sys/kernel.h> - -#include <machine/clock.h> - +#include <sys/bus.h> +#include <sys/malloc.h> + #include <vm/vm.h> -#include <vm/vm_param.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 <i386/isa/isa_device.h> -#include <i386/isa/isa.h> +#include <isa/isareg.h> +#include <isa/isavar.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> #include <i386/isa/ppcreg.h> -#include "opt_ppc.h" +#include "ppbus_if.h" #define LOG_PPC(function, ppc, string) \ if (bootverbose) printf("%s: %s\n", function, string) -static int ppcprobe(struct isa_device *); -static int ppcattach(struct isa_device *); -struct isa_driver ppcdriver = { - ppcprobe, ppcattach, "ppc" +#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) + +devclass_t ppc_devclass; + +static int ppc_probe(device_t dev); +static int ppc_attach(device_t dev); +static int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val); + +static void ppc_reset_epp(device_t); +static void ppc_ecp_sync(device_t); +static void ppcintr(void *arg); + +static int ppc_exec_microseq(device_t, struct ppb_microseq **); +static int ppc_setmode(device_t, int); + +static int ppc_read(device_t, char *, int, int); +static int ppc_write(device_t, char *, int, int); + +static u_char ppc_io(device_t, int, u_char *, int, u_char); + +static int ppc_setup_intr(device_t, device_t, struct resource *, int, + void (*)(void *), void *, void **); +static int ppc_teardown_intr(device_t, device_t, struct resource *, void *); + +static device_method_t ppc_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppc_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 struct ppc_data *ppcdata[NPPC]; -static int nppc = 0; - -static char *ppc_types[] = { + +static char *ppc_models[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 }; @@ -98,91 +146,13 @@ static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; #define BIOS_MAX_PPC 4 /* - * All these functions are default actions for IN/OUT operations. - * They may be redefined if needed. - */ -static void ppc_outsb_epp(int unit, char *addr, int cnt) { - outsb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsw_epp(int unit, char *addr, int cnt) { - outsw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsl_epp(int unit, char *addr, int cnt) { - outsl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insb_epp(int unit, char *addr, int cnt) { - insb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insw_epp(int unit, char *addr, int cnt) { - insw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insl_epp(int unit, char *addr, int cnt) { - insl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } - -static u_char ppc_rdtr(int unit) { return r_dtr(ppcdata[unit]); } -static u_char ppc_rstr(int unit) { return r_str(ppcdata[unit]); } -static u_char ppc_rctr(int unit) { return r_ctr(ppcdata[unit]); } -static u_char ppc_repp_A(int unit) { return r_epp_A(ppcdata[unit]); } -static u_char ppc_repp_D(int unit) { return r_epp_D(ppcdata[unit]); } -static u_char ppc_recr(int unit) { return r_ecr(ppcdata[unit]); } -static u_char ppc_rfifo(int unit) { return r_fifo(ppcdata[unit]); } - -static void ppc_wdtr(int unit, char byte) { w_dtr(ppcdata[unit], byte); } -static void ppc_wstr(int unit, char byte) { w_str(ppcdata[unit], byte); } -static void ppc_wctr(int unit, char byte) { w_ctr(ppcdata[unit], byte); } -static void ppc_wepp_A(int unit, char byte) { w_epp_A(ppcdata[unit], byte); } -static void ppc_wepp_D(int unit, char byte) { w_epp_D(ppcdata[unit], byte); } -static void ppc_wecr(int unit, char byte) { w_ecr(ppcdata[unit], byte); } -static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); } - -static void ppc_reset_epp_timeout(int); -static void ppc_ecp_sync(int); -static ointhand2_t ppcintr; - -static int ppc_exec_microseq(int, struct ppb_microseq **); -static int ppc_generic_setmode(int, int); -static int ppc_smclike_setmode(int, int); - -static int ppc_read(int, char *, int, int); -static int ppc_write(int, char *, int, int); - -static struct ppb_adapter ppc_smclike_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_smclike_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp_A, ppc_repp_D, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp_A, ppc_wepp_D, ppc_wecr, ppc_wfifo -}; - -static struct ppb_adapter ppc_generic_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_generic_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp_A, ppc_repp_D, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp_A, ppc_wepp_D, ppc_wecr, ppc_wfifo -}; - -/* * ppc_ecp_sync() XXX */ static void -ppc_ecp_sync(int unit) { +ppc_ecp_sync(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; int i, r; + struct ppc_data *ppc = DEVTOSOFTC(dev); if (!(ppc->ppc_avm & PPB_ECP)) return; @@ -199,7 +169,7 @@ ppc_ecp_sync(int unit) { } printf("ppc%d: ECP sync failed as data still " \ - "present in FIFO.\n", unit); + "present in FIFO.\n", ppc->ppc_unit); return; } @@ -328,6 +298,121 @@ ppc_detect_port(struct ppc_data *ppc) } /* + * 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) { + /* 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) { + /* 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. @@ -381,11 +466,11 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for outb(idport, PC873_SID); val = inb(idport + 1); if ((val & 0xf0) == 0x10) { - ppc->ppc_type = NS_PC87332; + ppc->ppc_model = NS_PC87332; } else if ((val & 0xf8) == 0x70) { - ppc->ppc_type = NS_PC87306; + ppc->ppc_model = NS_PC87306; } else if ((val & 0xf8) == 0x50) { - ppc->ppc_type = NS_PC87334; + ppc->ppc_model = NS_PC87334; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); @@ -484,7 +569,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for else ppc->ppc_epp = EPP_1_7; - if ((ppc->ppc_type == NS_PC87332) && bootverbose) { + if ((ppc->ppc_model == NS_PC87332) && bootverbose) { outb(idport, PC873_PTR); ptr = inb(idport + 1); if (ptr & PC873_EPPRDIR) @@ -539,7 +624,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for printf(", EPP1.9"); /* enable automatic direction turnover */ - if (ppc->ppc_type == NS_PC87332) { + if (ppc->ppc_model == NS_PC87332) { outb(idport, PC873_PTR); ptr = inb(idport + 1); ptr &= ~PC873_EPPRDIR; @@ -581,22 +666,14 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for if (bootverbose) printf("\n"); - ppc->ppc_link.adapter = &ppc_generic_adapter; - ppc_generic_setmode(ppc->ppc_unit, chipset_mode); + ppc->ppc_type = PPC_TYPE_GENERIC; + ppc_generic_setmode(ppc, chipset_mode); return(chipset_mode); } return(-1); } -static int -ppc_check_epp_timeout(struct ppc_data *ppc) -{ - ppc_reset_epp_timeout(ppc->ppc_unit); - - return (!(r_str(ppc) & TIMEOUT)); -} - /* * ppc_smc37c66xgt_detect * @@ -661,7 +738,7 @@ config: if (port_address[(int)r] != ppc->ppc_base) return (-1); - ppc->ppc_type = type; + ppc->ppc_model = type; /* * CR1 and CR4 registers bits 3 and 0/1 for mode configuration @@ -800,8 +877,8 @@ end_detect: /* end config mode */ outb(csr, 0xaa); - ppc->ppc_link.adapter = &ppc_smclike_adapter; - ppc_smclike_setmode(ppc->ppc_unit, chipset_mode); + ppc->ppc_type = PPC_TYPE_SMCLIKE; + ppc_smclike_setmode(ppc, chipset_mode); return (chipset_mode); } @@ -866,15 +943,15 @@ found: switch (inb(efdr) & WINB_CHIPID) { case WINB_W83877F_ID: - ppc->ppc_type = WINB_W83877F; + ppc->ppc_model = WINB_W83877F; break; case WINB_W83877AF_ID: - ppc->ppc_type = WINB_W83877AF; + ppc->ppc_model = WINB_W83877AF; break; default: - ppc->ppc_type = WINB_UNKNOWN; + ppc->ppc_model = WINB_UNKNOWN; } if (bootverbose) { @@ -898,7 +975,7 @@ found: printf("ppc%d:", ppc->ppc_unit); } - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; if (!chipset_mode) { /* autodetect mode */ @@ -940,7 +1017,7 @@ found: case (WINB_PARALLEL | WINB_ECP_EPP): ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP SPP"); @@ -966,7 +1043,7 @@ found: if (bootverbose) printf(" ECP+EPP"); - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_type = PPC_TYPE_SMCLIKE; } else { outb(efdr, inb(efdr) | WINB_ECP); @@ -988,10 +1065,18 @@ found: /* exit configuration mode */ outb(efer, 0xaa); - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); + 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 @@ -1000,7 +1085,7 @@ static int ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) { /* default to generic */ - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; if (bootverbose) printf("ppc%d:", ppc->ppc_unit); @@ -1023,8 +1108,8 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) if (ppc->ppc_avm & PPB_ECP) { /* SMC like chipset found */ - ppc->ppc_type = SMC_LIKE; - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_model = SMC_LIKE; + ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP"); @@ -1050,7 +1135,14 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) if (bootverbose) printf("\n"); - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); + 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); } @@ -1063,6 +1155,7 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) static int ppc_detect(struct ppc_data *ppc, int chipset_mode) { +#ifdef PPC_PROBE_CHIPSET int i, mode; /* list of supported chipsets */ @@ -1073,6 +1166,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { 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) @@ -1081,6 +1175,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { /* 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 * @@ -1089,9 +1184,11 @@ ppc_detect(struct ppc_data *ppc, int chipset_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) { @@ -1100,6 +1197,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { } } } +#endif /* configure/detect ECP FIFO */ if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) @@ -1115,9 +1213,9 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { * Microsequence mechanism is supposed to handle fast I/O operations. */ static int -ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) +ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) { - struct ppc_data *ppc = ppcdata[unit]; + struct ppc_data *ppc = DEVTOSOFTC(dev); struct ppb_microseq *mi; char cc, *p; int i, iter, len; @@ -1326,9 +1424,10 @@ ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) } static void -ppcintr(int unit) +ppcintr(void *arg) { - struct ppc_data *ppc = ppcdata[unit]; + 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); @@ -1341,8 +1440,6 @@ ppcintr(int unit) /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { - /* call upper code */ - ppb_intr(&ppc->ppc_link); return; } @@ -1356,8 +1453,7 @@ ppcintr(int unit) w_ecr(ppc, ecr | PPC_nFAULT_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { - /* call upper code */ - ppb_intr(&ppc->ppc_link); + /* shall be handled by underlying layers XXX */ return; } } @@ -1397,14 +1493,13 @@ ppcintr(int unit) /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; - } return; } static int -ppc_read(int unit, char *buf, int len, int mode) +ppc_read(device_t dev, char *buf, int len, int mode) { return (EINVAL); } @@ -1417,9 +1512,9 @@ ppc_read(int unit, char *buf, int len, int mode) * EINVAL is returned */ static int -ppc_write(int unit, char *buf, int len, int how) +ppc_write(device_t dev, char *buf, int len, int how) { - struct ppc_data *ppc = ppcdata[unit]; + struct ppc_data *ppc = DEVTOSOFTC(dev); char ecr, ecr_sav, ctr, ctr_sav; int s, error = 0; int spin; @@ -1434,7 +1529,7 @@ ppc_write(int unit, char *buf, int len, int how) /* * Send buffer with DMA, FIFO and interrupts */ - if (ppc->ppc_avm & PPB_ECP) { + if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) { if (ppc->ppc_dmachan >= 0) { @@ -1568,231 +1663,334 @@ error: return (error); } -/* - * Configure current operating mode - */ -static int -ppc_generic_setmode(int unit, int mode) +static void +ppc_reset_epp(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; - u_char ecr = 0; + struct ppc_data *ppc = DEVTOSOFTC(dev); + + ppc_reset_epp_timeout(ppc); - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); + return; +} - /* if ECP mode, configure ecr register */ - if (ppc->ppc_avm & 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; +static int +ppc_setmode(device_t dev, int mode) +{ + struct ppc_data *ppc = DEVTOSOFTC(dev); - 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; + switch (ppc->ppc_type) { + case PPC_TYPE_SMCLIKE: + return (ppc_smclike_setmode(ppc, mode)); + break; - w_ecr(ppc, ecr); + case PPC_TYPE_GENERIC: + default: + return (ppc_generic_setmode(ppc, mode)); + break; } - ppc->ppc_mode = mode; - - return (0); + /* not reached */ + return (ENXIO); } -/* - * 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. - */ -int -ppc_smclike_setmode(int unit, int mode) +static int +ppc_probe(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; - 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) { - /* 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; + static short next_bios_ppc = 0; + struct ppc_data *ppc; + device_t parent; + int port; - 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; + device_set_desc(dev, "Parallel port"); - w_ecr(ppc, ecr); - } + /* XXX shall be connected to pnpbios - from Peter Wemm */ + if (isa_get_logicalid(dev)) + return ENXIO; - ppc->ppc_mode = mode; + parent = device_get_parent(dev); - return (0); -} - -/* - * 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(int unit) -{ - struct ppc_data *ppc = ppcdata[unit]; - register char r; + /* + * Allocate the ppc_data structure. + */ + ppc = DEVTOSOFTC(dev); + bzero(ppc, sizeof(struct ppc_data)); - r = r_str(ppc); - w_str(ppc, r | 0x1); - w_str(ppc, r & 0xfe); + ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0; + ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0; - return; -} - -static int -ppcprobe(struct isa_device *dvp) -{ - static short next_bios_ppc = 0; - struct ppc_data *ppc; + /* retrieve ISA parameters */ + BUS_READ_IVAR(parent, dev, ISA_IVAR_PORT, &port); /* * If port not specified, use bios list. */ - if(dvp->id_iobase < 0) { + if (port < 0) { if((next_bios_ppc < BIOS_MAX_PPC) && (*(BIOS_PORTS+next_bios_ppc) != 0) ) { - dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++); + port = *(BIOS_PORTS+next_bios_ppc++); if (bootverbose) - printf("ppc: parallel port found at 0x%x\n", - dvp->id_iobase); - } else - return (0); + device_printf(dev, "parallel port found at 0x%x\n", + port); + } else { + device_printf(dev, "parallel port not found.\n"); + return ENXIO; + } } - - /* - * Port was explicitly specified. - * This allows probing of ports unknown to the BIOS. - */ - - /* - * Allocate the ppc_data structure. - */ - ppc = malloc(sizeof(struct ppc_data), M_DEVBUF, M_NOWAIT); - if (!ppc) { - printf("ppc: cannot malloc!\n"); + ppc->ppc_base = port; + + /* IO port is mandatory */ + ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, + &ppc->rid_ioport, port, port, + IO_LPTSIZE, RF_ACTIVE); + if (ppc->res_ioport == 0) { + device_printf(dev, "cannot reserve I/O port range\n"); goto error; } - bzero(ppc, sizeof(struct ppc_data)); - ppc->ppc_base = dvp->id_iobase; - ppc->ppc_unit = dvp->id_unit; - ppc->ppc_type = GENERIC; + ppc->ppc_flags = device_get_flags(dev); - /* store boot flags */ - ppc->ppc_flags = dvp->id_flags; + if (!(ppc->ppc_flags & 0x20)) { + ppc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ppc->rid_irq, + 0ul, ~0ul, 1, RF_SHAREABLE); + ppc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ, &ppc->rid_drq, + 0ul, ~0ul, 1, RF_ACTIVE); + } - ppc->ppc_mode = PPB_COMPATIBLE; - ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; + if (ppc->res_irq) + BUS_READ_IVAR(parent, dev, ISA_IVAR_IRQ, &ppc->ppc_irq); + if (ppc->res_drq) + BUS_READ_IVAR(parent, dev, ISA_IVAR_DRQ, &ppc->ppc_dmachan); - /* - * XXX Try and detect if interrupts are working - */ - if (!(dvp->id_flags & 0x20) && dvp->id_irq) - ppc->ppc_irq = ffs(dvp->id_irq) - 1; + ppc->ppc_unit = device_get_unit(dev); + ppc->ppc_model = GENERIC; - ppc->ppc_dmachan = dvp->id_drq; + ppc->ppc_mode = PPB_COMPATIBLE; + ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; - ppcdata[ppc->ppc_unit] = ppc; - nppc ++; - - /* - * Link the Parallel Port Chipset (adapter) to - * the future ppbus. Default to a generic chipset - */ - ppc->ppc_link.adapter_unit = ppc->ppc_unit; - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; /* * Try to detect the chipset and its mode. */ - if (ppc_detect(ppc, dvp->id_flags & 0xf)) + if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) goto error; - return (IO_LPTSIZE); + return (0); error: - return (0); + 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); } static int -ppcattach(struct isa_device *isdp) +ppc_attach(device_t dev) { - struct ppc_data *ppc = ppcdata[isdp->id_unit]; - struct ppb_data *ppbus; + struct ppc_data *ppc = DEVTOSOFTC(dev); - printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit, - ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm], - ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? - ppc_epp_protocol[ppc->ppc_epp] : ""); + device_t ppbus; + device_t parent = device_get_parent(dev); + 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) - printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n", - ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr, - ppc->ppc_rthr); + device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", + ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); - isdp->id_ointr = ppcintr; + 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); /* - * Prepare ppbus data area for upper level code. + * Probe the ppbus and attach devices found. */ - ppbus = ppb_alloc_bus(); + device_probe_and_attach(ppbus); - if (!ppbus) - return (0); + /* register the ppc interrupt handler as default */ + if (ppc->res_irq) { + /* default to the tty mask for registration */ /* XXX */ + if (BUS_SETUP_INTR(parent, dev, ppc->res_irq, INTR_TYPE_TTY, + ppcintr, dev, &ppc->intr_cookie) == 0) { - ppc->ppc_link.ppbus = ppbus; - ppbus->ppb_link = &ppc->ppc_link; + /* remember the ppcintr is registered */ + ppc->ppc_registered = 1; + } + } - if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { + return (0); +} - /* acquire the DMA channel forever */ - isa_dma_acquire(ppc->ppc_dmachan); - isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ +static 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: + outsb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_OUTSW_EPP: + outsw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_OUTSL_EPP: + outsl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSB_EPP: + insb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSW_EPP: + insw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSL_EPP: + insl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_RDTR: + return (r_dtr(ppc)); + break; + case PPB_RSTR: + return (r_str(ppc)); + break; + case PPB_RCTR: + return (r_ctr(ppc)); + break; + case PPB_REPP_A: + return (r_epp_A(ppc)); + break; + case PPB_REPP_D: + return (r_epp_D(ppc)); + break; + case PPB_RECR: + return (r_ecr(ppc)); + break; + case PPB_RFIFO: + return (r_fifo(ppc)); + break; + 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", __FUNCTION__); + break; } - /* - * Probe the ppbus and attach devices found. - */ - ppb_attachdevs(ppbus); + return (0); /* not significative */ +} - return (1); +static 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: + BUS_READ_IVAR(device_get_parent(bus), bus, ISA_IVAR_IRQ, val); + 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 + */ +static 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 + */ +static 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); #endif diff --git a/sys/i386/isa/ppcreg.h b/sys/i386/isa/ppcreg.h index faecb97..ec17806 100644 --- a/sys/i386/isa/ppcreg.h +++ b/sys/i386/isa/ppcreg.h @@ -45,12 +45,19 @@ #define NS_PC87334 10 /* + * 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_type; + 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 */ @@ -83,16 +90,22 @@ struct ppc_data { short ppc_wthr; /* writeIntrThresold */ short ppc_rthr; /* readIntrThresold */ -#define ppc_base ppc_link.base -#define ppc_epp ppc_link.epp_protocol -#define ppc_irq ppc_link.id_irq -#define ppc_subm ppc_link.submicroseq -#define ppc_ptr ppc_link.ptr -#define ppc_accum ppc_link.accum + 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; - struct ppb_link ppc_link; + device_t ppbus; /* parallel port chipset corresponding ppbus */ + + int rid_irq, rid_drq, rid_ioport; + struct resource *res_irq, *res_drq, *res_ioport; + + void *intr_cookie; + + int ppc_registered; /* 1 if ppcintr() is the registered interrupt */ }; /* diff --git a/sys/isa/ppc.c b/sys/isa/ppc.c index 436caeb..0ee1eb6 100644 --- a/sys/isa/ppc.c +++ b/sys/isa/ppc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997, 1998 Nicolas Souchu + * Copyright (c) 1997-2000 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,42 +30,90 @@ #if NPPC > 0 +#include "opt_ppc.h" + #include <sys/param.h> #include <sys/systm.h> -#include <sys/conf.h> -#include <sys/malloc.h> #include <sys/kernel.h> - -#include <machine/clock.h> - +#include <sys/bus.h> +#include <sys/malloc.h> + #include <vm/vm.h> -#include <vm/vm_param.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 <i386/isa/isa_device.h> -#include <i386/isa/isa.h> +#include <isa/isareg.h> +#include <isa/isavar.h> #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_msq.h> #include <i386/isa/ppcreg.h> -#include "opt_ppc.h" +#include "ppbus_if.h" #define LOG_PPC(function, ppc, string) \ if (bootverbose) printf("%s: %s\n", function, string) -static int ppcprobe(struct isa_device *); -static int ppcattach(struct isa_device *); -struct isa_driver ppcdriver = { - ppcprobe, ppcattach, "ppc" +#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) + +devclass_t ppc_devclass; + +static int ppc_probe(device_t dev); +static int ppc_attach(device_t dev); +static int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val); + +static void ppc_reset_epp(device_t); +static void ppc_ecp_sync(device_t); +static void ppcintr(void *arg); + +static int ppc_exec_microseq(device_t, struct ppb_microseq **); +static int ppc_setmode(device_t, int); + +static int ppc_read(device_t, char *, int, int); +static int ppc_write(device_t, char *, int, int); + +static u_char ppc_io(device_t, int, u_char *, int, u_char); + +static int ppc_setup_intr(device_t, device_t, struct resource *, int, + void (*)(void *), void *, void **); +static int ppc_teardown_intr(device_t, device_t, struct resource *, void *); + +static device_method_t ppc_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppc_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 struct ppc_data *ppcdata[NPPC]; -static int nppc = 0; - -static char *ppc_types[] = { + +static char *ppc_models[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 }; @@ -98,91 +146,13 @@ static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; #define BIOS_MAX_PPC 4 /* - * All these functions are default actions for IN/OUT operations. - * They may be redefined if needed. - */ -static void ppc_outsb_epp(int unit, char *addr, int cnt) { - outsb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsw_epp(int unit, char *addr, int cnt) { - outsw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsl_epp(int unit, char *addr, int cnt) { - outsl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insb_epp(int unit, char *addr, int cnt) { - insb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insw_epp(int unit, char *addr, int cnt) { - insw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insl_epp(int unit, char *addr, int cnt) { - insl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } - -static u_char ppc_rdtr(int unit) { return r_dtr(ppcdata[unit]); } -static u_char ppc_rstr(int unit) { return r_str(ppcdata[unit]); } -static u_char ppc_rctr(int unit) { return r_ctr(ppcdata[unit]); } -static u_char ppc_repp_A(int unit) { return r_epp_A(ppcdata[unit]); } -static u_char ppc_repp_D(int unit) { return r_epp_D(ppcdata[unit]); } -static u_char ppc_recr(int unit) { return r_ecr(ppcdata[unit]); } -static u_char ppc_rfifo(int unit) { return r_fifo(ppcdata[unit]); } - -static void ppc_wdtr(int unit, char byte) { w_dtr(ppcdata[unit], byte); } -static void ppc_wstr(int unit, char byte) { w_str(ppcdata[unit], byte); } -static void ppc_wctr(int unit, char byte) { w_ctr(ppcdata[unit], byte); } -static void ppc_wepp_A(int unit, char byte) { w_epp_A(ppcdata[unit], byte); } -static void ppc_wepp_D(int unit, char byte) { w_epp_D(ppcdata[unit], byte); } -static void ppc_wecr(int unit, char byte) { w_ecr(ppcdata[unit], byte); } -static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); } - -static void ppc_reset_epp_timeout(int); -static void ppc_ecp_sync(int); -static ointhand2_t ppcintr; - -static int ppc_exec_microseq(int, struct ppb_microseq **); -static int ppc_generic_setmode(int, int); -static int ppc_smclike_setmode(int, int); - -static int ppc_read(int, char *, int, int); -static int ppc_write(int, char *, int, int); - -static struct ppb_adapter ppc_smclike_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_smclike_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp_A, ppc_repp_D, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp_A, ppc_wepp_D, ppc_wecr, ppc_wfifo -}; - -static struct ppb_adapter ppc_generic_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_generic_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp_A, ppc_repp_D, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp_A, ppc_wepp_D, ppc_wecr, ppc_wfifo -}; - -/* * ppc_ecp_sync() XXX */ static void -ppc_ecp_sync(int unit) { +ppc_ecp_sync(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; int i, r; + struct ppc_data *ppc = DEVTOSOFTC(dev); if (!(ppc->ppc_avm & PPB_ECP)) return; @@ -199,7 +169,7 @@ ppc_ecp_sync(int unit) { } printf("ppc%d: ECP sync failed as data still " \ - "present in FIFO.\n", unit); + "present in FIFO.\n", ppc->ppc_unit); return; } @@ -328,6 +298,121 @@ ppc_detect_port(struct ppc_data *ppc) } /* + * 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) { + /* 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) { + /* 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. @@ -381,11 +466,11 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for outb(idport, PC873_SID); val = inb(idport + 1); if ((val & 0xf0) == 0x10) { - ppc->ppc_type = NS_PC87332; + ppc->ppc_model = NS_PC87332; } else if ((val & 0xf8) == 0x70) { - ppc->ppc_type = NS_PC87306; + ppc->ppc_model = NS_PC87306; } else if ((val & 0xf8) == 0x50) { - ppc->ppc_type = NS_PC87334; + ppc->ppc_model = NS_PC87334; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); @@ -484,7 +569,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for else ppc->ppc_epp = EPP_1_7; - if ((ppc->ppc_type == NS_PC87332) && bootverbose) { + if ((ppc->ppc_model == NS_PC87332) && bootverbose) { outb(idport, PC873_PTR); ptr = inb(idport + 1); if (ptr & PC873_EPPRDIR) @@ -539,7 +624,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for printf(", EPP1.9"); /* enable automatic direction turnover */ - if (ppc->ppc_type == NS_PC87332) { + if (ppc->ppc_model == NS_PC87332) { outb(idport, PC873_PTR); ptr = inb(idport + 1); ptr &= ~PC873_EPPRDIR; @@ -581,22 +666,14 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for if (bootverbose) printf("\n"); - ppc->ppc_link.adapter = &ppc_generic_adapter; - ppc_generic_setmode(ppc->ppc_unit, chipset_mode); + ppc->ppc_type = PPC_TYPE_GENERIC; + ppc_generic_setmode(ppc, chipset_mode); return(chipset_mode); } return(-1); } -static int -ppc_check_epp_timeout(struct ppc_data *ppc) -{ - ppc_reset_epp_timeout(ppc->ppc_unit); - - return (!(r_str(ppc) & TIMEOUT)); -} - /* * ppc_smc37c66xgt_detect * @@ -661,7 +738,7 @@ config: if (port_address[(int)r] != ppc->ppc_base) return (-1); - ppc->ppc_type = type; + ppc->ppc_model = type; /* * CR1 and CR4 registers bits 3 and 0/1 for mode configuration @@ -800,8 +877,8 @@ end_detect: /* end config mode */ outb(csr, 0xaa); - ppc->ppc_link.adapter = &ppc_smclike_adapter; - ppc_smclike_setmode(ppc->ppc_unit, chipset_mode); + ppc->ppc_type = PPC_TYPE_SMCLIKE; + ppc_smclike_setmode(ppc, chipset_mode); return (chipset_mode); } @@ -866,15 +943,15 @@ found: switch (inb(efdr) & WINB_CHIPID) { case WINB_W83877F_ID: - ppc->ppc_type = WINB_W83877F; + ppc->ppc_model = WINB_W83877F; break; case WINB_W83877AF_ID: - ppc->ppc_type = WINB_W83877AF; + ppc->ppc_model = WINB_W83877AF; break; default: - ppc->ppc_type = WINB_UNKNOWN; + ppc->ppc_model = WINB_UNKNOWN; } if (bootverbose) { @@ -898,7 +975,7 @@ found: printf("ppc%d:", ppc->ppc_unit); } - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; if (!chipset_mode) { /* autodetect mode */ @@ -940,7 +1017,7 @@ found: case (WINB_PARALLEL | WINB_ECP_EPP): ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP SPP"); @@ -966,7 +1043,7 @@ found: if (bootverbose) printf(" ECP+EPP"); - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_type = PPC_TYPE_SMCLIKE; } else { outb(efdr, inb(efdr) | WINB_ECP); @@ -988,10 +1065,18 @@ found: /* exit configuration mode */ outb(efer, 0xaa); - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); + 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 @@ -1000,7 +1085,7 @@ static int ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) { /* default to generic */ - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; if (bootverbose) printf("ppc%d:", ppc->ppc_unit); @@ -1023,8 +1108,8 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) if (ppc->ppc_avm & PPB_ECP) { /* SMC like chipset found */ - ppc->ppc_type = SMC_LIKE; - ppc->ppc_link.adapter = &ppc_smclike_adapter; + ppc->ppc_model = SMC_LIKE; + ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP"); @@ -1050,7 +1135,14 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) if (bootverbose) printf("\n"); - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); + 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); } @@ -1063,6 +1155,7 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) static int ppc_detect(struct ppc_data *ppc, int chipset_mode) { +#ifdef PPC_PROBE_CHIPSET int i, mode; /* list of supported chipsets */ @@ -1073,6 +1166,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { 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) @@ -1081,6 +1175,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { /* 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 * @@ -1089,9 +1184,11 @@ ppc_detect(struct ppc_data *ppc, int chipset_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) { @@ -1100,6 +1197,7 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { } } } +#endif /* configure/detect ECP FIFO */ if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) @@ -1115,9 +1213,9 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) { * Microsequence mechanism is supposed to handle fast I/O operations. */ static int -ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) +ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) { - struct ppc_data *ppc = ppcdata[unit]; + struct ppc_data *ppc = DEVTOSOFTC(dev); struct ppb_microseq *mi; char cc, *p; int i, iter, len; @@ -1326,9 +1424,10 @@ ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) } static void -ppcintr(int unit) +ppcintr(void *arg) { - struct ppc_data *ppc = ppcdata[unit]; + 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); @@ -1341,8 +1440,6 @@ ppcintr(int unit) /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { - /* call upper code */ - ppb_intr(&ppc->ppc_link); return; } @@ -1356,8 +1453,7 @@ ppcintr(int unit) w_ecr(ppc, ecr | PPC_nFAULT_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { - /* call upper code */ - ppb_intr(&ppc->ppc_link); + /* shall be handled by underlying layers XXX */ return; } } @@ -1397,14 +1493,13 @@ ppcintr(int unit) /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; - } return; } static int -ppc_read(int unit, char *buf, int len, int mode) +ppc_read(device_t dev, char *buf, int len, int mode) { return (EINVAL); } @@ -1417,9 +1512,9 @@ ppc_read(int unit, char *buf, int len, int mode) * EINVAL is returned */ static int -ppc_write(int unit, char *buf, int len, int how) +ppc_write(device_t dev, char *buf, int len, int how) { - struct ppc_data *ppc = ppcdata[unit]; + struct ppc_data *ppc = DEVTOSOFTC(dev); char ecr, ecr_sav, ctr, ctr_sav; int s, error = 0; int spin; @@ -1434,7 +1529,7 @@ ppc_write(int unit, char *buf, int len, int how) /* * Send buffer with DMA, FIFO and interrupts */ - if (ppc->ppc_avm & PPB_ECP) { + if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) { if (ppc->ppc_dmachan >= 0) { @@ -1568,231 +1663,334 @@ error: return (error); } -/* - * Configure current operating mode - */ -static int -ppc_generic_setmode(int unit, int mode) +static void +ppc_reset_epp(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; - u_char ecr = 0; + struct ppc_data *ppc = DEVTOSOFTC(dev); + + ppc_reset_epp_timeout(ppc); - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); + return; +} - /* if ECP mode, configure ecr register */ - if (ppc->ppc_avm & 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; +static int +ppc_setmode(device_t dev, int mode) +{ + struct ppc_data *ppc = DEVTOSOFTC(dev); - 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; + switch (ppc->ppc_type) { + case PPC_TYPE_SMCLIKE: + return (ppc_smclike_setmode(ppc, mode)); + break; - w_ecr(ppc, ecr); + case PPC_TYPE_GENERIC: + default: + return (ppc_generic_setmode(ppc, mode)); + break; } - ppc->ppc_mode = mode; - - return (0); + /* not reached */ + return (ENXIO); } -/* - * 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. - */ -int -ppc_smclike_setmode(int unit, int mode) +static int +ppc_probe(device_t dev) { - struct ppc_data *ppc = ppcdata[unit]; - 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) { - /* 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; + static short next_bios_ppc = 0; + struct ppc_data *ppc; + device_t parent; + int port; - 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; + device_set_desc(dev, "Parallel port"); - w_ecr(ppc, ecr); - } + /* XXX shall be connected to pnpbios - from Peter Wemm */ + if (isa_get_logicalid(dev)) + return ENXIO; - ppc->ppc_mode = mode; + parent = device_get_parent(dev); - return (0); -} - -/* - * 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(int unit) -{ - struct ppc_data *ppc = ppcdata[unit]; - register char r; + /* + * Allocate the ppc_data structure. + */ + ppc = DEVTOSOFTC(dev); + bzero(ppc, sizeof(struct ppc_data)); - r = r_str(ppc); - w_str(ppc, r | 0x1); - w_str(ppc, r & 0xfe); + ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0; + ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0; - return; -} - -static int -ppcprobe(struct isa_device *dvp) -{ - static short next_bios_ppc = 0; - struct ppc_data *ppc; + /* retrieve ISA parameters */ + BUS_READ_IVAR(parent, dev, ISA_IVAR_PORT, &port); /* * If port not specified, use bios list. */ - if(dvp->id_iobase < 0) { + if (port < 0) { if((next_bios_ppc < BIOS_MAX_PPC) && (*(BIOS_PORTS+next_bios_ppc) != 0) ) { - dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++); + port = *(BIOS_PORTS+next_bios_ppc++); if (bootverbose) - printf("ppc: parallel port found at 0x%x\n", - dvp->id_iobase); - } else - return (0); + device_printf(dev, "parallel port found at 0x%x\n", + port); + } else { + device_printf(dev, "parallel port not found.\n"); + return ENXIO; + } } - - /* - * Port was explicitly specified. - * This allows probing of ports unknown to the BIOS. - */ - - /* - * Allocate the ppc_data structure. - */ - ppc = malloc(sizeof(struct ppc_data), M_DEVBUF, M_NOWAIT); - if (!ppc) { - printf("ppc: cannot malloc!\n"); + ppc->ppc_base = port; + + /* IO port is mandatory */ + ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, + &ppc->rid_ioport, port, port, + IO_LPTSIZE, RF_ACTIVE); + if (ppc->res_ioport == 0) { + device_printf(dev, "cannot reserve I/O port range\n"); goto error; } - bzero(ppc, sizeof(struct ppc_data)); - ppc->ppc_base = dvp->id_iobase; - ppc->ppc_unit = dvp->id_unit; - ppc->ppc_type = GENERIC; + ppc->ppc_flags = device_get_flags(dev); - /* store boot flags */ - ppc->ppc_flags = dvp->id_flags; + if (!(ppc->ppc_flags & 0x20)) { + ppc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ppc->rid_irq, + 0ul, ~0ul, 1, RF_SHAREABLE); + ppc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ, &ppc->rid_drq, + 0ul, ~0ul, 1, RF_ACTIVE); + } - ppc->ppc_mode = PPB_COMPATIBLE; - ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; + if (ppc->res_irq) + BUS_READ_IVAR(parent, dev, ISA_IVAR_IRQ, &ppc->ppc_irq); + if (ppc->res_drq) + BUS_READ_IVAR(parent, dev, ISA_IVAR_DRQ, &ppc->ppc_dmachan); - /* - * XXX Try and detect if interrupts are working - */ - if (!(dvp->id_flags & 0x20) && dvp->id_irq) - ppc->ppc_irq = ffs(dvp->id_irq) - 1; + ppc->ppc_unit = device_get_unit(dev); + ppc->ppc_model = GENERIC; - ppc->ppc_dmachan = dvp->id_drq; + ppc->ppc_mode = PPB_COMPATIBLE; + ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; - ppcdata[ppc->ppc_unit] = ppc; - nppc ++; - - /* - * Link the Parallel Port Chipset (adapter) to - * the future ppbus. Default to a generic chipset - */ - ppc->ppc_link.adapter_unit = ppc->ppc_unit; - ppc->ppc_link.adapter = &ppc_generic_adapter; + ppc->ppc_type = PPC_TYPE_GENERIC; /* * Try to detect the chipset and its mode. */ - if (ppc_detect(ppc, dvp->id_flags & 0xf)) + if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) goto error; - return (IO_LPTSIZE); + return (0); error: - return (0); + 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); } static int -ppcattach(struct isa_device *isdp) +ppc_attach(device_t dev) { - struct ppc_data *ppc = ppcdata[isdp->id_unit]; - struct ppb_data *ppbus; + struct ppc_data *ppc = DEVTOSOFTC(dev); - printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit, - ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm], - ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? - ppc_epp_protocol[ppc->ppc_epp] : ""); + device_t ppbus; + device_t parent = device_get_parent(dev); + 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) - printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n", - ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr, - ppc->ppc_rthr); + device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", + ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); - isdp->id_ointr = ppcintr; + 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); /* - * Prepare ppbus data area for upper level code. + * Probe the ppbus and attach devices found. */ - ppbus = ppb_alloc_bus(); + device_probe_and_attach(ppbus); - if (!ppbus) - return (0); + /* register the ppc interrupt handler as default */ + if (ppc->res_irq) { + /* default to the tty mask for registration */ /* XXX */ + if (BUS_SETUP_INTR(parent, dev, ppc->res_irq, INTR_TYPE_TTY, + ppcintr, dev, &ppc->intr_cookie) == 0) { - ppc->ppc_link.ppbus = ppbus; - ppbus->ppb_link = &ppc->ppc_link; + /* remember the ppcintr is registered */ + ppc->ppc_registered = 1; + } + } - if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { + return (0); +} - /* acquire the DMA channel forever */ - isa_dma_acquire(ppc->ppc_dmachan); - isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ +static 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: + outsb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_OUTSW_EPP: + outsw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_OUTSL_EPP: + outsl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSB_EPP: + insb(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSW_EPP: + insw(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_INSL_EPP: + insl(ppc->ppc_base + PPC_EPP_DATA, addr, cnt); + break; + case PPB_RDTR: + return (r_dtr(ppc)); + break; + case PPB_RSTR: + return (r_str(ppc)); + break; + case PPB_RCTR: + return (r_ctr(ppc)); + break; + case PPB_REPP_A: + return (r_epp_A(ppc)); + break; + case PPB_REPP_D: + return (r_epp_D(ppc)); + break; + case PPB_RECR: + return (r_ecr(ppc)); + break; + case PPB_RFIFO: + return (r_fifo(ppc)); + break; + 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", __FUNCTION__); + break; } - /* - * Probe the ppbus and attach devices found. - */ - ppb_attachdevs(ppbus); + return (0); /* not significative */ +} - return (1); +static 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: + BUS_READ_IVAR(device_get_parent(bus), bus, ISA_IVAR_IRQ, val); + 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 + */ +static 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 + */ +static 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); #endif diff --git a/sys/isa/ppcreg.h b/sys/isa/ppcreg.h index faecb97..ec17806 100644 --- a/sys/isa/ppcreg.h +++ b/sys/isa/ppcreg.h @@ -45,12 +45,19 @@ #define NS_PC87334 10 /* + * 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_type; + 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 */ @@ -83,16 +90,22 @@ struct ppc_data { short ppc_wthr; /* writeIntrThresold */ short ppc_rthr; /* readIntrThresold */ -#define ppc_base ppc_link.base -#define ppc_epp ppc_link.epp_protocol -#define ppc_irq ppc_link.id_irq -#define ppc_subm ppc_link.submicroseq -#define ppc_ptr ppc_link.ptr -#define ppc_accum ppc_link.accum + 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; - struct ppb_link ppc_link; + device_t ppbus; /* parallel port chipset corresponding ppbus */ + + int rid_irq, rid_drq, rid_ioport; + struct resource *res_irq, *res_drq, *res_ioport; + + void *intr_cookie; + + int ppc_registered; /* 1 if ppcintr() is the registered interrupt */ }; /* |