Index: stable/6/sys/dev/ppbus/if_plip.c =================================================================== --- stable/6/sys/dev/ppbus/if_plip.c (revision 160502) +++ stable/6/sys/dev/ppbus/if_plip.c (revision 160503) @@ -1,772 +1,773 @@ /*- * Copyright (c) 1997 Poul-Henning Kamp * 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. * * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp */ #include __FBSDID("$FreeBSD$"); /* * Parallel port TCP/IP interfaces added. I looked at the driver from * MACH but this is a complete rewrite, and btw. incompatible, and it * should perform better too. I have never run the MACH driver though. * * This driver sends two bytes (0x08, 0x00) in front of each packet, * to allow us to distinguish another format later. * * Now added a Linux/Crynwr compatibility mode which is enabled using * IF_LINK0 - Tim Wilkinson. * * TODO: * Make HDLC/PPP mode, use IF_LLC1 to enable. * * Connect the two computers using a Laplink parallel cable to use this * feature: * * +----------------------------------------+ * |A-name A-End B-End Descr. Port/Bit | * +----------------------------------------+ * |DATA0 2 15 Data 0/0x01 | * |-ERROR 15 2 1/0x08 | * +----------------------------------------+ * |DATA1 3 13 Data 0/0x02 | * |+SLCT 13 3 1/0x10 | * +----------------------------------------+ * |DATA2 4 12 Data 0/0x04 | * |+PE 12 4 1/0x20 | * +----------------------------------------+ * |DATA3 5 10 Strobe 0/0x08 | * |-ACK 10 5 1/0x40 | * +----------------------------------------+ * |DATA4 6 11 Data 0/0x10 | * |BUSY 11 6 1/~0x80 | * +----------------------------------------+ * |GND 18-25 18-25 GND - | * +----------------------------------------+ * * Expect transfer-rates up to 75 kbyte/sec. * * If GCC could correctly grok * register int port asm("edx") * the code would be cleaner * * Poul-Henning Kamp */ /* * Update for ppbus, PLIP support only - Nicolas Souchu */ #include "opt_plip.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ppbus_if.h" #include #ifndef LPMTU /* MTU for the lp# interfaces */ #define LPMTU 1500 #endif #ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ #define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ #endif #ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ #define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ #endif #ifndef LPMAXERRS /* Max errors before !RUNNING */ #define LPMAXERRS 100 #endif #define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ #define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ #define MLPIPHDRLEN CLPIPHDRLEN #define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ #define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN #define MLPIPHDRLEN LPIPHDRLEN #endif #define LPIPTBLSIZE 256 /* Size of octet translation table */ #define lprintf if (lptflag) printf #ifdef PLIP_DEBUG static int volatile lptflag = 1; #else static int volatile lptflag = 0; #endif struct lp_data { struct ifnet *sc_ifp; u_char *sc_ifbuf; int sc_iferrs; struct resource *res_irq; }; /* Tables for the lp# interface */ static u_char *txmith; #define txmitl (txmith+(1*LPIPTBLSIZE)) #define trecvh (txmith+(2*LPIPTBLSIZE)) #define trecvl (txmith+(3*LPIPTBLSIZE)) static u_char *ctxmith; #define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) #define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) #define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) /* Functions for the lp# interface */ 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 lp_intr(void *); #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 devclass_t lp_devclass; static void lp_identify(driver_t *driver, device_t parent) { device_t dev; dev = device_find_child(parent, "plip", 0); if (!dev) BUS_ADD_CHILD(parent, 0, "plip", -1); } /* * lpprobe() */ static int lp_probe(device_t dev) { device_t ppbus = device_get_parent(dev); struct lp_data *lp; int zero = 0; uintptr_t irq; lp = DEVTOSOFTC(dev); /* retrieve the ppbus irq */ BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); /* if we haven't interrupts, the probe fails */ if (irq == -1) { device_printf(dev, "not an interrupt driven port, failed.\n"); return (ENXIO); } /* 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); } /* * lp dependent initialisation. */ device_set_desc(dev, "PLIP network interface"); return (0); } static int lp_attach (device_t dev) { struct lp_data *lp = DEVTOSOFTC(dev); struct ifnet *ifp; ifp = lp->sc_ifp = if_alloc(IFT_PARA); if (ifp == NULL) { return (ENOSPC); } ifp->if_softc = lp; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = LPMTU; ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST | IFF_NEEDSGIANT; ifp->if_ioctl = lpioctl; ifp->if_output = lpoutput; ifp->if_hdrlen = 0; ifp->if_addrlen = 0; ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; if_attach(ifp); bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); return (0); } /* * Build the translation tables for the LPIP (BSD unix) protocol. * We don't want to calculate these nasties in our tight loop, so we * precalculate them when we initialize. */ static int lpinittables (void) { int i; if (!txmith) txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); if (!txmith) return 1; if (!ctxmith) ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); if (!ctxmith) return 1; for (i=0; i < LPIPTBLSIZE; i++) { ctxmith[i] = (i & 0xF0) >> 4; ctxmitl[i] = 0x10 | (i & 0x0F); ctrecvh[i] = (i & 0x78) << 1; ctrecvl[i] = (i & 0x78) >> 3; } for (i=0; i < LPIPTBLSIZE; i++) { txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); } return 0; } /* * Process an ioctl request. */ static int lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) { device_t dev = UNITODEVICE(ifp->if_dunit); 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) { case SIOCSIFDSTADDR: case SIOCAIFADDR: case SIOCSIFADDR: if (ifa->ifa_addr->sa_family != AF_INET) return EAFNOSUPPORT; ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { ppb_wctr(ppbus, 0x00); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* IFF_UP is not set, try to release the bus anyway */ ppb_release_bus(ppbus, dev); break; } if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { /* XXX * Should the request be interruptible? */ 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(ppbus, PPB_COMPATIBLE); if (lpinittables()) { ppb_release_bus(ppbus, dev); return ENOBUFS; } sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN, M_DEVBUF, M_WAITOK); if (!sc->sc_ifbuf) { ppb_release_bus(ppbus, dev); return ENOBUFS; } /* 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_drv_flags |= IFF_DRV_RUNNING; } break; case SIOCSIFMTU: ptr = sc->sc_ifbuf; sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); if (!sc->sc_ifbuf) { sc->sc_ifbuf = ptr; return ENOBUFS; } if (ptr) free(ptr,M_DEVBUF); sc->sc_ifp->if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU: ifr->ifr_mtu = sc->sc_ifp->if_mtu; break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == 0) { return EAFNOSUPPORT; /* XXX */ } switch (ifr->ifr_addr.sa_family) { case AF_INET: break; default: return EAFNOSUPPORT; } break; case SIOCGIFMEDIA: /* * No ifmedia support at this stage; maybe use it * in future for eg. protocol selection. */ return EINVAL; default: lprintf("LP:ioctl(0x%lx)\n", cmd); return EINVAL; } return 0; } static __inline int clpoutbyte (u_char byte, int spin, device_t ppbus) { ppb_wdtr(ppbus, ctxmitl[byte]); while (ppb_rstr(ppbus) & CLPIP_SHAKE) if (--spin == 0) { return 1; } ppb_wdtr(ppbus, ctxmith[byte]); while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) if (--spin == 0) { return 1; } return 0; } static __inline int clpinbyte (int spin, device_t ppbus) { u_char c, cl; while((ppb_rstr(ppbus) & CLPIP_SHAKE)) if(!--spin) { return -1; } cl = ppb_rstr(ppbus); ppb_wdtr(ppbus, 0x10); while(!(ppb_rstr(ppbus) & CLPIP_SHAKE)) if(!--spin) { return -1; } c = ppb_rstr(ppbus); ppb_wdtr(ppbus, 0x00); return (ctrecvl[cl] | ctrecvh[c]); } static void lptap(struct ifnet *ifp, struct mbuf *m) { u_int32_t af = AF_INET; BPF_MTAP2(ifp, &af, sizeof(af), m); } static void lp_intr (void *arg) { 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; struct mbuf *top; s = splhigh(); if (sc->sc_ifp->if_flags & IFF_LINK0) { /* Ack. the request */ ppb_wdtr(ppbus, 0x01); /* Get the packet length */ j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) goto err; len = j; j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) goto err; len = len + (j << 8); if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN) goto err; bp = sc->sc_ifbuf; while (len--) { j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) { goto err; } *bp++ = j; } /* Get and ignore checksum */ j = clpinbyte(LPMAXSPIN2, ppbus); if (j == -1) { goto err; } len = bp - sc->sc_ifbuf; if (len <= CLPIPHDRLEN) goto err; sc->sc_iferrs = 0; len -= CLPIPHDRLEN; sc->sc_ifp->if_ipackets++; sc->sc_ifp->if_ibytes += len; top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp, 0); if (top) { if (sc->sc_ifp->if_bpf) lptap(sc->sc_ifp, top); netisr_queue(NETISR_IP, top); /* mbuf is free'd on failure. */ } goto done; } while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { len = sc->sc_ifp->if_mtu + LPIPHDRLEN; bp = sc->sc_ifbuf; while (len--) { cl = ppb_rstr(ppbus); ppb_wdtr(ppbus, 8); j = LPMAXSPIN2; while((ppb_rstr(ppbus) & LPIP_SHAKE)) if(!--j) goto err; c = ppb_rstr(ppbus); ppb_wdtr(ppbus, 0); *bp++= trecvh[cl] | trecvl[c]; j = LPMAXSPIN2; while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) { if (cl != c && (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) == (c & 0xf8)) goto end; if (!--j) goto err; } } end: len = bp - sc->sc_ifbuf; if (len <= LPIPHDRLEN) goto err; sc->sc_iferrs = 0; len -= LPIPHDRLEN; sc->sc_ifp->if_ipackets++; sc->sc_ifp->if_ibytes += len; top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp, 0); if (top) { if (sc->sc_ifp->if_bpf) lptap(sc->sc_ifp, top); netisr_queue(NETISR_IP, top); /* mbuf is free'd on failure. */ } } goto done; err: ppb_wdtr(ppbus, 0); lprintf("R"); sc->sc_ifp->if_ierrors++; sc->sc_iferrs++; /* * We are not able to send receive anything for now, * so stop wasting our time */ if (sc->sc_iferrs > LPMAXERRS) { printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev)); ppb_wctr(ppbus, 0x00); sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sc->sc_iferrs=0; } done: splx(s); return; } static __inline int lpoutbyte (u_char byte, int spin, device_t ppbus) { ppb_wdtr(ppbus, txmith[byte]); while (!(ppb_rstr(ppbus) & LPIP_SHAKE)) if (--spin == 0) return 1; ppb_wdtr(ppbus, txmitl[byte]); while (ppb_rstr(ppbus) & LPIP_SHAKE) if (--spin == 0) return 1; return 0; } static int lpoutput (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { device_t dev = UNITODEVICE(ifp->if_dunit); device_t ppbus = device_get_parent(dev); int s, err; struct mbuf *mm; u_char *cp = "\0\0"; u_char chksum = 0; int count = 0; int i, len, spin; /* We need a sensible value if we abort */ cp++; ifp->if_drv_flags |= IFF_DRV_RUNNING; err = 1; /* assume we're aborting because of an error */ s = splhigh(); /* Suspend (on laptops) or receive-errors might have taken us offline */ ppb_wctr(ppbus, IRQENABLE); if (ifp->if_flags & IFF_LINK0) { if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { lprintf("&"); lp_intr(dev); } /* Alert other end to pending packet */ spin = LPMAXSPIN1; ppb_wdtr(ppbus, 0x08); while ((ppb_rstr(ppbus) & 0x08) == 0) if (--spin == 0) { goto nend; } /* Calculate length of packet, then send that */ count += 14; /* Ethernet header len */ mm = m; for (mm = m; mm; mm = mm->m_next) { count += mm->m_len; } if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) goto nend; if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) goto nend; /* Send dummy ethernet header */ for (i = 0; i < 12; i++) { if (clpoutbyte(i, LPMAXSPIN1, ppbus)) goto nend; chksum += i; } if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) goto nend; if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) goto nend; chksum += 0x08 + 0x00; /* Add into checksum */ mm = m; do { cp = mtod(mm, u_char *); len = mm->m_len; while (len--) { chksum += *cp; if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus)) goto nend; } } while ((mm = mm->m_next)); /* Send checksum */ if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) goto nend; /* Go quiescent */ ppb_wdtr(ppbus, 0); err = 0; /* No errors */ nend: if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; lprintf("X"); } else { ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; if (ifp->if_bpf) lptap(ifp, m); } m_freem(m); if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { lprintf("^"); lp_intr(dev); } (void) splx(s); return 0; } if (ppb_rstr(ppbus) & LPIP_SHAKE) { lprintf("&"); lp_intr(dev); } if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) goto end; if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) goto end; mm = m; do { cp = mtod(mm,u_char *); len = mm->m_len; while (len--) if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) goto end; } while ((mm = mm->m_next)); err = 0; /* no errors were encountered */ end: --cp; ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; lprintf("X"); } else { ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; if (ifp->if_bpf) lptap(ifp, m); } m_freem(m); if (ppb_rstr(ppbus) & LPIP_SHAKE) { lprintf("^"); lp_intr(dev); } (void) splx(s); return 0; } static device_method_t lp_methods[] = { /* device interface */ DEVMETHOD(device_identify, lp_identify), DEVMETHOD(device_probe, lp_probe), DEVMETHOD(device_attach, lp_attach), { 0, 0 } }; static driver_t lp_driver = { "plip", lp_methods, sizeof(struct lp_data), }; DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0); +MODULE_DEPEND(plip, ppbus, 1, 1, 1); Index: stable/6/sys/dev/ppbus/lpbb.c =================================================================== --- stable/6/sys/dev/ppbus/lpbb.c (revision 160502) +++ stable/6/sys/dev/ppbus/lpbb.c (revision 160503) @@ -1,230 +1,231 @@ /*- * Copyright (c) 1998, 2001 Nicolas Souchu, Marc Bouget * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * */ #include __FBSDID("$FreeBSD$"); /* * I2C Bit-Banging over parallel port * * See the Official Philips interface description in lpbb(4) */ #include #include #include #include #include #include #include #include "ppbus_if.h" #include #include #include #include "iicbb_if.h" static int lpbb_detect(device_t dev); static void lpbb_identify(driver_t *driver, device_t parent) { device_t dev; dev = device_find_child(parent, "lpbb", 0); if (!dev) BUS_ADD_CHILD(parent, 0, "lpbb", -1); } static int lpbb_probe(device_t dev) { /* Perhaps call this during identify instead? */ if (!lpbb_detect(dev)) return (ENXIO); device_set_desc(dev, "Parallel I2C bit-banging interface"); return (0); } static int lpbb_attach(device_t dev) { device_t bitbang; /* add generic bit-banging code */ bitbang = device_add_child(dev, "iicbb", -1); device_probe_and_attach(bitbang); return (0); } static int lpbb_callback(device_t dev, int index, caddr_t *data) { device_t ppbus = device_get_parent(dev); int error = 0; int how; switch (index) { case IIC_REQUEST_BUS: /* request the ppbus */ how = *(int *)data; error = ppb_request_bus(ppbus, dev, how); break; case IIC_RELEASE_BUS: /* release the ppbus */ error = ppb_release_bus(ppbus, dev); break; default: error = EINVAL; } return (error); } #define SDA_out 0x80 #define SCL_out 0x08 #define SDA_in 0x80 #define SCL_in 0x08 #define ALIM 0x20 #define I2CKEY 0x50 static int lpbb_getscl(device_t dev) { return ((ppb_rstr(device_get_parent(dev)) & SCL_in) == SCL_in); } static int lpbb_getsda(device_t dev) { return ((ppb_rstr(device_get_parent(dev)) & SDA_in) == SDA_in); } static void lpbb_setsda(device_t dev, char val) { device_t ppbus = device_get_parent(dev); if(val==0) ppb_wdtr(ppbus, (u_char)SDA_out); else ppb_wdtr(ppbus, (u_char)~SDA_out); } static void lpbb_setscl(device_t dev, unsigned char val) { device_t ppbus = device_get_parent(dev); 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(device_t dev) { 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 */ lpbb_setsda(dev, 1); lpbb_setscl(dev, 1); if ((ppb_rstr(ppbus) & I2CKEY) || ((ppb_rstr(ppbus) & ALIM) != ALIM)) { ppb_release_bus(ppbus, dev); return (0); } ppb_release_bus(ppbus, dev); return (1); } static int lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) { 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 */ lpbb_setsda(dev, 1); lpbb_setscl(dev, 1); ppb_release_bus(ppbus, dev); return (IIC_ENOADDR); } static devclass_t lpbb_devclass; static device_method_t lpbb_methods[] = { /* device interface */ DEVMETHOD(device_identify, lpbb_identify), DEVMETHOD(device_probe, lpbb_probe), DEVMETHOD(device_attach, lpbb_attach), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), /* iicbb interface */ DEVMETHOD(iicbb_callback, lpbb_callback), DEVMETHOD(iicbb_setsda, lpbb_setsda), DEVMETHOD(iicbb_setscl, lpbb_setscl), DEVMETHOD(iicbb_getsda, lpbb_getsda), DEVMETHOD(iicbb_getscl, lpbb_getscl), DEVMETHOD(iicbb_reset, lpbb_reset), { 0, 0 } }; static driver_t lpbb_driver = { "lpbb", lpbb_methods, 1, }; DRIVER_MODULE(lpbb, ppbus, lpbb_driver, lpbb_devclass, 0, 0); +MODULE_DEPEND(lpbb, ppbus, 1, 1, 1); MODULE_DEPEND(lpbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); MODULE_VERSION(lpbb, 1); Index: stable/6/sys/dev/ppbus/lpt.c =================================================================== --- stable/6/sys/dev/ppbus/lpt.c (revision 160502) +++ stable/6/sys/dev/ppbus/lpt.c (revision 160503) @@ -1,967 +1,968 @@ /*- * Copyright (c) 1990 William F. Jolitz, TeleMuse * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This software is a component of "386BSD" developed by * William F. Jolitz, TeleMuse. * 4. Neither the name of the developer nor the name "386BSD" * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT * NOT MAKE USE OF THIS WORK. * * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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. * * from: unknown origin, 386BSD 0.1 * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp * From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp */ #include __FBSDID("$FreeBSD$"); /* * Device Driver for AT parallel printer port * Written by William Jolitz 12/18/90 */ /* * Updated for ppbus by Nicolas Souchu * [Mon Jul 28 1997] */ #include "opt_lpt.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ppbus_if.h" #include #ifndef LPT_DEBUG #define lprintf(args) #else #define lprintf(args) \ do { \ if (lptflag) \ printf args; \ } while (0) static int volatile lptflag = 1; #endif #define LPINITRDY 4 /* wait up to 4 seconds for a ready */ #define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */ #define LPTOUTMAX 1 /* maximal timeout 1 s */ #define LPPRI (PZERO+8) #define BUFSIZE 1024 #define BUFSTATSIZE 32 #define LPTUNIT(s) ((s)&0x03) #define LPTFLAGS(s) ((s)&0xfc) struct lpt_data { short sc_state; /* default case: negative prime, negative ack, handshake strobe, prime once */ u_char sc_control; char sc_flags; #define LP_POS_INIT 0x04 /* if we are a postive init signal */ #define LP_POS_ACK 0x08 /* if we are a positive going ack */ #define LP_NO_PRIME 0x10 /* don't prime the printer at all */ #define LP_PRIMEOPEN 0x20 /* prime on every open */ #define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */ #define LP_BYPASS 0x80 /* bypass printer ready checks */ void *sc_inbuf; void *sc_statbuf; short sc_xfercnt ; char sc_primed; char *sc_cp ; u_short sc_irq ; /* IRQ status of port */ #define LP_HAS_IRQ 0x01 /* we have an irq available */ #define LP_USE_IRQ 0x02 /* we are using our irq */ #define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ #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 */ }; #define LPT_NAME "lpt" /* our official name */ static timeout_t lptout; static int lpt_port_test(device_t dev, u_char data, u_char mask); static int lpt_detect(device_t dev); #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 void lptintr(device_t dev); static void lpt_intr(void *arg); /* without spls */ static devclass_t lpt_devclass; /* bits for state */ #define OPEN (1<<0) /* device is open */ #define ASLP (1<<1) /* awaiting draining of printer */ #define EERROR (1<<2) /* error was received from printer */ #define OBUSY (1<<3) /* printer is busy doing output */ #define LPTOUT (1<<4) /* timeout while not selected */ #define TOUT (1<<5) /* timeout while not selected */ #define LPTINIT (1<<6) /* waiting to initialize for open */ #define INTERRUPTED (1<<7) /* write call was interrupted */ #define HAVEBUS (1<<8) /* the driver owns the bus */ /* status masks to interrogate printer status */ #define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */ #define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR) /* Printer Ready condition - from lpa.c */ /* 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(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 */ static d_open_t lptopen; static d_close_t lptclose; static d_write_t lptwrite; static d_read_t lptread; static d_ioctl_t lptioctl; static struct cdevsw lpt_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, .d_open = lptopen, .d_close = lptclose, .d_read = lptread, .d_write = lptwrite, .d_ioctl = lptioctl, .d_name = LPT_NAME, }; static int 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(ppbus, dev, how)) == 0) sc->sc_state |= HAVEBUS; return (error); } static int lpt_release_ppbus(device_t dev) { device_t ppbus = device_get_parent(dev); struct lpt_data *sc = DEVTOSOFTC(dev); int error = 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(device_t ppbus, u_char data, u_char mask) { int temp, timeout; data = data & mask; ppb_wdtr(ppbus, data); timeout = 10000; do { DELAY(10); temp = ppb_rdtr(ppbus) & mask; } while (temp != data && --timeout); lprintf(("out=%x\tin=%x\ttout=%d\n", data, temp, timeout)); return (temp == data); } /* * Probe simplified by replacing multiple loops with a hardcoded * test pattern - 1999/02/08 des@freebsd.org * * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 * Based partially on Rod Grimes' printer probe * * Logic: * 1) If no port address was given, use the bios detected ports * and autodetect what ports the printers are on. * 2) Otherwise, probe the data port at the address given, * using the method in Rod Grimes' port probe. * (Much code ripped off directly from Rod's probe.) * * Comments from Rod's probe: * Logic: * 1) You should be able to write to and read back the same value * to the data port. Do an alternating zeros, alternating ones, * walking zero, and walking one test to check for stuck bits. * * 2) You should be able to write to and read back the same value * to the control port lower 5 bits, the upper 3 bits are reserved * per the IBM PC technical reference manauls and different boards * do different things with them. Do an alternating zeros, alternating * ones, walking zero, and walking one test to check for stuck bits. * * Some printers drag the strobe line down when the are powered off * so this bit has been masked out of the control port test. * * XXX Some printers may not like a fast pulse on init or strobe, I * don't know at this point, if that becomes a problem these bits * should be turned off in the mask byte for the control port test. * * We are finally left with a mask of 0x14, due to some printers * being adamant about holding other bits high ........ * * Before probing the control port, we write a 0 to the data port - * If not, some printers chuck out garbage when the strobe line * gets toggled. * * 3) Set the data and control ports to a value of 0 * * This probe routine has been tested on Epson Lx-800, HP LJ3P, * Epson FX-1170 and C.Itoh 8510RM * printers. * Quick exit on fail added. */ static int lpt_detect(device_t dev) { device_t ppbus = device_get_parent(dev); static u_char testbyte[18] = { 0x55, /* alternating zeros */ 0xaa, /* alternating ones */ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 /* walking one */ }; int i, error, status; status = 1; /* assume success */ 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(ppbus, testbyte[i], 0xff)) { status = 0; goto end_probe; } end_probe: /* write 0's to control and data ports */ ppb_wdtr(ppbus, 0); ppb_wctr(ppbus, 0); lpt_release_ppbus(dev); return (status); } static void lpt_identify(driver_t *driver, device_t parent) { device_t dev; dev = device_find_child(parent, LPT_NAME, 0); if (!dev) BUS_ADD_CHILD(parent, 0, LPT_NAME, -1); } /* * lpt_probe() */ static int lpt_probe(device_t dev) { if (!lpt_detect(dev)) return (ENXIO); device_set_desc(dev, "Printer"); return (0); } static int lpt_attach(device_t dev) { device_t ppbus = device_get_parent(dev); struct lpt_data *sc = DEVTOSOFTC(dev); int zero = 0, unit = device_get_unit(dev); int error; intptr_t irq; sc->sc_primed = 0; /* not primed yet */ if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); return (0); } ppb_wctr(ppbus, LPC_NINIT); /* check if we can use interrupt, should be done by ppc stuff */ lprintf(("oldirq %x\n", sc->sc_irq)); /* 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; device_printf(dev, "Interrupt-driven port\n"); } else { sc->sc_irq = 0; device_printf(dev, "Polled port\n"); } lprintf(("irq %x %x\n", (int)irq, sc->sc_irq)); lpt_release_ppbus(dev); 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) { 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(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)dev, sc->sc_backoff); } else sc->sc_state &= ~TOUT; if (sc->sc_state & EERROR) sc->sc_state &= ~EERROR; /* * Avoid possible hangs due to missed interrupts */ if (sc->sc_xfercnt) { lptintr(dev); } else { sc->sc_state &= ~OBUSY; wakeup(dev); } } /* * lptopen -- reset the printer, then wait until it's selected and not busy. * If LP_BYPASS flag is selected, then we do not try to select the * printer -- this is just used for passing ioctls. */ static int lptopen(struct cdev *dev, int flags, int fmt, struct thread *td) { 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 (!sc) return (ENXIO); if (sc->sc_state) { lprintf((LPT_NAME ": still open %x\n", sc->sc_state)); return(EBUSY); } else sc->sc_state |= LPTINIT; sc->sc_flags = LPTFLAGS(minor(dev)); /* Check for open with BYPASS flag set. */ if (sc->sc_flags & LP_BYPASS) { sc->sc_state = OPEN; return(0); } /* request the ppbus only if we don't have it already */ 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 */ if (sc->sc_irq & LP_ENABLE_IRQ) sc->sc_irq |= LP_USE_IRQ; else sc->sc_irq &= ~LP_USE_IRQ; /* init printer */ if ((sc->sc_flags & LP_NO_PRIME) == 0) { if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { ppb_wctr(ppbus, 0); sc->sc_primed++; DELAY(500); } } ppb_wctr(ppbus, LPC_SEL|LPC_NINIT); /* wait till ready (printer running diagnostics) */ trys = 0; do { /* ran out of waiting for the printer */ if (trys++ >= LPINITRDY*4) { splx(s); sc->sc_state = 0; lprintf(("status %x\n", ppb_rstr(ppbus))); lpt_release_ppbus(lptdev); return (EBUSY); } /* wait 1/4 second, give up if we get a signal */ if (tsleep(lptdev, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) { sc->sc_state = 0; splx(s); lpt_release_ppbus(lptdev); return (EBUSY); } /* is printer online and ready for output */ } while ((ppb_rstr(ppbus) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR)); sc->sc_control = LPC_SEL|LPC_NINIT; if (sc->sc_flags & LP_AUTOLF) sc->sc_control |= LPC_AUTOL; /* enable interrupt if interrupt-driven */ if (sc->sc_irq & LP_USE_IRQ) sc->sc_control |= LPC_ENA; ppb_wctr(ppbus, sc->sc_control); sc->sc_state = OPEN; sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); sc->sc_statbuf = malloc(BUFSTATSIZE, M_DEVBUF, M_WAITOK); sc->sc_xfercnt = 0; splx(s); /* release the ppbus */ 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)lptdev, (sc->sc_backoff = hz/LPTOUTINITIAL)); } lprintf(("opened.\n")); return(0); } /* * lptclose -- close the device, free the local line buffer. * * Check for interrupted write call added. */ static int lptclose(struct cdev *dev, int flags, int fmt, struct thread *td) { 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(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(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(lptdev, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK) break; ppb_wctr(ppbus, LPC_NINIT); free(sc->sc_inbuf, M_DEVBUF); free(sc->sc_statbuf, M_DEVBUF); end_close: /* release the bus anyway * unregistration of interrupt forced by release */ lpt_release_ppbus(lptdev); sc->sc_state = 0; sc->sc_xfercnt = 0; lprintf(("closed.\n")); return(0); } /* * lpt_pushbytes() * Workhorse for actually spinning and writing bytes to printer * Derived from lpa.c * Originally by ? * * This code is only used when we are polling the port */ static int lpt_pushbytes(device_t dev) { struct lpt_data *sc = DEVTOSOFTC(dev); device_t ppbus = device_get_parent(dev); int spin, err, tic; char ch; lprintf(("p")); /* loop for every character .. */ while (sc->sc_xfercnt > 0) { /* printer data */ ch = *(sc->sc_cp); sc->sc_cp++; sc->sc_xfercnt--; /* * Wait for printer ready. * Loop 20 usecs testing BUSY bit, then sleep * for exponentially increasing timeout. (vak) */ 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(ppbus)) { /* * Now sleep, every cycle a * little longer .. */ tic = tic + tic + 1; /* * But no more than 10 seconds. (vak) */ if (tic > MAX_SLEEP) tic = MAX_SLEEP; err = tsleep(dev, LPPRI, LPT_NAME "poll", tic); if (err != EWOULDBLOCK) { return (err); } } } /* output data */ ppb_wdtr(ppbus, ch); /* strobe */ ppb_wctr(ppbus, sc->sc_control|LPC_STB); ppb_wctr(ppbus, sc->sc_control); } return(0); } /* * lptread --retrieve printer status in IEEE1284 NIBBLE mode */ static int lptread(struct cdev *dev, struct uio *uio, int ioflag) { 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 (sc->sc_flags & LP_BYPASS) { /* we can't do reads in bypass mode */ return (EPERM); } 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(ppbus, PPB_NIBBLE, sc->sc_statbuf, min(BUFSTATSIZE, uio->uio_resid), &len))) { goto error; } if (!len) goto error; /* no more data */ if ((error = uiomove(sc->sc_statbuf, len, uio))) goto error; } error: ppb_1284_terminate(ppbus); return (error); } /* * lptwrite --copy a line from user space to a local buffer, then call * putc to get the chars moved to the output queue. * * Flagging of interrupted write added. */ static int lptwrite(struct cdev *dev, struct uio *uio, int ioflag) { register unsigned n; int 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(sc->sc_flags & LP_BYPASS) { /* we can't do writes in bypass mode */ return(EPERM); } /* request the ppbus only if we don't have it already */ /* 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; uiomove(sc->sc_cp, n, uio); sc->sc_xfercnt = n ; if (sc->sc_irq & LP_ENABLE_EXT) { /* try any extended mode */ err = ppb_write(ppbus, sc->sc_cp, sc->sc_xfercnt, 0); switch (err) { case 0: /* if not all data was sent, we could rely * on polling for the last bytes */ sc->sc_xfercnt = 0; break; case EINTR: sc->sc_state |= INTERRUPTED; return(err); case EINVAL: /* advanced mode not avail */ log(LOG_NOTICE, LPT_NAME "%d: advanced mode not avail, polling\n", unit); break; default: return(err); } } else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { lprintf(("i")); /* if the printer is ready for a char, */ /* give it one */ if ((sc->sc_state & OBUSY) == 0){ lprintf(("\nC %d. ", sc->sc_xfercnt)); lptintr(lptdev); } lprintf(("W ")); if (sc->sc_state & OBUSY) if ((err = tsleep(lptdev, LPPRI|PCATCH, LPT_NAME "write", 0))) { sc->sc_state |= INTERRUPTED; return(err); } } /* check to see if we must do a polled write */ if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { lprintf(("p")); err = lpt_pushbytes(lptdev); if (err) return(err); } } /* we have not been interrupted, release the ppbus */ lpt_release_ppbus(lptdev); return(0); } /* * lpt_intr -- handle printer interrupts which occur when the printer is * ready to accept another char. * * do checking for interrupted write call. */ static void lpt_intr(void *arg) { device_t lptdev = (device_t)arg; device_t ppbus = device_get_parent(lptdev); struct lpt_data *sc = DEVTOSOFTC(lptdev); int sts = 0; int i; /* we must own the bus to use it */ if ((sc->sc_state & HAVEBUS) == 0) return; /* * Is printer online and ready for output? * * Avoid falling back to lptout() too quickly. First spin-loop * to see if the printer will become ready ``really soon now''. */ for (i = 0; i < 100 && ((sts=ppb_rstr(ppbus)) & RDY_MASK) != LP_READY; i++) ; if ((sts & RDY_MASK) == LP_READY) { sc->sc_state = (sc->sc_state | OBUSY) & ~EERROR; sc->sc_backoff = hz/LPTOUTINITIAL; if (sc->sc_xfercnt) { /* send char */ /*lprintf(("%x ", *sc->sc_cp)); */ ppb_wdtr(ppbus, *sc->sc_cp++) ; ppb_wctr(ppbus, sc->sc_control|LPC_STB); /* DELAY(X) */ ppb_wctr(ppbus, sc->sc_control); /* any more data for printer */ if(--(sc->sc_xfercnt) > 0) return; } /* * No more data waiting for printer. * Wakeup is not done if write call was not interrupted. */ sc->sc_state &= ~OBUSY; if(!(sc->sc_state & INTERRUPTED)) wakeup(lptdev); lprintf(("w ")); return; } else { /* check for error */ if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) && (sc->sc_state & OPEN)) sc->sc_state |= EERROR; /* lptout() will jump in and try to restart. */ } lprintf(("sts %x ", sts)); } static void lptintr(device_t dev) { /* call the interrupt at required spl level */ int s = spltty(); lpt_intr(dev); splx(s); return; } static int lptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { int error = 0; u_int unit = LPTUNIT(minor(dev)); struct lpt_data *sc = UNITOSOFTC(unit); u_char old_sc_irq; /* old printer IRQ status */ switch (cmd) { case LPT_IRQ : if(sc->sc_irq & LP_HAS_IRQ) { /* * NOTE: * If the IRQ status is changed, * this will only be visible on the * next open. * * If interrupt status changes, * this gets syslog'd. */ old_sc_irq = sc->sc_irq; switch(*(int*)data) { case 0: sc->sc_irq &= (~LP_ENABLE_IRQ); break; case 1: sc->sc_irq &= (~LP_ENABLE_EXT); sc->sc_irq |= LP_ENABLE_IRQ; break; case 2: /* classic irq based transfer and advanced * modes are in conflict */ sc->sc_irq &= (~LP_ENABLE_IRQ); sc->sc_irq |= LP_ENABLE_EXT; break; case 3: sc->sc_irq &= (~LP_ENABLE_EXT); break; default: break; } if (old_sc_irq != sc->sc_irq ) log(LOG_NOTICE, LPT_NAME "%d: switched to %s %s mode\n", unit, (sc->sc_irq & LP_ENABLE_IRQ)? "interrupt-driven":"polled", (sc->sc_irq & LP_ENABLE_EXT)? "extended":"standard"); } else /* polled port */ error = EOPNOTSUPP; break; default: error = ENODEV; } return(error); } static device_method_t lpt_methods[] = { /* device interface */ DEVMETHOD(device_identify, lpt_identify), DEVMETHOD(device_probe, lpt_probe), DEVMETHOD(device_attach, lpt_attach), { 0, 0 } }; static driver_t lpt_driver = { LPT_NAME, lpt_methods, sizeof(struct lpt_data), }; DRIVER_MODULE(lpt, ppbus, lpt_driver, lpt_devclass, 0, 0); +MODULE_DEPEND(lpt, ppbus, 1, 1, 1); Index: stable/6/sys/dev/ppbus/ppi.c =================================================================== --- stable/6/sys/dev/ppbus/ppi.c (revision 160502) +++ stable/6/sys/dev/ppbus/ppi.c (revision 160503) @@ -1,577 +1,578 @@ /*- * Copyright (c) 1997, 1998, 1999 Nicolas Souchu, Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * */ #include __FBSDID("$FreeBSD$"); #include "opt_ppb_1284.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PERIPH_1284 #include #endif #include #include "ppbus_if.h" #include #define BUFSIZE 512 struct ppi_data { int ppi_unit; int ppi_flags; #define HAVE_PPBUS (1<<0) #define HAD_PPBUS (1<<1) int ppi_count; int ppi_mode; /* IEEE1284 mode */ char ppi_buffer[BUFSIZE]; #ifdef PERIPH_1284 struct resource *intr_resource; /* interrupt resource */ void *intr_cookie; /* interrupt registration cookie */ #endif /* PERIPH_1284 */ }; #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))) static devclass_t ppi_devclass; static d_open_t ppiopen; static d_close_t ppiclose; static d_ioctl_t ppiioctl; static d_write_t ppiwrite; static d_read_t ppiread; static struct cdevsw ppi_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, .d_open = ppiopen, .d_close = ppiclose, .d_read = ppiread, .d_write = ppiwrite, .d_ioctl = ppiioctl, .d_name = "ppi", }; #ifdef PERIPH_1284 static void ppi_enable_intr(device_t ppidev) { char r; device_t ppbus = device_get_parent(ppidev); r = ppb_rctr(ppbus); ppb_wctr(ppbus, r | IRQENABLE); return; } static void ppi_disable_intr(device_t ppidev) { char r; device_t ppbus = device_get_parent(ppidev); r = ppb_rctr(ppbus); ppb_wctr(ppbus, r & ~IRQENABLE); return; } #endif /* PERIPH_1284 */ static void ppi_identify(driver_t *driver, device_t parent) { device_t dev; dev = device_find_child(parent, "ppi", 0); if (!dev) BUS_ADD_CHILD(parent, 0, "ppi", -1); } /* * ppi_probe() */ static int ppi_probe(device_t dev) { struct ppi_data *ppi; /* probe is always ok */ device_set_desc(dev, "Parallel I/O"); ppi = DEVTOSOFTC(dev); return (0); } /* * ppi_attach() */ static int ppi_attach(device_t dev) { #ifdef PERIPH_1284 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); /* declare our interrupt handler */ ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1, RF_ACTIVE); #endif /* PERIPH_1284 */ make_dev(&ppi_cdevsw, device_get_unit(dev), /* XXX cleanup */ UID_ROOT, GID_WHEEL, 0600, "ppi%d", device_get_unit(dev)); return (0); } #ifdef PERIPH_1284 /* * Cable * ----- * * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks: * * nStrobe <-> nAck 1 <-> 10 * nAutofd <-> Busy 11 <-> 14 * nSelectin <-> Select 17 <-> 13 * nInit <-> nFault 15 <-> 16 * */ static void ppiintr(void *arg) { device_t ppidev = (device_t)arg; device_t ppbus = device_get_parent(ppidev); struct ppi_data *ppi = DEVTOSOFTC(ppidev); ppi_disable_intr(ppidev); switch (ppb_1284_get_state(ppbus)) { /* accept IEEE1284 negotiation then wakeup a waiting process to * continue negotiation at process level */ case PPB_FORWARD_IDLE: /* Event 1 */ if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) == (SELECT | nBUSY)) { /* IEEE1284 negotiation */ #ifdef DEBUG_1284 printf("N"); #endif /* Event 2 - prepare for reading the ext. value */ ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN); ppb_1284_set_state(ppbus, PPB_NEGOCIATION); } else { #ifdef DEBUG_1284 printf("0x%x", ppb_rstr(ppbus)); #endif ppb_peripheral_terminate(ppbus, PPB_DONTWAIT); break; } /* wake up any process waiting for negotiation from * remote master host */ /* XXX should set a variable to warn the process about * the interrupt */ wakeup(ppi); break; default: #ifdef DEBUG_1284 printf("?%d", ppb_1284_get_state(ppbus)); #endif ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE); ppb_set_mode(ppbus, PPB_COMPATIBLE); break; } ppi_enable_intr(ppidev); return; } #endif /* PERIPH_1284 */ static int ppiopen(struct cdev *dev, int flags, int fmt, struct thread *td) { u_int unit = minor(dev); struct ppi_data *ppi = UNITOSOFTC(unit); device_t ppidev = UNITODEVICE(unit); device_t ppbus = device_get_parent(ppidev); int res; if (!ppi) return (ENXIO); if (!(ppi->ppi_flags & HAVE_PPBUS)) { if ((res = ppb_request_bus(ppbus, ppidev, (flags & O_NONBLOCK) ? PPB_DONTWAIT : (PPB_WAIT | PPB_INTR)))) return (res); ppi->ppi_flags |= HAVE_PPBUS; #ifdef PERIPH_1284 if (ppi->intr_resource) { /* register our interrupt handler */ BUS_SETUP_INTR(device_get_parent(ppidev), ppidev, ppi->intr_resource, INTR_TYPE_TTY, ppiintr, dev, &ppi->intr_cookie); } #endif /* PERIPH_1284 */ } ppi->ppi_count += 1; return (0); } static int ppiclose(struct cdev *dev, int flags, int fmt, struct thread *td) { u_int unit = minor(dev); 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 (ppb_1284_get_state(ppbus)) { case PPB_PERIPHERAL_IDLE: ppb_peripheral_terminate(ppbus, 0); break; case PPB_REVERSE_IDLE: case PPB_EPP_IDLE: case PPB_ECP_FORWARD_IDLE: default: ppb_1284_terminate(ppbus); break; } #endif /* PERIPH_1284 */ /* unregistration of interrupt forced by release */ ppb_release_bus(ppbus, ppidev); ppi->ppi_flags &= ~HAVE_PPBUS; } return (0); } /* * ppiread() * * IEEE1284 compliant read. * * First, try negotiation to BYTE then NIBBLE mode * If no data is available, wait for it otherwise transfer as much as possible */ static int ppiread(struct cdev *dev, struct uio *uio, int ioflag) { #ifdef PERIPH_1284 u_int unit = minor(dev); struct ppi_data *ppi = UNITOSOFTC(unit); device_t ppidev = UNITODEVICE(unit); device_t ppbus = device_get_parent(ppidev); int len, error = 0; switch (ppb_1284_get_state(ppbus)) { case PPB_PERIPHERAL_IDLE: ppb_peripheral_terminate(ppbus, 0); /* FALLTHROUGH */ case PPB_FORWARD_IDLE: /* if can't negotiate NIBBLE mode then try BYTE mode, * the peripheral may be a computer */ if ((ppb_1284_negociate(ppbus, ppi->ppi_mode = PPB_NIBBLE, 0))) { /* XXX Wait 2 seconds to let the remote host some * time to terminate its interrupt */ tsleep(ppi, PPBPRI, "ppiread", 2*hz); if ((error = ppb_1284_negociate(ppbus, ppi->ppi_mode = PPB_BYTE, 0))) return (error); } break; case PPB_REVERSE_IDLE: case PPB_EPP_IDLE: case PPB_ECP_FORWARD_IDLE: default: break; } #ifdef DEBUG_1284 printf("N"); #endif /* read data */ len = 0; while (uio->uio_resid) { if ((error = ppb_1284_read(ppbus, ppi->ppi_mode, ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid), &len))) { goto error; } if (!len) goto error; /* no more data */ #ifdef DEBUG_1284 printf("d"); #endif if ((error = uiomove(ppi->ppi_buffer, len, uio))) goto error; } error: #else /* PERIPH_1284 */ int error = ENODEV; #endif return (error); } /* * ppiwrite() * * IEEE1284 compliant write * * Actually, this is the peripheral side of a remote IEEE1284 read * * The first part of the negotiation (IEEE1284 device detection) is * done at interrupt level, then the remaining is done by the writing * process * * Once negotiation done, transfer data */ static int ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) { #ifdef PERIPH_1284 u_int unit = minor(dev); 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 int ret; #define ADDRESS MS_PARAM(0, 0, MS_TYP_PTR) #define LENGTH MS_PARAM(0, 1, MS_TYP_INT) struct ppb_microseq msq[] = { { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } }, MS_RET(0) }; /* negotiate ECP mode */ if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) { printf("ppiwrite: ECP negotiation failed\n"); } while (!error && (len = min(uio->uio_resid, BUFSIZE))) { uiomove(ppi->ppi_buffer, len, uio); ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len); error = ppb_MS_microseq(ppbus, msq, &ret); } #endif /* we have to be peripheral to be able to send data, so * wait for the appropriate state */ if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION) ppb_1284_terminate(ppbus); while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) { /* XXX should check a variable before sleeping */ #ifdef DEBUG_1284 printf("s"); #endif ppi_enable_intr(ppidev); /* sleep until IEEE1284 negotiation starts */ error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0); switch (error) { case 0: /* negotiate peripheral side with BYTE mode */ ppb_peripheral_negociate(ppbus, PPB_BYTE, 0); break; case EWOULDBLOCK: break; default: goto error; } } #ifdef DEBUG_1284 printf("N"); #endif /* negotiation 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(ppbus, ppi->ppi_buffer, len, &sent))) goto error; #ifdef DEBUG_1284 printf("d"); #endif } error: #else /* PERIPH_1284 */ int error = ENODEV; #endif return (error); } static int ppiioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { u_int unit = minor(dev); 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(ppbus); break; case PPIGSTATUS: /* get status bits */ *val = ppb_rstr(ppbus); break; case PPIGCTRL: /* get control bits */ *val = ppb_rctr(ppbus); break; case PPIGEPPD: /* get EPP data bits */ *val = ppb_repp_D(ppbus); break; case PPIGECR: /* get ECP bits */ *val = ppb_recr(ppbus); break; case PPIGFIFO: /* read FIFO */ *val = ppb_rfifo(ppbus); break; case PPISDATA: /* set data register */ ppb_wdtr(ppbus, *val); break; case PPISSTATUS: /* set status bits */ ppb_wstr(ppbus, *val); break; case PPISCTRL: /* set control bits */ ppb_wctr(ppbus, *val); break; case PPISEPPD: /* set EPP data bits */ ppb_wepp_D(ppbus, *val); break; case PPISECR: /* set ECP bits */ ppb_wecr(ppbus, *val); break; case PPISFIFO: /* write FIFO */ ppb_wfifo(ppbus, *val); break; case PPIGEPPA: /* get EPP address bits */ *val = ppb_repp_A(ppbus); break; case PPISEPPA: /* set EPP address bits */ ppb_wepp_A(ppbus, *val); break; default: error = ENOTTY; break; } return (error); } static device_method_t ppi_methods[] = { /* device interface */ DEVMETHOD(device_identify, ppi_identify), DEVMETHOD(device_probe, ppi_probe), DEVMETHOD(device_attach, ppi_attach), { 0, 0 } }; static driver_t ppi_driver = { "ppi", ppi_methods, sizeof(struct ppi_data), }; DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0); +MODULE_DEPEND(ppi, ppbus, 1, 1, 1); Index: stable/6/sys/dev/ppbus/pps.c =================================================================== --- stable/6/sys/dev/ppbus/pps.c (revision 160502) +++ stable/6/sys/dev/ppbus/pps.c (revision 160503) @@ -1,323 +1,324 @@ /*- * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * * * This driver implements a draft-mogul-pps-api-02.txt PPS source. * * The input pin is pin#10 * The echo output pin is pin#14 * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "ppbus_if.h" #include #define PPS_NAME "pps" /* our official name */ #define PRVERBOSE(fmt, arg...) if (bootverbose) printf(fmt, ##arg); struct pps_data { struct ppb_device pps_dev; struct pps_state pps[9]; struct cdev *devs[9]; device_t ppsdev; device_t ppbus; int busy; struct callout_handle timeout; int lastdata; struct mtx mtx; struct resource *intr_resource; /* interrupt resource */ void *intr_cookie; /* interrupt registration cookie */ }; static void ppsintr(void *arg); static void ppshcpoll(void *arg); #define DEVTOSOFTC(dev) \ ((struct pps_data *)device_get_softc(dev)) static devclass_t pps_devclass; static d_open_t ppsopen; static d_close_t ppsclose; static d_ioctl_t ppsioctl; static struct cdevsw pps_cdevsw = { .d_version = D_VERSION, .d_open = ppsopen, .d_close = ppsclose, .d_ioctl = ppsioctl, .d_name = PPS_NAME, }; static void ppsidentify(driver_t *driver, device_t parent) { device_t dev; dev = device_find_child(parent, PPS_NAME, 0); if (!dev) BUS_ADD_CHILD(parent, 0, PPS_NAME, -1); } static int ppstry(device_t ppbus, int send, int expect) { int i; ppb_wdtr(ppbus, send); i = ppb_rdtr(ppbus); PRVERBOSE("S: %02x E: %02x G: %02x\n", send, expect, i); return (i != expect); } static int ppsprobe(device_t ppsdev) { device_set_desc(ppsdev, "Pulse per second Timing Interface"); return (0); } static int ppsattach(device_t dev) { struct pps_data *sc = DEVTOSOFTC(dev); device_t ppbus = device_get_parent(dev); struct cdev *d; intptr_t irq; int i, unit, zero = 0; mtx_init(&sc->mtx, device_get_nameunit(dev), "pps", MTX_SPIN); /* 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); } /* interrupts seem mandatory */ if (sc->intr_resource == NULL) return (ENXIO); sc->ppsdev = dev; sc->ppbus = ppbus; unit = device_get_unit(ppbus); d = make_dev(&pps_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", unit); sc->devs[0] = d; sc->pps[0].ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; d->si_drv1 = sc; d->si_drv2 = (void*)0; pps_init(&sc->pps[0]); if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) return (0); do { i = ppb_set_mode(sc->ppbus, PPB_EPP); PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); if (i == -1) break; i = 0; ppb_wctr(ppbus, i); if (ppstry(ppbus, 0x00, 0x00)) break; if (ppstry(ppbus, 0x55, 0x55)) break; if (ppstry(ppbus, 0xaa, 0xaa)) break; if (ppstry(ppbus, 0xff, 0xff)) break; i = IRQENABLE | PCD | STROBE | nINIT | SELECTIN; ppb_wctr(ppbus, i); PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); if (ppstry(ppbus, 0x00, 0x00)) break; if (ppstry(ppbus, 0x55, 0x00)) break; if (ppstry(ppbus, 0xaa, 0x00)) break; if (ppstry(ppbus, 0xff, 0x00)) break; i = IRQENABLE | PCD | nINIT | SELECTIN; ppb_wctr(ppbus, i); PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); ppstry(ppbus, 0x00, 0xff); ppstry(ppbus, 0x55, 0xff); ppstry(ppbus, 0xaa, 0xff); ppstry(ppbus, 0xff, 0xff); for (i = 1; i < 9; i++) { d = make_dev(&pps_cdevsw, unit + 0x10000 * i, UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%db%d", unit, i - 1); sc->devs[i] = d; sc->pps[i].ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; d->si_drv1 = sc; d->si_drv2 = (void *)(intptr_t)i; pps_init(&sc->pps[i]); } } while (0); i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE); ppb_release_bus(ppbus, dev); return (0); } static int ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td) { struct pps_data *sc = dev->si_drv1; int subdev = (intptr_t)dev->si_drv2; int error, i; if (!sc->busy) { device_t ppsdev = sc->ppsdev; device_t ppbus = sc->ppbus; if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) return (EINTR); /* attach the interrupt handler */ if ((error = bus_setup_intr(ppsdev, sc->intr_resource, (INTR_TYPE_TTY | INTR_MPSAFE | INTR_FAST), ppsintr, sc, &sc->intr_cookie))) { ppb_release_bus(ppbus, ppsdev); return (error); } i = ppb_set_mode(sc->ppbus, PPB_PS2); PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); i = IRQENABLE | PCD | nINIT | SELECTIN; ppb_wctr(ppbus, i); } if (subdev > 0 && !(sc->busy & ~1)) { sc->timeout = timeout(ppshcpoll, sc, 1); sc->lastdata = ppb_rdtr(sc->ppbus); } sc->busy |= (1 << subdev); return(0); } static int ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td) { struct pps_data *sc = dev->si_drv1; int subdev = (intptr_t)dev->si_drv2; sc->pps[subdev].ppsparam.mode = 0; /* PHK ??? */ sc->busy &= ~(1 << subdev); if (subdev > 0 && !(sc->busy & ~1)) untimeout(ppshcpoll, sc, sc->timeout); if (!sc->busy) { device_t ppsdev = sc->ppsdev; device_t ppbus = sc->ppbus; ppb_wdtr(ppbus, 0); ppb_wctr(ppbus, 0); /* Note: the interrupt handler is automatically detached */ ppb_set_mode(ppbus, PPB_COMPATIBLE); ppb_release_bus(ppbus, ppsdev); } return(0); } static void ppshcpoll(void *arg) { struct pps_data *sc = arg; int i, j, k, l; if (!(sc->busy & ~1)) return; mtx_lock_spin(&sc->mtx); sc->timeout = timeout(ppshcpoll, sc, 1); i = ppb_rdtr(sc->ppbus); if (i == sc->lastdata) return; l = sc->lastdata ^ i; k = 1; for (j = 1; j < 9; j ++) { if (l & k) { pps_capture(&sc->pps[j]); pps_event(&sc->pps[j], i & k ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); } k += k; } sc->lastdata = i; mtx_unlock_spin(&sc->mtx); } static void ppsintr(void *arg) { struct pps_data *sc = (struct pps_data *)arg; pps_capture(&sc->pps[0]); if (!(ppb_rstr(sc->ppbus) & nACK)) return; if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(sc->ppbus, IRQENABLE | AUTOFEED); mtx_lock_spin(&sc->mtx); pps_event(&sc->pps[0], PPS_CAPTUREASSERT); mtx_unlock_spin(&sc->mtx); if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(sc->ppbus, IRQENABLE); } static int ppsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { struct pps_data *sc = dev->si_drv1; int subdev = (intptr_t)dev->si_drv2; int err; mtx_lock_spin(&sc->mtx); err = pps_ioctl(cmd, data, &sc->pps[subdev]); mtx_unlock_spin(&sc->mtx); return (err); } static device_method_t pps_methods[] = { /* device interface */ DEVMETHOD(device_identify, ppsidentify), DEVMETHOD(device_probe, ppsprobe), DEVMETHOD(device_attach, ppsattach), { 0, 0 } }; static driver_t pps_driver = { PPS_NAME, pps_methods, sizeof(struct pps_data), }; DRIVER_MODULE(pps, ppbus, pps_driver, pps_devclass, 0, 0); +MODULE_DEPEND(pps, ppbus, 1, 1, 1); Index: stable/6/sys/dev/ppc/ppc.c =================================================================== --- stable/6/sys/dev/ppc/ppc.c (revision 160502) +++ stable/6/sys/dev/ppc/ppc.c (revision 160503) @@ -1,2155 +1,2156 @@ /*- * Copyright (c) 1997-2000 Nicolas Souchu * Copyright (c) 2001 Alcove - Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_ppc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ppbus_if.h" static int ppc_isa_probe(device_t dev); static void ppcintr(void *arg); #define LOG_PPC(function, ppc, string) \ if (bootverbose) printf("%s: %s\n", function, string) #define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev)) devclass_t ppc_devclass; static device_method_t ppc_methods[] = { /* device interface */ DEVMETHOD(device_probe, ppc_isa_probe), DEVMETHOD(device_attach, ppc_attach), /* bus interface */ DEVMETHOD(bus_read_ivar, ppc_read_ivar), DEVMETHOD(bus_setup_intr, ppc_setup_intr), DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), /* ppbus interface */ DEVMETHOD(ppbus_io, ppc_io), DEVMETHOD(ppbus_exec_microseq, ppc_exec_microseq), DEVMETHOD(ppbus_reset_epp, ppc_reset_epp), DEVMETHOD(ppbus_setmode, ppc_setmode), DEVMETHOD(ppbus_ecp_sync, ppc_ecp_sync), DEVMETHOD(ppbus_read, ppc_read), DEVMETHOD(ppbus_write, ppc_write), { 0, 0 } }; static driver_t ppc_driver = { "ppc", ppc_methods, sizeof(struct ppc_data), }; static char *ppc_models[] = { "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", "SMC FDC37C935", "PC87303", 0 }; /* list of available modes */ static char *ppc_avms[] = { "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 }; /* list of current executing modes * Note that few modes do not actually exist. */ static char *ppc_modes[] = { "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", "EPP", "EPP", "EPP", "ECP", "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 }; static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; #ifdef __i386__ /* * BIOS printer list - used by BIOS probe. */ #define BIOS_PPC_PORTS 0x408 #define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) #define BIOS_MAX_PPC 4 #endif /* * ppc_ecp_sync() XXX */ void ppc_ecp_sync(device_t dev) { int i, r; struct ppc_data *ppc = DEVTOSOFTC(dev); if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) return; r = r_ecr(ppc); if ((r & 0xe0) != PPC_ECR_EPP) return; for (i = 0; i < 100; i++) { r = r_ecr(ppc); if (r & 0x1) return; DELAY(100); } printf("ppc%d: ECP sync failed as data still " \ "present in FIFO.\n", ppc->ppc_unit); return; } /* * ppc_detect_fifo() * * Detect parallel port FIFO */ static int ppc_detect_fifo(struct ppc_data *ppc) { char ecr_sav; char ctr_sav, ctr, cc; short i; /* save registers */ ecr_sav = r_ecr(ppc); ctr_sav = r_ctr(ppc); /* enter ECP configuration mode, no interrupt, no DMA */ w_ecr(ppc, 0xf4); /* read PWord size - transfers in FIFO mode must be PWord aligned */ ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); /* XXX 16 and 32 bits implementations not supported */ if (ppc->ppc_pword != PPC_PWORD_8) { LOG_PPC(__func__, ppc, "PWord not supported"); goto error; } w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ ctr = r_ctr(ppc); w_ctr(ppc, ctr | PCD); /* set direction to 1 */ /* enter ECP test mode, no interrupt, no DMA */ w_ecr(ppc, 0xd4); /* flush the FIFO */ for (i=0; i<1024; i++) { if (r_ecr(ppc) & PPC_FIFO_EMPTY) break; cc = r_fifo(ppc); } if (i >= 1024) { LOG_PPC(__func__, ppc, "can't flush FIFO"); goto error; } /* enable interrupts, no DMA */ w_ecr(ppc, 0xd0); /* determine readIntrThreshold * fill the FIFO until serviceIntr is set */ for (i=0; i<1024; i++) { w_fifo(ppc, (char)i); if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { /* readThreshold reached */ ppc->ppc_rthr = i+1; } if (r_ecr(ppc) & PPC_FIFO_FULL) { ppc->ppc_fifo = i+1; break; } } if (i >= 1024) { LOG_PPC(__func__, ppc, "can't fill FIFO"); goto error; } w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ w_ecr(ppc, 0xd0); /* enable interrupts */ /* determine writeIntrThreshold * empty the FIFO until serviceIntr is set */ for (i=ppc->ppc_fifo; i>0; i--) { if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { LOG_PPC(__func__, ppc, "invalid data in FIFO"); goto error; } if (r_ecr(ppc) & PPC_SERVICE_INTR) { /* writeIntrThreshold reached */ ppc->ppc_wthr = ppc->ppc_fifo - i+1; } /* if FIFO empty before the last byte, error */ if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { LOG_PPC(__func__, ppc, "data lost in FIFO"); goto error; } } /* FIFO must be empty after the last byte */ if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { LOG_PPC(__func__, ppc, "can't empty the FIFO"); goto error; } w_ctr(ppc, ctr_sav); w_ecr(ppc, ecr_sav); return (0); error: w_ctr(ppc, ctr_sav); w_ecr(ppc, ecr_sav); return (EINVAL); } static int ppc_detect_port(struct ppc_data *ppc) { w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ w_dtr(ppc, 0xaa); if (r_dtr(ppc) != 0xaa) return (0); return (1); } /* * EPP timeout, according to the PC87332 manual * Semantics of clearing EPP timeout bit. * PC87332 - reading SPP_STR does it... * SMC - write 1 to EPP timeout bit XXX * Others - (?) write 0 to EPP timeout bit */ static void ppc_reset_epp_timeout(struct ppc_data *ppc) { register char r; r = r_str(ppc); w_str(ppc, r | 0x1); w_str(ppc, r & 0xfe); return; } static int ppc_check_epp_timeout(struct ppc_data *ppc) { ppc_reset_epp_timeout(ppc); return (!(r_str(ppc) & TIMEOUT)); } /* * Configure current operating mode */ static int ppc_generic_setmode(struct ppc_data *ppc, int mode) { u_char ecr = 0; /* check if mode is available */ if (mode && !(ppc->ppc_avm & mode)) return (EINVAL); /* if ECP mode, configure ecr register */ if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { /* return to byte mode (keeping direction bit), * no interrupt, no DMA to be able to change to * ECP */ w_ecr(ppc, PPC_ECR_RESET); ecr = PPC_DISABLE_INTR; if (mode & PPB_EPP) return (EINVAL); else if (mode & PPB_ECP) /* select ECP mode */ ecr |= PPC_ECR_ECP; else if (mode & PPB_PS2) /* select PS2 mode with ECP */ ecr |= PPC_ECR_PS2; else /* select COMPATIBLE/NIBBLE mode */ ecr |= PPC_ECR_STD; w_ecr(ppc, ecr); } ppc->ppc_mode = mode; return (0); } /* * The ppc driver is free to choose options like FIFO or DMA * if ECP mode is available. * * The 'RAW' option allows the upper drivers to force the ppc mode * even with FIFO, DMA available. */ static int ppc_smclike_setmode(struct ppc_data *ppc, int mode) { u_char ecr = 0; /* check if mode is available */ if (mode && !(ppc->ppc_avm & mode)) return (EINVAL); /* if ECP mode, configure ecr register */ if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) { /* return to byte mode (keeping direction bit), * no interrupt, no DMA to be able to change to * ECP or EPP mode */ w_ecr(ppc, PPC_ECR_RESET); ecr = PPC_DISABLE_INTR; if (mode & PPB_EPP) /* select EPP mode */ ecr |= PPC_ECR_EPP; else if (mode & PPB_ECP) /* select ECP mode */ ecr |= PPC_ECR_ECP; else if (mode & PPB_PS2) /* select PS2 mode with ECP */ ecr |= PPC_ECR_PS2; else /* select COMPATIBLE/NIBBLE mode */ ecr |= PPC_ECR_STD; w_ecr(ppc, ecr); } ppc->ppc_mode = mode; return (0); } #ifdef PPC_PROBE_CHIPSET /* * ppc_pc873xx_detect * * Probe for a Natsemi PC873xx-family part. * * References in this function are to the National Semiconductor * PC87332 datasheet TL/C/11930, May 1995 revision. */ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; static int pc873xx_irqtab[] = {5, 7, 5, 0}; static int pc873xx_regstab[] = { PC873_FER, PC873_FAR, PC873_PTR, PC873_FCR, PC873_PCR, PC873_PMC, PC873_TUP, PC873_SID, PC873_PNP0, PC873_PNP1, PC873_LPTBA, -1 }; static char *pc873xx_rnametab[] = { "FER", "FAR", "PTR", "FCR", "PCR", "PMC", "TUP", "SID", "PNP0", "PNP1", "LPTBA", NULL }; static int ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ { static int index = 0; int idport, irq; int ptr, pcr, val, i; while ((idport = pc873xx_basetab[index++])) { /* XXX should check first to see if this location is already claimed */ /* * Pull the 873xx through the power-on ID cycle (2.2,1.). * We can't use this to locate the chip as it may already have * been used by the BIOS. */ (void)inb(idport); (void)inb(idport); (void)inb(idport); (void)inb(idport); /* * Read the SID byte. Possible values are : * * 01010xxx PC87334 * 0001xxxx PC87332 * 01110xxx PC87306 * 00110xxx PC87303 */ outb(idport, PC873_SID); val = inb(idport + 1); if ((val & 0xf0) == 0x10) { ppc->ppc_model = NS_PC87332; } else if ((val & 0xf8) == 0x70) { ppc->ppc_model = NS_PC87306; } else if ((val & 0xf8) == 0x50) { ppc->ppc_model = NS_PC87334; } else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the documentation, but probing yielded 0x40... */ ppc->ppc_model = NS_PC87303; } else { if (bootverbose && (val != 0xff)) printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); continue ; /* not recognised */ } /* print registers */ if (bootverbose) { printf("PC873xx"); for (i=0; pc873xx_regstab[i] != -1; i++) { outb(idport, pc873xx_regstab[i]); printf(" %s=0x%x", pc873xx_rnametab[i], inb(idport + 1) & 0xff); } printf("\n"); } /* * We think we have one. Is it enabled and where we want it to be? */ outb(idport, PC873_FER); val = inb(idport + 1); if (!(val & PC873_PPENABLE)) { if (bootverbose) printf("PC873xx parallel port disabled\n"); continue; } outb(idport, PC873_FAR); val = inb(idport + 1); /* XXX we should create a driver instance for every port found */ if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) { /* First try to change the port address to that requested... */ switch(ppc->ppc_base) { case 0x378: val &= 0xfc; break; case 0x3bc: val &= 0xfd; break; case 0x278: val &= 0xfe; break; default: val &= 0xfd; break; } outb(idport, PC873_FAR); outb(idport + 1, val); outb(idport + 1, val); /* Check for success by reading back the value we supposedly wrote and comparing...*/ outb(idport, PC873_FAR); val = inb(idport + 1) & 0x3; /* If we fail, report the failure... */ if (pc873xx_porttab[val] != ppc->ppc_base) { if (bootverbose) printf("PC873xx at 0x%x not for driver at port 0x%x\n", pc873xx_porttab[val], ppc->ppc_base); } continue; } outb(idport, PC873_PTR); ptr = inb(idport + 1); /* get irq settings */ if (ppc->ppc_base == 0x378) irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; else irq = pc873xx_irqtab[val]; if (bootverbose) printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); /* * Check if irq settings are correct */ if (irq != ppc->ppc_irq) { /* * If the chipset is not locked and base address is 0x378, * we have another chance */ if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { if (ppc->ppc_irq == 7) { outb(idport + 1, (ptr | PC873_LPTBIRQ7)); outb(idport + 1, (ptr | PC873_LPTBIRQ7)); } else { outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); } if (bootverbose) printf("PC873xx irq set to %d\n", ppc->ppc_irq); } else { if (bootverbose) printf("PC873xx sorry, can't change irq setting\n"); } } else { if (bootverbose) printf("PC873xx irq settings are correct\n"); } outb(idport, PC873_PCR); pcr = inb(idport + 1); if ((ptr & PC873_CFGLOCK) || !chipset_mode) { if (bootverbose) printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); ppc->ppc_avm |= PPB_NIBBLE; if (bootverbose) printf(", NIBBLE"); if (pcr & PC873_EPPEN) { ppc->ppc_avm |= PPB_EPP; if (bootverbose) printf(", EPP"); if (pcr & PC873_EPP19) ppc->ppc_epp = EPP_1_9; else ppc->ppc_epp = EPP_1_7; if ((ppc->ppc_model == NS_PC87332) && bootverbose) { outb(idport, PC873_PTR); ptr = inb(idport + 1); if (ptr & PC873_EPPRDIR) printf(", Regular mode"); else printf(", Automatic mode"); } } else if (pcr & PC873_ECPEN) { ppc->ppc_avm |= PPB_ECP; if (bootverbose) printf(", ECP"); if (pcr & PC873_ECPCLK) { /* XXX */ ppc->ppc_avm |= PPB_PS2; if (bootverbose) printf(", PS/2"); } } else { outb(idport, PC873_PTR); ptr = inb(idport + 1); if (ptr & PC873_EXTENDED) { ppc->ppc_avm |= PPB_SPP; if (bootverbose) printf(", SPP"); } } } else { if (bootverbose) printf("PC873xx unlocked"); if (chipset_mode & PPB_ECP) { if ((chipset_mode & PPB_EPP) && bootverbose) printf(", ECP+EPP not supported"); pcr &= ~PC873_EPPEN; pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ outb(idport + 1, pcr); outb(idport + 1, pcr); if (bootverbose) printf(", ECP"); } else if (chipset_mode & PPB_EPP) { pcr &= ~(PC873_ECPEN | PC873_ECPCLK); pcr |= (PC873_EPPEN | PC873_EPP19); outb(idport + 1, pcr); outb(idport + 1, pcr); ppc->ppc_epp = EPP_1_9; /* XXX */ if (bootverbose) printf(", EPP1.9"); /* enable automatic direction turnover */ if (ppc->ppc_model == NS_PC87332) { outb(idport, PC873_PTR); ptr = inb(idport + 1); ptr &= ~PC873_EPPRDIR; outb(idport + 1, ptr); outb(idport + 1, ptr); if (bootverbose) printf(", Automatic mode"); } } else { pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); outb(idport + 1, pcr); outb(idport + 1, pcr); /* configure extended bit in PTR */ outb(idport, PC873_PTR); ptr = inb(idport + 1); if (chipset_mode & PPB_PS2) { ptr |= PC873_EXTENDED; if (bootverbose) printf(", PS/2"); } else { /* default to NIBBLE mode */ ptr &= ~PC873_EXTENDED; if (bootverbose) printf(", NIBBLE"); } outb(idport + 1, ptr); outb(idport + 1, ptr); } ppc->ppc_avm = chipset_mode; } if (bootverbose) printf("\n"); ppc->ppc_type = PPC_TYPE_GENERIC; ppc_generic_setmode(ppc, chipset_mode); return(chipset_mode); } return(-1); } /* * ppc_smc37c66xgt_detect * * SMC FDC37C66xGT configuration. */ static int ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) { int s, i; u_char r; int type = -1; int csr = SMC66x_CSR; /* initial value is 0x3F0 */ int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; #define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ /* * Detection: enter configuration mode and read CRD register. */ s = splhigh(); outb(csr, SMC665_iCODE); outb(csr, SMC665_iCODE); splx(s); outb(csr, 0xd); if (inb(cio) == 0x65) { type = SMC_37C665GT; goto config; } for (i = 0; i < 2; i++) { s = splhigh(); outb(csr, SMC666_iCODE); outb(csr, SMC666_iCODE); splx(s); outb(csr, 0xd); if (inb(cio) == 0x66) { type = SMC_37C666GT; break; } /* Another chance, CSR may be hard-configured to be at 0x370 */ csr = SMC666_CSR; } config: /* * If chipset not found, do not continue. */ if (type == -1) return (-1); /* select CR1 */ outb(csr, 0x1); /* read the port's address: bits 0 and 1 of CR1 */ r = inb(cio) & SMC_CR1_ADDR; if (port_address[(int)r] != ppc->ppc_base) return (-1); ppc->ppc_model = type; /* * CR1 and CR4 registers bits 3 and 0/1 for mode configuration * If SPP mode is detected, try to set ECP+EPP mode */ if (bootverbose) { outb(csr, 0x1); printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, inb(cio) & 0xff); outb(csr, 0x4); printf(" CR4=0x%x", inb(cio) & 0xff); } /* select CR1 */ outb(csr, 0x1); if (!chipset_mode) { /* autodetect mode */ /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ if (type == SMC_37C666GT) { ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; if (bootverbose) printf(" configuration hardwired, supposing " \ "ECP+EPP SPP"); } else if ((inb(cio) & SMC_CR1_MODE) == 0) { /* already in extended parallel port mode, read CR4 */ outb(csr, 0x4); r = (inb(cio) & SMC_CR4_EMODE); switch (r) { case SMC_SPP: ppc->ppc_avm |= PPB_SPP; if (bootverbose) printf(" SPP"); break; case SMC_EPPSPP: ppc->ppc_avm |= PPB_EPP | PPB_SPP; if (bootverbose) printf(" EPP SPP"); break; case SMC_ECP: ppc->ppc_avm |= PPB_ECP | PPB_SPP; if (bootverbose) printf(" ECP SPP"); break; case SMC_ECPEPP: ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; if (bootverbose) printf(" ECP+EPP SPP"); break; } } else { /* not an extended port mode */ ppc->ppc_avm |= PPB_SPP; if (bootverbose) printf(" SPP"); } } else { /* mode forced */ ppc->ppc_avm = chipset_mode; /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ if (type == SMC_37C666GT) goto end_detect; r = inb(cio); if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { /* do not use ECP when the mode is not forced to */ outb(cio, r | SMC_CR1_MODE); if (bootverbose) printf(" SPP"); } else { /* an extended mode is selected */ outb(cio, r & ~SMC_CR1_MODE); /* read CR4 register and reset mode field */ outb(csr, 0x4); r = inb(cio) & ~SMC_CR4_EMODE; if (chipset_mode & PPB_ECP) { if (chipset_mode & PPB_EPP) { outb(cio, r | SMC_ECPEPP); if (bootverbose) printf(" ECP+EPP"); } else { outb(cio, r | SMC_ECP); if (bootverbose) printf(" ECP"); } } else { /* PPB_EPP is set */ outb(cio, r | SMC_EPPSPP); if (bootverbose) printf(" EPP SPP"); } } ppc->ppc_avm = chipset_mode; } /* set FIFO threshold to 16 */ if (ppc->ppc_avm & PPB_ECP) { /* select CRA */ outb(csr, 0xa); outb(cio, 16); } end_detect: if (bootverbose) printf ("\n"); if (ppc->ppc_avm & PPB_EPP) { /* select CR4 */ outb(csr, 0x4); r = inb(cio); /* * Set the EPP protocol... * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 */ if (ppc->ppc_epp == EPP_1_9) outb(cio, (r & ~SMC_CR4_EPPTYPE)); else outb(cio, (r | SMC_CR4_EPPTYPE)); } /* end config mode */ outb(csr, 0xaa); ppc->ppc_type = PPC_TYPE_SMCLIKE; ppc_smclike_setmode(ppc, chipset_mode); return (chipset_mode); } /* * SMC FDC37C935 configuration * Found on many Alpha machines */ static int ppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode) { int s; int type = -1; s = splhigh(); outb(SMC935_CFG, 0x55); /* enter config mode */ outb(SMC935_CFG, 0x55); splx(s); outb(SMC935_IND, SMC935_ID); /* check device id */ if (inb(SMC935_DAT) == 0x2) type = SMC_37C935; if (type == -1) { outb(SMC935_CFG, 0xaa); /* exit config mode */ return (-1); } ppc->ppc_model = type; outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */ outb(SMC935_DAT, 3); /* which is logical device 3 */ /* set io port base */ outb(SMC935_IND, SMC935_PORTHI); outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8)); outb(SMC935_IND, SMC935_PORTLO); outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff)); if (!chipset_mode) ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */ else { ppc->ppc_avm = chipset_mode; outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */ /* SPP + EPP or just plain SPP */ if (chipset_mode & (PPB_SPP)) { if (chipset_mode & PPB_EPP) { if (ppc->ppc_epp == EPP_1_9) { outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_EPP19SPP); } if (ppc->ppc_epp == EPP_1_7) { outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_EPP17SPP); } } else { outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_SPP); } } /* ECP + EPP or just plain ECP */ if (chipset_mode & PPB_ECP) { if (chipset_mode & PPB_EPP) { if (ppc->ppc_epp == EPP_1_9) { outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_ECPEPP19); } if (ppc->ppc_epp == EPP_1_7) { outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_ECPEPP17); } } else { outb(SMC935_IND, SMC935_PPMODE); outb(SMC935_DAT, SMC935_ECP); } } } outb(SMC935_CFG, 0xaa); /* exit config mode */ ppc->ppc_type = PPC_TYPE_SMCLIKE; ppc_smclike_setmode(ppc, chipset_mode); return (chipset_mode); } /* * Winbond W83877F stuff * * EFER: extended function enable register * EFIR: extended function index register * EFDR: extended function data register */ #define efir ((efer == 0x250) ? 0x251 : 0x3f0) #define efdr ((efer == 0x250) ? 0x252 : 0x3f1) static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; static int w83877f_keyiter[] = { 1, 2, 2, 1 }; static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; static int ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) { int i, j, efer; unsigned char r, hefere, hefras; for (i = 0; i < 4; i ++) { /* first try to enable configuration registers */ efer = w83877f_efers[i]; /* write the key to the EFER */ for (j = 0; j < w83877f_keyiter[i]; j ++) outb (efer, w83877f_keys[i]); /* then check HEFERE and HEFRAS bits */ outb (efir, 0x0c); hefere = inb(efdr) & WINB_HEFERE; outb (efir, 0x16); hefras = inb(efdr) & WINB_HEFRAS; /* * HEFRAS HEFERE * 0 1 write 89h to 250h (power-on default) * 1 0 write 86h twice to 3f0h * 1 1 write 87h twice to 3f0h * 0 0 write 88h to 250h */ if ((hefere | hefras) == w83877f_hefs[i]) goto found; } return (-1); /* failed */ found: /* check base port address - read from CR23 */ outb(efir, 0x23); if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ return (-1); /* read CHIP ID from CR9/bits0-3 */ outb(efir, 0x9); switch (inb(efdr) & WINB_CHIPID) { case WINB_W83877F_ID: ppc->ppc_model = WINB_W83877F; break; case WINB_W83877AF_ID: ppc->ppc_model = WINB_W83877AF; break; default: ppc->ppc_model = WINB_UNKNOWN; } if (bootverbose) { /* dump of registers */ printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); for (i = 0; i <= 0xd; i ++) { outb(efir, i); printf("0x%x ", inb(efdr)); } for (i = 0x10; i <= 0x17; i ++) { outb(efir, i); printf("0x%x ", inb(efdr)); } outb(efir, 0x1e); printf("0x%x ", inb(efdr)); for (i = 0x20; i <= 0x29; i ++) { outb(efir, i); printf("0x%x ", inb(efdr)); } printf("\n"); printf("ppc%d:", ppc->ppc_unit); } ppc->ppc_type = PPC_TYPE_GENERIC; if (!chipset_mode) { /* autodetect mode */ /* select CR0 */ outb(efir, 0x0); r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); /* select CR9 */ outb(efir, 0x9); r |= (inb(efdr) & WINB_PRTMODS2); switch (r) { case WINB_W83757: if (bootverbose) printf("ppc%d: W83757 compatible mode\n", ppc->ppc_unit); return (-1); /* generic or SMC-like */ case WINB_EXTFDC: case WINB_EXTADP: case WINB_EXT2FDD: case WINB_JOYSTICK: if (bootverbose) printf(" not in parallel port mode\n"); return (-1); case (WINB_PARALLEL | WINB_EPP_SPP): ppc->ppc_avm |= PPB_EPP | PPB_SPP; if (bootverbose) printf(" EPP SPP"); break; case (WINB_PARALLEL | WINB_ECP): ppc->ppc_avm |= PPB_ECP | PPB_SPP; if (bootverbose) printf(" ECP SPP"); break; case (WINB_PARALLEL | WINB_ECP_EPP): ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP SPP"); break; default: printf("%s: unknown case (0x%x)!\n", __func__, r); } } else { /* mode forced */ /* select CR9 and set PRTMODS2 bit */ outb(efir, 0x9); outb(efdr, inb(efdr) & ~WINB_PRTMODS2); /* select CR0 and reset PRTMODSx bits */ outb(efir, 0x0); outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); if (chipset_mode & PPB_ECP) { if (chipset_mode & PPB_EPP) { outb(efdr, inb(efdr) | WINB_ECP_EPP); if (bootverbose) printf(" ECP+EPP"); ppc->ppc_type = PPC_TYPE_SMCLIKE; } else { outb(efdr, inb(efdr) | WINB_ECP); if (bootverbose) printf(" ECP"); } } else { /* select EPP_SPP otherwise */ outb(efdr, inb(efdr) | WINB_EPP_SPP); if (bootverbose) printf(" EPP SPP"); } ppc->ppc_avm = chipset_mode; } if (bootverbose) printf("\n"); /* exit configuration mode */ outb(efer, 0xaa); switch (ppc->ppc_type) { case PPC_TYPE_SMCLIKE: ppc_smclike_setmode(ppc, chipset_mode); break; default: ppc_generic_setmode(ppc, chipset_mode); break; } return (chipset_mode); } #endif /* * ppc_generic_detect */ static int ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) { /* default to generic */ ppc->ppc_type = PPC_TYPE_GENERIC; if (bootverbose) printf("ppc%d:", ppc->ppc_unit); /* first, check for ECP */ w_ecr(ppc, PPC_ECR_PS2); if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { ppc->ppc_dtm |= PPB_ECP | PPB_SPP; if (bootverbose) printf(" ECP SPP"); /* search for SMC style ECP+EPP mode */ w_ecr(ppc, PPC_ECR_EPP); } /* try to reset EPP timeout bit */ if (ppc_check_epp_timeout(ppc)) { ppc->ppc_dtm |= PPB_EPP; if (ppc->ppc_dtm & PPB_ECP) { /* SMC like chipset found */ ppc->ppc_model = SMC_LIKE; ppc->ppc_type = PPC_TYPE_SMCLIKE; if (bootverbose) printf(" ECP+EPP"); } else { if (bootverbose) printf(" EPP"); } } else { /* restore to standard mode */ w_ecr(ppc, PPC_ECR_STD); } /* XXX try to detect NIBBLE and PS2 modes */ ppc->ppc_dtm |= PPB_NIBBLE; if (bootverbose) printf(" SPP"); if (chipset_mode) ppc->ppc_avm = chipset_mode; else ppc->ppc_avm = ppc->ppc_dtm; if (bootverbose) printf("\n"); switch (ppc->ppc_type) { case PPC_TYPE_SMCLIKE: ppc_smclike_setmode(ppc, chipset_mode); break; default: ppc_generic_setmode(ppc, chipset_mode); break; } return (chipset_mode); } /* * ppc_detect() * * mode is the mode suggested at boot */ static int ppc_detect(struct ppc_data *ppc, int chipset_mode) { #ifdef PPC_PROBE_CHIPSET int i, mode; /* list of supported chipsets */ int (*chipset_detect[])(struct ppc_data *, int) = { ppc_pc873xx_detect, ppc_smc37c66xgt_detect, ppc_w83877f_detect, ppc_smc37c935_detect, ppc_generic_detect, NULL }; #endif /* if can't find the port and mode not forced return error */ if (!ppc_detect_port(ppc) && chipset_mode == 0) return (EIO); /* failed, port not present */ /* assume centronics compatible mode is supported */ ppc->ppc_avm = PPB_COMPATIBLE; #ifdef PPC_PROBE_CHIPSET /* we have to differenciate available chipset modes, * chipset running modes and IEEE-1284 operating modes * * after detection, the port must support running in compatible mode */ if (ppc->ppc_flags & 0x40) { if (bootverbose) printf("ppc: chipset forced to generic\n"); #endif ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); #ifdef PPC_PROBE_CHIPSET } else { for (i=0; chipset_detect[i] != NULL; i++) { if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { ppc->ppc_mode = mode; break; } } } #endif /* configure/detect ECP FIFO */ if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) ppc_detect_fifo(ppc); return (0); } /* * ppc_exec_microseq() * * Execute a microsequence. * Microsequence mechanism is supposed to handle fast I/O operations. */ int ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) { struct ppc_data *ppc = DEVTOSOFTC(dev); struct ppb_microseq *mi; char cc, *p; int i, iter, len; int error; register int reg; register char mask; register int accum = 0; register char *ptr = 0; struct ppb_microseq *stack = 0; /* microsequence registers are equivalent to PC-like port registers */ #define r_reg(reg,ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, reg)) #define w_reg(reg, ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, reg, byte)) #define INCR_PC (mi ++) /* increment program counter */ mi = *p_msq; for (;;) { switch (mi->opcode) { case MS_OP_RSET: cc = r_reg(mi->arg[0].i, ppc); cc &= (char)mi->arg[2].i; /* clear mask */ cc |= (char)mi->arg[1].i; /* assert mask */ w_reg(mi->arg[0].i, ppc, cc); INCR_PC; break; case MS_OP_RASSERT_P: reg = mi->arg[1].i; ptr = ppc->ppc_ptr; if ((len = mi->arg[0].i) == MS_ACCUM) { accum = ppc->ppc_accum; for (; accum; accum--) w_reg(reg, ppc, *ptr++); ppc->ppc_accum = accum; } else for (i=0; ippc_ptr = ptr; INCR_PC; break; case MS_OP_RFETCH_P: reg = mi->arg[1].i; mask = (char)mi->arg[2].i; ptr = ppc->ppc_ptr; if ((len = mi->arg[0].i) == MS_ACCUM) { accum = ppc->ppc_accum; for (; accum; accum--) *ptr++ = r_reg(reg, ppc) & mask; ppc->ppc_accum = accum; } else for (i=0; ippc_ptr = ptr; INCR_PC; break; case MS_OP_RFETCH: *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & (char)mi->arg[1].i; INCR_PC; break; case MS_OP_RASSERT: case MS_OP_DELAY: /* let's suppose the next instr. is the same */ prefetch: for (;mi->opcode == MS_OP_RASSERT; INCR_PC) w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); if (mi->opcode == MS_OP_DELAY) { DELAY(mi->arg[0].i); INCR_PC; goto prefetch; } break; case MS_OP_ADELAY: if (mi->arg[0].i) tsleep(NULL, PPBPRI, "ppbdelay", mi->arg[0].i * (hz/1000)); INCR_PC; break; case MS_OP_TRIG: reg = mi->arg[0].i; iter = mi->arg[1].i; p = (char *)mi->arg[2].p; /* XXX delay limited to 255 us */ for (i=0; ippc_accum = mi->arg[0].i; INCR_PC; break; case MS_OP_DBRA: if (--ppc->ppc_accum > 0) mi += mi->arg[0].i; INCR_PC; break; case MS_OP_BRSET: cc = r_str(ppc); if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) mi += mi->arg[1].i; INCR_PC; break; case MS_OP_BRCLEAR: cc = r_str(ppc); if ((cc & (char)mi->arg[0].i) == 0) mi += mi->arg[1].i; INCR_PC; break; case MS_OP_BRSTAT: cc = r_str(ppc); if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == (char)mi->arg[0].i) mi += mi->arg[2].i; INCR_PC; break; case MS_OP_C_CALL: /* * If the C call returns !0 then end the microseq. * The current state of ptr is passed to the C function */ if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) return (error); INCR_PC; break; case MS_OP_PTR: ppc->ppc_ptr = (char *)mi->arg[0].p; INCR_PC; break; case MS_OP_CALL: if (stack) panic("%s: too much calls", __func__); if (mi->arg[0].p) { /* store the state of the actual * microsequence */ stack = mi; /* jump to the new microsequence */ mi = (struct ppb_microseq *)mi->arg[0].p; } else INCR_PC; break; case MS_OP_SUBRET: /* retrieve microseq and pc state before the call */ mi = stack; /* reset the stack */ stack = 0; /* XXX return code */ INCR_PC; break; case MS_OP_PUT: case MS_OP_GET: case MS_OP_RET: /* can't return to ppb level during the execution * of a submicrosequence */ if (stack) panic("%s: can't return to ppb level", __func__); /* update pc for ppb level of execution */ *p_msq = mi; /* return to ppb level of execution */ return (0); default: panic("%s: unknown microsequence opcode 0x%x", __func__, mi->opcode); } } /* unreached */ } static void ppcintr(void *arg) { device_t dev = (device_t)arg; struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); u_char ctr, ecr, str; str = r_str(ppc); ctr = r_ctr(ppc); ecr = r_ecr(ppc); #if PPC_DEBUG > 1 printf("![%x/%x/%x]", ctr, ecr, str); #endif /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { return; } /* interrupts are generated by nFault signal * only in ECP mode */ if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { /* check if ppc driver has programmed the * nFault interrupt */ if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { w_ecr(ppc, ecr | PPC_nFAULT_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { /* shall be handled by underlying layers XXX */ return; } } if (ppc->ppc_irqstat & PPC_IRQ_DMA) { /* disable interrupts (should be done by hardware though) */ w_ecr(ppc, ecr | PPC_SERVICE_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_DMA; ecr = r_ecr(ppc); /* check if DMA completed */ if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { #ifdef PPC_DEBUG printf("a"); #endif /* stop DMA */ w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); ecr = r_ecr(ppc); if (ppc->ppc_dmastat == PPC_DMA_STARTED) { #ifdef PPC_DEBUG printf("d"); #endif isa_dmadone( ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt, ppc->ppc_dmachan); ppc->ppc_dmastat = PPC_DMA_COMPLETE; /* wakeup the waiting process */ wakeup(ppc); } } } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; } return; } int ppc_read(device_t dev, char *buf, int len, int mode) { return (EINVAL); } /* * Call this function if you want to send data in any advanced mode * of your parallel port: FIFO, DMA * * If what you want is not possible (no ECP, no DMA...), * EINVAL is returned */ int ppc_write(device_t dev, char *buf, int len, int how) { struct ppc_data *ppc = DEVTOSOFTC(dev); char ecr, ecr_sav, ctr, ctr_sav; int s, error = 0; int spin; #ifdef PPC_DEBUG printf("w"); #endif ecr_sav = r_ecr(ppc); ctr_sav = r_ctr(ppc); /* * Send buffer with DMA, FIFO and interrupts */ if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) { if (ppc->ppc_dmachan > 0) { /* byte mode, no intr, no DMA, dir=0, flush fifo */ ecr = PPC_ECR_STD | PPC_DISABLE_INTR; w_ecr(ppc, ecr); /* disable nAck interrupts */ ctr = r_ctr(ppc); ctr &= ~IRQENABLE; w_ctr(ppc, ctr); ppc->ppc_dmaflags = 0; ppc->ppc_dmaddr = (caddr_t)buf; ppc->ppc_dmacnt = (u_int)len; switch (ppc->ppc_mode) { case PPB_COMPATIBLE: /* compatible mode with FIFO, no intr, DMA, dir=0 */ ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA; break; case PPB_ECP: ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA; break; default: error = EINVAL; goto error; } w_ecr(ppc, ecr); ecr = r_ecr(ppc); /* enter splhigh() not to be preempted * by the dma interrupt, we may miss * the wakeup otherwise */ s = splhigh(); ppc->ppc_dmastat = PPC_DMA_INIT; /* enable interrupts */ ecr &= ~PPC_SERVICE_INTR; ppc->ppc_irqstat = PPC_IRQ_DMA; w_ecr(ppc, ecr); isa_dmastart( ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt, ppc->ppc_dmachan); #ifdef PPC_DEBUG printf("s%d", ppc->ppc_dmacnt); #endif ppc->ppc_dmastat = PPC_DMA_STARTED; /* Wait for the DMA completed interrupt. We hope we won't * miss it, otherwise a signal will be necessary to unlock the * process. */ do { /* release CPU */ error = tsleep(ppc, PPBPRI | PCATCH, "ppcdma", 0); } while (error == EWOULDBLOCK); splx(s); if (error) { #ifdef PPC_DEBUG printf("i"); #endif /* stop DMA */ isa_dmadone( ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt, ppc->ppc_dmachan); /* no dma, no interrupt, flush the fifo */ w_ecr(ppc, PPC_ECR_RESET); ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; goto error; } /* wait for an empty fifo */ while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { for (spin=100; spin; spin--) if (r_ecr(ppc) & PPC_FIFO_EMPTY) goto fifo_empty; #ifdef PPC_DEBUG printf("Z"); #endif error = tsleep(ppc, PPBPRI | PCATCH, "ppcfifo", hz/100); if (error != EWOULDBLOCK) { #ifdef PPC_DEBUG printf("I"); #endif /* no dma, no interrupt, flush the fifo */ w_ecr(ppc, PPC_ECR_RESET); ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; error = EINTR; goto error; } } fifo_empty: /* no dma, no interrupt, flush the fifo */ w_ecr(ppc, PPC_ECR_RESET); } else error = EINVAL; /* XXX we should FIFO and * interrupts */ } else error = EINVAL; error: /* PDRQ must be kept unasserted until nPDACK is * deasserted for a minimum of 350ns (SMC datasheet) * * Consequence may be a FIFO that never empty */ DELAY(1); w_ecr(ppc, ecr_sav); w_ctr(ppc, ctr_sav); return (error); } void ppc_reset_epp(device_t dev) { struct ppc_data *ppc = DEVTOSOFTC(dev); ppc_reset_epp_timeout(ppc); return; } int ppc_setmode(device_t dev, int mode) { struct ppc_data *ppc = DEVTOSOFTC(dev); switch (ppc->ppc_type) { case PPC_TYPE_SMCLIKE: return (ppc_smclike_setmode(ppc, mode)); break; case PPC_TYPE_GENERIC: default: return (ppc_generic_setmode(ppc, mode)); break; } /* not reached */ return (ENXIO); } static struct isa_pnp_id lpc_ids[] = { { 0x0004d041, "Standard parallel printer port" }, /* PNP0400 */ { 0x0104d041, "ECP parallel printer port" }, /* PNP0401 */ { 0 } }; static int ppc_isa_probe(device_t dev) { device_t parent; int error; parent = device_get_parent(dev); error = ISA_PNP_PROBE(parent, dev, lpc_ids); if (error == ENXIO) return (ENXIO); else if (error != 0) /* XXX shall be set after detection */ device_set_desc(dev, "Parallel port"); return(ppc_probe(dev)); } int ppc_probe(device_t dev) { #ifdef __i386__ static short next_bios_ppc = 0; #endif struct ppc_data *ppc; int error; u_long port; /* * Allocate the ppc_data structure. */ ppc = DEVTOSOFTC(dev); bzero(ppc, sizeof(struct ppc_data)); ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0; ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0; /* retrieve ISA parameters */ error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, NULL); #ifdef __i386__ /* * If port not specified, use bios list. */ if (error) { if((next_bios_ppc < BIOS_MAX_PPC) && (*(BIOS_PORTS+next_bios_ppc) != 0) ) { port = *(BIOS_PORTS+next_bios_ppc++); if (bootverbose) device_printf(dev, "parallel port found at 0x%x\n", (int) port); } else { device_printf(dev, "parallel port not found.\n"); return ENXIO; } bus_set_resource(dev, SYS_RES_IOPORT, 0, port, IO_LPTSIZE_EXTENDED); } #endif #ifdef __alpha__ /* * There isn't a bios list on alpha. Put it in the usual place. */ if (error) { bus_set_resource(dev, SYS_RES_IOPORT, 0, 0x3bc, IO_LPTSIZE_NORMAL); } #endif /* IO port is mandatory */ /* Try "extended" IO port range...*/ ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &ppc->rid_ioport, 0, ~0, IO_LPTSIZE_EXTENDED, RF_ACTIVE); if (ppc->res_ioport != 0) { if (bootverbose) device_printf(dev, "using extended I/O port range\n"); } else { /* Failed? If so, then try the "normal" IO port range... */ ppc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &ppc->rid_ioport, 0, ~0, IO_LPTSIZE_NORMAL, RF_ACTIVE); if (ppc->res_ioport != 0) { if (bootverbose) device_printf(dev, "using normal I/O port range\n"); } else { device_printf(dev, "cannot reserve I/O port range\n"); goto error; } } ppc->ppc_base = rman_get_start(ppc->res_ioport); ppc->bsh = rman_get_bushandle(ppc->res_ioport); ppc->bst = rman_get_bustag(ppc->res_ioport); ppc->ppc_flags = device_get_flags(dev); if (!(ppc->ppc_flags & 0x20)) { ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &ppc->rid_irq, RF_SHAREABLE); ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &ppc->rid_drq, RF_ACTIVE); } if (ppc->res_irq) ppc->ppc_irq = rman_get_start(ppc->res_irq); if (ppc->res_drq) ppc->ppc_dmachan = rman_get_start(ppc->res_drq); ppc->ppc_unit = device_get_unit(dev); ppc->ppc_model = GENERIC; ppc->ppc_mode = PPB_COMPATIBLE; ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; ppc->ppc_type = PPC_TYPE_GENERIC; /* * Try to detect the chipset and its mode. */ if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) goto error; return (0); error: if (ppc->res_irq != 0) { bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, ppc->res_irq); } if (ppc->res_ioport != 0) { bus_deactivate_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, ppc->res_ioport); bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, ppc->res_ioport); } if (ppc->res_drq != 0) { bus_deactivate_resource(dev, SYS_RES_DRQ, ppc->rid_drq, ppc->res_drq); bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, ppc->res_drq); } return (ENXIO); } int ppc_attach(device_t dev) { struct ppc_data *ppc = DEVTOSOFTC(dev); device_t ppbus; device_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) device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { /* acquire the DMA channel forever */ /* XXX */ isa_dma_acquire(ppc->ppc_dmachan); isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ } /* add ppbus as a child of this isa to parallel bridge */ ppbus = device_add_child(dev, "ppbus", -1); /* * Probe the ppbus and attach devices found. */ device_probe_and_attach(ppbus); /* register the ppc interrupt handler as default */ if (ppc->res_irq) { /* default to the tty mask for registration */ /* XXX */ if (BUS_SETUP_INTR(parent, dev, ppc->res_irq, INTR_TYPE_TTY, ppcintr, dev, &ppc->intr_cookie) == 0) { /* remember the ppcintr is registered */ ppc->ppc_registered = 1; } } return (0); } u_char ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) { struct ppc_data *ppc = DEVTOSOFTC(ppcdev); switch (iop) { case PPB_OUTSB_EPP: bus_space_write_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); break; case PPB_OUTSW_EPP: bus_space_write_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); break; case PPB_OUTSL_EPP: bus_space_write_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); break; case PPB_INSB_EPP: bus_space_read_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); break; case PPB_INSW_EPP: bus_space_read_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); break; case PPB_INSL_EPP: bus_space_read_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); break; case PPB_RDTR: return (r_dtr(ppc)); case PPB_RSTR: return (r_str(ppc)); case PPB_RCTR: return (r_ctr(ppc)); case PPB_REPP_A: return (r_epp_A(ppc)); case PPB_REPP_D: return (r_epp_D(ppc)); case PPB_RECR: return (r_ecr(ppc)); case PPB_RFIFO: return (r_fifo(ppc)); case PPB_WDTR: w_dtr(ppc, byte); break; case PPB_WSTR: w_str(ppc, byte); break; case PPB_WCTR: w_ctr(ppc, byte); break; case PPB_WEPP_A: w_epp_A(ppc, byte); break; case PPB_WEPP_D: w_epp_D(ppc, byte); break; case PPB_WECR: w_ecr(ppc, byte); break; case PPB_WFIFO: w_fifo(ppc, byte); break; default: panic("%s: unknown I/O operation", __func__); break; } return (0); /* not significative */ } int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) { struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); switch (index) { case PPC_IVAR_EPP_PROTO: *val = (u_long)ppc->ppc_epp; break; case PPC_IVAR_IRQ: *val = (u_long)ppc->ppc_irq; break; default: return (ENOENT); } return (0); } /* * Resource is useless here since ppbus devices' interrupt handlers are * multiplexed to the same resource initially allocated by ppc */ int ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, void (*ihand)(void *), void *arg, void **cookiep) { int error; struct ppc_data *ppc = DEVTOSOFTC(bus); if (ppc->ppc_registered) { /* XXX refuse registration if DMA is in progress */ /* first, unregister the default interrupt handler */ if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus), bus, ppc->res_irq, ppc->intr_cookie))) return (error); /* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */ /* ppc->res_irq); */ /* DMA/FIFO operation won't be possible anymore */ ppc->ppc_registered = 0; } /* pass registration to the upper layer, ignore the incoming resource */ return (BUS_SETUP_INTR(device_get_parent(bus), child, r, flags, ihand, arg, cookiep)); } /* * When no underlying device has a registered interrupt, register the ppc * layer one */ int ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) { int error; struct ppc_data *ppc = DEVTOSOFTC(bus); device_t parent = device_get_parent(bus); /* pass unregistration to the upper layer */ if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih))) return (error); /* default to the tty mask for registration */ /* XXX */ if (ppc->ppc_irq && !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq, INTR_TYPE_TTY, ppcintr, bus, &ppc->intr_cookie))) { /* remember the ppcintr is registered */ ppc->ppc_registered = 1; } return (error); } DRIVER_MODULE(ppc, isa, ppc_driver, ppc_devclass, 0, 0); DRIVER_MODULE(ppc, acpi, ppc_driver, ppc_devclass, 0, 0); +MODULE_DEPEND(ppc, ppbus, 1, 1, 1); Index: stable/6/sys/modules/Makefile =================================================================== --- stable/6/sys/modules/Makefile (revision 160502) +++ stable/6/sys/modules/Makefile (revision 160503) @@ -1,546 +1,549 @@ # $FreeBSD$ # oldcard -- specialized use for debugging only. # owi -- totally unsupported for debugging only. SUBDIR= ${_3dfx} \ ${_3dfx_linux} \ ${_aac} \ accf_data \ accf_http \ ${_acpi} \ ${_agp} \ aha \ ${_ahb} \ ${_aic} \ aic7xxx \ aio \ ${_amd} \ amr \ an \ ${_aout} \ ${_apm} \ ${_ar} \ ${_arcmsr} \ ${_arcnet} \ ${_arl} \ ${_asr} \ ata \ ath \ ${_ath_hal} \ ath_rate_amrr \ ath_rate_onoe \ ath_rate_sample \ aue \ ${_auxio} \ ${_awi} \ axe \ bce \ bfe \ bge \ ${_bios} \ ${_bktr} \ bridge \ cam \ ${_canbepm} \ ${_canbus} \ ${_cardbus} \ ${_cbb} \ cd9660 \ cd9660_iconv \ cdce \ ${_ce} \ ${_ciss} \ ${_cm} \ coda \ coda5 \ ${_coff} \ ${_cp} \ ${_cpufreq} \ ${_crypto} \ ${_cryptodev} \ ${_cs} \ ${_ctau} \ cue \ ${_cx} \ dc \ dcons \ dcons_crom \ de \ ${_digi} \ ${_dpt} \ ${_drm} \ dummynet \ ${_ed} \ ${_el} \ ${_elink} \ ${_em} \ en \ ${_ep} \ ${_ex} \ ${_exca} \ ${_ext2fs} \ fatm \ fdc \ fdescfs \ ${_fe} \ firewire \ firmware \ fxp \ ${_gem} \ geom \ harp \ hatm \ ${_hfa} \ hifn \ hme \ ${_hptmv} \ hwpmc \ ${_i2c} \ ${_ibcs2} \ ${_ichwd} \ ${_ida} \ ${_idt} \ ${_ie} \ if_bridge \ if_disc \ if_ef \ if_faith \ if_gif \ if_gre \ ${_if_ndis} \ if_ppp \ if_sl \ if_stf \ if_tap \ if_tun \ if_vlan \ ${_iir} \ ${_io} \ ip6fw \ ipdivert \ ${_ipfilter} \ ipfw \ ip_mroute_mod \ ${_ipmi} \ ${_ips} \ ipw \ isp \ ispfw \ iwi \ joy \ kbdmux \ kue \ le \ lge \ libalias \ libiconv \ libmbpool \ libmchain \ ${_linprocfs} \ ${_linsysfs} \ ${_linux} \ ${_lnc} \ lpt \ mac_biba \ mac_bsdextended \ mac_ifoff \ mac_lomac \ mac_mls \ mac_none \ mac_partition \ mac_portacl \ mac_seeotheruids \ mac_stub \ mac_test \ mcd \ md \ mem \ mfi \ mii \ mlx \ ${_mly} \ mpt \ msdosfs \ msdosfs_iconv \ ${_mse} \ my \ ${_ncp} \ ${_ncv} \ ${_ndis} \ netgraph \ nfsclient \ nfsserver \ nge \ nmdm \ ${_nsp} \ ntfs \ ntfs_iconv \ nullfs \ ${_nve} \ ${_nwfs} \ ${_oltr} \ ${_osf1} \ ${_padlock} \ patm \ ${_pccard} \ ${_pcfclock} \ pcn \ ${_pecoff} \ ${_pf} \ ${_pflog} \ plip \ ${_pmc} \ portalfs \ ppbus \ + ${_ppc} \ ppi \ pps \ procfs \ pseudofs \ ${_pst} \ ${_puc} \ ral \ ${_random} \ ${_ray} \ rc \ rc4 \ re \ reiserfs \ rl \ rp \ ${_rr232x} \ rue \ ${_s3} \ ${_safe} \ ${_sbni} \ sbsh \ scd \ ${_scsi_low} \ sf \ ${_sio} \ sis \ sk \ ${_smbfs} \ sn \ ${_snc} \ snp \ ${_sound} \ ${_speaker} \ ${_splash} \ ${_sppp} \ ${_sr} \ ste \ ${_stg} \ ${_streams} \ sym \ ${_syscons} \ sysvipc \ ti \ tl \ trm \ ${_twa} \ twe \ tx \ txp \ ${_uart} \ ubsa \ ubsec \ ubser \ ucom \ ucycom \ udav \ udbp \ udf \ udf_iconv \ ufm \ ${_ufs} \ uftdi \ ugen \ uhid \ ukbd \ ulpt \ umass \ umct \ umodem \ ums \ unionfs \ uplcom \ ural \ urio \ usb \ uscanner \ utopia \ uvisor \ uvscom \ ${_vesa} \ vge \ vkbd \ ${_vpo} \ vr \ vx \ wb \ ${_wi} \ wlan \ wlan_acl \ wlan_ccmp \ wlan_tkip \ wlan_wep \ wlan_xauth \ ${_xe} \ xl \ zlib .if ${MACHINE_ARCH} != "powerpc" _syscons= syscons _uart= uart _vpo= vpo .endif .if defined(ALL_MODULES) _ufs= ufs .endif .if !defined(NO_CRYPT) || defined(ALL_MODULES) .if exists(${.CURDIR}/../opencrypto) _crypto= crypto _cryptodev= cryptodev .endif .if exists(${.CURDIR}/../crypto) _random= random .endif .endif .if !defined(NO_IPFILTER) || defined(ALL_MODULES) _ipfilter= ipfilter .endif .if !defined(NO_PF) || defined(ALL_MODULES) _pf= pf _pflog= pflog .endif .if ${MACHINE_ARCH} == "i386" # XXX some of these can move to the general case when de-i386'ed # XXX some of these can move now, but are untested on other architectures. _3dfx= 3dfx _3dfx_linux= 3dfx_linux _agp= agp _aic= aic _amd= amd _aout= aout _apm= apm _ar= ar _arcnet= arcnet _ath_hal= ath_hal _awi= awi _bktr= bktr _cardbus= cardbus _cbb= cbb _ce= ce _coff= coff _cp= cp _cpufreq= cpufreq _digi= digi _drm= drm _ed= ed _elink= elink _em= em _ep= ep _exca= exca _ext2fs= ext2fs _fe= fe _hfa= hfa _i2c= i2c _ibcs2= ibcs2 _ie= ie _if_ndis= if_ndis _io= io _linprocfs= linprocfs _linsysfs= linsysfs _linux= linux _lnc= lnc _mse= mse _ncp= ncp _ncv= ncv _ndis= ndis _nsp= nsp _nwfs= nwfs _oltr= oltr _pccard= pccard _pcfclock= pcfclock _pecoff= pecoff _pst= pst _puc= puc _ray= ray _safe= safe _sbni= sbni _scsi_low= scsi_low _sio= sio _smbfs= smbfs _sound= sound _speaker= speaker _splash= splash _sppp= sppp _sr= sr _stg= stg _streams= streams _wi= wi _xe= xe .if ${MACHINE} == "i386" _aac= aac _acpi= acpi _ahb= ahb _arcmsr= arcmsr _arl= arl _asr= asr _bios= bios _ciss= ciss _cm= cm _cs= cs _ctau= ctau _cx= cx _dpt= dpt _el= el _ex= ex _hptmv= hptmv _ichwd= ichwd _ida= ida _idt= idt _iir= iir _ipmi= ipmi _ips= ips _mly= mly _nve= nve .if !defined(NO_CRYPT) || defined(ALL_MODULES) .if exists(${.CURDIR}/../crypto/via) _padlock= padlock .endif .endif +_ppc= ppc _rr232x= rr232x _s3= s3 _twa= twa _vesa= vesa .elif ${MACHINE} == "pc98" _canbepm= canbepm _canbus= canbus _pmc= pmc _snc= snc .endif .endif .if ${MACHINE_ARCH} == "alpha" _agp= agp _ahb= ahb _ath_hal= ath_hal _ext2fs= ext2fs _linprocfs= linprocfs _linsysfs= linsysfs _linux= linux _osf1= osf1 _sound= sound _sppp= sppp .endif .if ${MACHINE_ARCH} == "amd64" _aac= aac #_acpi= acpi # doesn't work on amd64 yet _agp= agp _arcmsr= arcmsr _ath_hal= ath_hal _ciss= ciss _cpufreq= cpufreq _digi= digi _drm= drm _em= em _ext2fs= ext2fs _hptmv= hptmv _i2c= i2c _ichwd= ichwd _ida= ida _if_ndis= if_ndis _iir= iir _io= io _ipmi= ipmi _ips= ips #_lnc= lnc _mly= mly _ndis= ndis _nve= nve +_ppc= ppc _rr232x= rr232x _safe= safe _scsi_low= scsi_low _smbfs= smbfs _sound= sound _speaker= speaker _sppp= sppp _twa= twa .endif .if ${MACHINE_ARCH} == "ia64" # Modules not enabled on ia64 (as compared to i386) include: # aac acpi aout apm atspeaker drm ibcs2 linprocfs linux ncv # nsp oltr pecoff s3 sbni stg vesa # acpi is not enabled because it is broken as a module on ia64 _aic= aic #_ar= ar not 64-bit clean _arcnet= arcnet _asr= asr _bktr= bktr _cardbus= cardbus _cbb= cbb _ciss= ciss _cm= cm _coff= coff _cpufreq= cpufreq _el= el _em= em _ep= ep _exca= exca _fe= fe _hfa= hfa _iir= iir _mly= mly _pccard= pccard _scsi_low= scsi_low _smbfs= smbfs _sound= sound _splash= splash _sppp= sppp #_sr= sr not 64bit clean _streams= streams _wi= wi _xe= xe .endif .if ${MACHINE_ARCH} == "powerpc" _ath_hal= ath_hal _gem= gem .endif .if ${MACHINE_ARCH} == "sparc64" _ath_hal= ath_hal _auxio= auxio _em= em _gem= gem _sound= sound .endif .if defined(MODULES_OVERRIDE) && !defined(ALL_MODULES) SUBDIR=${MODULES_OVERRIDE} .endif .for reject in ${WITHOUT_MODULES} SUBDIR:= ${SUBDIR:N${reject}} .endfor # Calling kldxref(8) for each module is expensive. .if !defined(NO_XREF) .MAKEFLAGS+= -DNO_XREF afterinstall: @if type kldxref >/dev/null 2>&1; then \ ${ECHO} kldxref ${DESTDIR}${KMODDIR}; \ kldxref ${DESTDIR}${KMODDIR}; \ fi .endif .include Index: stable/6/sys/modules/ppc/Makefile =================================================================== --- stable/6/sys/modules/ppc/Makefile (revision 160502) +++ stable/6/sys/modules/ppc/Makefile (revision 160503) @@ -1,24 +1,11 @@ # $FreeBSD$ +#.PATH: ${.CURDIR}/../../kern .PATH: ${.CURDIR}/../../dev/ppc -KMOD= ppc -SRCS= bus_if.h device_if.h ppbus_if.h isa_if.h pci_if.h serdev_if.h \ - opt_ppc.h opt_isa.h \ - ppc.c ppc_pci.c ppc_puc.c +.PATH: ${.CURDIR}/../../dev/ppbus -.if ${MACHINE_ARCH} == "amd64" -SRCS+= ppc_acpi.c ppc_isa.c -.endif - -.if ${MACHINE_ARCH} == "i386" -.if ${MACHINE} != "pc98" -SRCS+= ppc_acpi.c -.endif -SRCS+= ppc_isa.c -.endif - -.if ${MACHINE_ARCH} == "ia64" -SRCS+= ppc_acpi.c -.endif +KMOD= ppc +SRCS= bus_if.h ppbus_if.h opt_ppc.h device_if.h isa_if.h \ + ppc.c ppc_puc.c .include