146f3ff79SMike Smith /*- 246f3ff79SMike Smith * Copyright (c) 1997 Poul-Henning Kamp 346f3ff79SMike Smith * All rights reserved. 446f3ff79SMike Smith * 546f3ff79SMike Smith * Redistribution and use in source and binary forms, with or without 646f3ff79SMike Smith * modification, are permitted provided that the following conditions 746f3ff79SMike Smith * are met: 846f3ff79SMike Smith * 1. Redistributions of source code must retain the above copyright 946f3ff79SMike Smith * notice, this list of conditions and the following disclaimer. 1046f3ff79SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1146f3ff79SMike Smith * notice, this list of conditions and the following disclaimer in the 1246f3ff79SMike Smith * documentation and/or other materials provided with the distribution. 1346f3ff79SMike Smith * 1446f3ff79SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1546f3ff79SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1646f3ff79SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1746f3ff79SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1846f3ff79SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1946f3ff79SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2046f3ff79SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2146f3ff79SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2246f3ff79SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2346f3ff79SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2446f3ff79SMike Smith * SUCH DAMAGE. 2546f3ff79SMike Smith * 2646f3ff79SMike Smith * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 2746f3ff79SMike Smith * $Id$ 2846f3ff79SMike Smith */ 2946f3ff79SMike Smith 3046f3ff79SMike Smith /* 3146f3ff79SMike Smith * Parallel port TCP/IP interfaces added. I looked at the driver from 3246f3ff79SMike Smith * MACH but this is a complete rewrite, and btw. incompatible, and it 3346f3ff79SMike Smith * should perform better too. I have never run the MACH driver though. 3446f3ff79SMike Smith * 3546f3ff79SMike Smith * This driver sends two bytes (0x08, 0x00) in front of each packet, 3646f3ff79SMike Smith * to allow us to distinguish another format later. 3746f3ff79SMike Smith * 3846f3ff79SMike Smith * Now added an Linux/Crynwr compatibility mode which is enabled using 3946f3ff79SMike Smith * IF_LINK0 - Tim Wilkinson. 4046f3ff79SMike Smith * 4146f3ff79SMike Smith * TODO: 4246f3ff79SMike Smith * Make HDLC/PPP mode, use IF_LLC1 to enable. 4346f3ff79SMike Smith * 4446f3ff79SMike Smith * Connect the two computers using a Laplink parallel cable to use this 4546f3ff79SMike Smith * feature: 4646f3ff79SMike Smith * 4746f3ff79SMike Smith * +----------------------------------------+ 4846f3ff79SMike Smith * |A-name A-End B-End Descr. Port/Bit | 4946f3ff79SMike Smith * +----------------------------------------+ 5046f3ff79SMike Smith * |DATA0 2 15 Data 0/0x01 | 5146f3ff79SMike Smith * |-ERROR 15 2 1/0x08 | 5246f3ff79SMike Smith * +----------------------------------------+ 5346f3ff79SMike Smith * |DATA1 3 13 Data 0/0x02 | 5446f3ff79SMike Smith * |+SLCT 13 3 1/0x10 | 5546f3ff79SMike Smith * +----------------------------------------+ 5646f3ff79SMike Smith * |DATA2 4 12 Data 0/0x04 | 5746f3ff79SMike Smith * |+PE 12 4 1/0x20 | 5846f3ff79SMike Smith * +----------------------------------------+ 5946f3ff79SMike Smith * |DATA3 5 10 Strobe 0/0x08 | 6046f3ff79SMike Smith * |-ACK 10 5 1/0x40 | 6146f3ff79SMike Smith * +----------------------------------------+ 6246f3ff79SMike Smith * |DATA4 6 11 Data 0/0x10 | 6346f3ff79SMike Smith * |BUSY 11 6 1/~0x80 | 6446f3ff79SMike Smith * +----------------------------------------+ 6546f3ff79SMike Smith * |GND 18-25 18-25 GND - | 6646f3ff79SMike Smith * +----------------------------------------+ 6746f3ff79SMike Smith * 6846f3ff79SMike Smith * Expect transfer-rates up to 75 kbyte/sec. 6946f3ff79SMike Smith * 7046f3ff79SMike Smith * If GCC could correctly grok 7146f3ff79SMike Smith * register int port asm("edx") 7246f3ff79SMike Smith * the code would be cleaner 7346f3ff79SMike Smith * 7446f3ff79SMike Smith * Poul-Henning Kamp <phk@freebsd.org> 7546f3ff79SMike Smith */ 7646f3ff79SMike Smith 7746f3ff79SMike Smith /* 7846f3ff79SMike Smith * Update for ppbus, PLIP support only - Nicolas Souchu 7946f3ff79SMike Smith */ 8046f3ff79SMike Smith 8146f3ff79SMike Smith #ifdef KERNEL 8246f3ff79SMike Smith #include <sys/param.h> 8346f3ff79SMike Smith #include <sys/systm.h> 8446f3ff79SMike Smith #include <sys/proc.h> 8546f3ff79SMike Smith #include <sys/mbuf.h> 8646f3ff79SMike Smith #include <sys/socket.h> 8746f3ff79SMike Smith #include <sys/filio.h> 8846f3ff79SMike Smith #include <sys/sockio.h> 8946f3ff79SMike Smith #include <sys/kernel.h> 9046f3ff79SMike Smith #include <sys/time.h> 9146f3ff79SMike Smith #include <sys/malloc.h> 9246f3ff79SMike Smith 9346f3ff79SMike Smith #include <net/if.h> 9446f3ff79SMike Smith #include <net/if_types.h> 9546f3ff79SMike Smith #include <net/netisr.h> 9646f3ff79SMike Smith 9746f3ff79SMike Smith #endif /* KERNEL */ 9846f3ff79SMike Smith #include <sys/mbuf.h> 9946f3ff79SMike Smith #include <sys/socket.h> 10046f3ff79SMike Smith #include <net/netisr.h> 10146f3ff79SMike Smith #include <net/route.h> 10246f3ff79SMike Smith #include <netinet/in.h> 10346f3ff79SMike Smith #include <netinet/in_systm.h> 10446f3ff79SMike Smith #include <netinet/in_var.h> 10546f3ff79SMike Smith #include <netinet/ip.h> 10646f3ff79SMike Smith #include <netinet/if_ether.h> 10746f3ff79SMike Smith 10846f3ff79SMike Smith #include "bpfilter.h" 10946f3ff79SMike Smith #if NBPFILTER > 0 11046f3ff79SMike Smith #include <net/bpf.h> 11146f3ff79SMike Smith #include <net/bpfdesc.h> 11246f3ff79SMike Smith #endif 11346f3ff79SMike Smith 11446f3ff79SMike Smith #include <dev/ppbus/ppbconf.h> 11546f3ff79SMike Smith #include <dev/ppbus/nlpt.h> 11646f3ff79SMike Smith 11746f3ff79SMike Smith #ifndef LPMTU /* MTU for the lp# interfaces */ 11846f3ff79SMike Smith #define LPMTU 1500 11946f3ff79SMike Smith #endif 12046f3ff79SMike Smith 12146f3ff79SMike Smith #ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 12246f3ff79SMike Smith #define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 12346f3ff79SMike Smith #endif 12446f3ff79SMike Smith 12546f3ff79SMike Smith #ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 12646f3ff79SMike Smith #define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 12746f3ff79SMike Smith #endif 12846f3ff79SMike Smith 12946f3ff79SMike Smith #ifndef LPMAXERRS /* Max errors before !RUNNING */ 13046f3ff79SMike Smith #define LPMAXERRS 100 13146f3ff79SMike Smith #endif 13246f3ff79SMike Smith 13346f3ff79SMike Smith #define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 13446f3ff79SMike Smith #define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 13546f3ff79SMike Smith #define MLPIPHDRLEN CLPIPHDRLEN 13646f3ff79SMike Smith 13746f3ff79SMike Smith #define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 13846f3ff79SMike Smith #define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 13946f3ff79SMike Smith #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 14046f3ff79SMike Smith #define MLPIPHDRLEN LPIPHDRLEN 14146f3ff79SMike Smith #endif 14246f3ff79SMike Smith 14346f3ff79SMike Smith #define LPIPTBLSIZE 256 /* Size of octet translation table */ 14446f3ff79SMike Smith 14546f3ff79SMike Smith #define DEBUG 14646f3ff79SMike Smith 14746f3ff79SMike Smith #ifndef DEBUG 14846f3ff79SMike Smith #define lprintf (void) 14946f3ff79SMike Smith #else 15046f3ff79SMike Smith #define lprintf if (lptflag) printf 15146f3ff79SMike Smith static int volatile lptflag = 1; 15246f3ff79SMike Smith #endif 15346f3ff79SMike Smith 15446f3ff79SMike Smith struct lpt_softc { 15546f3ff79SMike Smith unsigned short lp_unit; 15646f3ff79SMike Smith 15746f3ff79SMike Smith struct ppb_device lp_dev; 15846f3ff79SMike Smith 15946f3ff79SMike Smith struct ifnet sc_if; 16046f3ff79SMike Smith u_char *sc_ifbuf; 16146f3ff79SMike Smith int sc_iferrs; 16246f3ff79SMike Smith }; 16346f3ff79SMike Smith 16446f3ff79SMike Smith static int nlp = 0; 16546f3ff79SMike Smith #define MAXPLIP 8 /* XXX not much better! */ 16646f3ff79SMike Smith static struct lpt_softc *lpdata[MAXPLIP]; 16746f3ff79SMike Smith 16846f3ff79SMike Smith 16946f3ff79SMike Smith /* Tables for the lp# interface */ 17046f3ff79SMike Smith static u_char *txmith; 17146f3ff79SMike Smith #define txmitl (txmith+(1*LPIPTBLSIZE)) 17246f3ff79SMike Smith #define trecvh (txmith+(2*LPIPTBLSIZE)) 17346f3ff79SMike Smith #define trecvl (txmith+(3*LPIPTBLSIZE)) 17446f3ff79SMike Smith 17546f3ff79SMike Smith static u_char *ctxmith; 17646f3ff79SMike Smith #define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 17746f3ff79SMike Smith #define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 17846f3ff79SMike Smith #define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 17946f3ff79SMike Smith 18046f3ff79SMike Smith /* Functions for the lp# interface */ 18146f3ff79SMike Smith static struct ppb_device *lpprobe(struct ppb_data *); 18246f3ff79SMike Smith static int lpattach(struct ppb_device *); 18346f3ff79SMike Smith 18446f3ff79SMike Smith static int lpinittables(void); 18546f3ff79SMike Smith static int lpioctl(struct ifnet *, u_long, caddr_t); 18646f3ff79SMike Smith static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 18746f3ff79SMike Smith struct rtentry *); 18846f3ff79SMike Smith static void lpintr(int); 18946f3ff79SMike Smith 19046f3ff79SMike Smith /* 19146f3ff79SMike Smith * Make ourselves visible as a ppbus driver 19246f3ff79SMike Smith */ 19346f3ff79SMike Smith 19446f3ff79SMike Smith static struct ppb_driver lpdriver = { 19546f3ff79SMike Smith lpprobe, lpattach, "lp" 19646f3ff79SMike Smith }; 19746f3ff79SMike Smith DATA_SET(ppbdriver_set, lpdriver); 19846f3ff79SMike Smith 19946f3ff79SMike Smith 20046f3ff79SMike Smith /* 20146f3ff79SMike Smith * lpprobe() 20246f3ff79SMike Smith */ 20346f3ff79SMike Smith static struct ppb_device * 20446f3ff79SMike Smith lpprobe(struct ppb_data *ppb) 20546f3ff79SMike Smith { 20646f3ff79SMike Smith struct lpt_softc *lp; 20746f3ff79SMike Smith 20846f3ff79SMike Smith /* if we haven't interrupts, the probe fails */ 20946f3ff79SMike Smith if (!ppb->ppb_link->id_irq) 21046f3ff79SMike Smith return (0); 21146f3ff79SMike Smith 21246f3ff79SMike Smith lp = (struct lpt_softc *) malloc(sizeof(struct lpt_softc), 21346f3ff79SMike Smith M_TEMP, M_NOWAIT); 21446f3ff79SMike Smith if (!lp) { 21546f3ff79SMike Smith printf("lp: cannot malloc!\n"); 21646f3ff79SMike Smith return (0); 21746f3ff79SMike Smith } 21846f3ff79SMike Smith bzero(lp, sizeof(struct lpt_softc)); 21946f3ff79SMike Smith 22046f3ff79SMike Smith lpdata[nlp] = lp; 22146f3ff79SMike Smith 22246f3ff79SMike Smith /* 22346f3ff79SMike Smith * lp dependent initialisation. 22446f3ff79SMike Smith */ 22546f3ff79SMike Smith lp->lp_unit = nlp; 22646f3ff79SMike Smith 22746f3ff79SMike Smith if (bootverbose) 22846f3ff79SMike Smith printf("plip: irq %d", ppb->ppb_link->id_irq); 22946f3ff79SMike Smith 23046f3ff79SMike Smith /* 23146f3ff79SMike Smith * ppbus dependent initialisation. 23246f3ff79SMike Smith */ 23346f3ff79SMike Smith lp->lp_dev.id_unit = lp->lp_unit; 23446f3ff79SMike Smith lp->lp_dev.name = lpdriver.name; 23546f3ff79SMike Smith lp->lp_dev.ppb = ppb; 23646f3ff79SMike Smith lp->lp_dev.intr = lpintr; 23746f3ff79SMike Smith 23846f3ff79SMike Smith /* Ok, go to next device on next probe */ 23946f3ff79SMike Smith nlp ++; 24046f3ff79SMike Smith 24146f3ff79SMike Smith return (&lp->lp_dev); 24246f3ff79SMike Smith } 24346f3ff79SMike Smith 24446f3ff79SMike Smith static int 24546f3ff79SMike Smith lpattach (struct ppb_device *dev) 24646f3ff79SMike Smith { 24746f3ff79SMike Smith int unit = dev->id_unit; 24846f3ff79SMike Smith struct lpt_softc *sc = lpdata[unit]; 24946f3ff79SMike Smith struct ifnet *ifp = &sc->sc_if; 25046f3ff79SMike Smith 25146f3ff79SMike Smith /* 25246f3ff79SMike Smith * Report ourselves 25346f3ff79SMike Smith */ 25446f3ff79SMike Smith printf("plip%d: <PLIP network interface> on ppbus %d\n", 25546f3ff79SMike Smith dev->id_unit, dev->ppb->ppb_link->adapter_unit); 25646f3ff79SMike Smith 25746f3ff79SMike Smith ifp->if_softc = sc; 25846f3ff79SMike Smith ifp->if_name = "lp"; 25946f3ff79SMike Smith ifp->if_unit = unit; 26046f3ff79SMike Smith ifp->if_mtu = LPMTU; 26146f3ff79SMike Smith ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 26246f3ff79SMike Smith ifp->if_ioctl = lpioctl; 26346f3ff79SMike Smith ifp->if_output = lpoutput; 26446f3ff79SMike Smith ifp->if_type = IFT_PARA; 26546f3ff79SMike Smith ifp->if_hdrlen = 0; 26646f3ff79SMike Smith ifp->if_addrlen = 0; 26746f3ff79SMike Smith ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 26846f3ff79SMike Smith if_attach(ifp); 26946f3ff79SMike Smith 27046f3ff79SMike Smith #if NBPFILTER > 0 27146f3ff79SMike Smith bpfattach(ifp, DLT_NULL, LPIPHDRLEN); 27246f3ff79SMike Smith #endif 27346f3ff79SMike Smith 27446f3ff79SMike Smith return (1); 27546f3ff79SMike Smith } 27646f3ff79SMike Smith /* 27746f3ff79SMike Smith * Build the translation tables for the LPIP (BSD unix) protocol. 27846f3ff79SMike Smith * We don't want to calculate these nasties in our tight loop, so we 27946f3ff79SMike Smith * precalculate them when we initialize. 28046f3ff79SMike Smith */ 28146f3ff79SMike Smith static int 28246f3ff79SMike Smith lpinittables (void) 28346f3ff79SMike Smith { 28446f3ff79SMike Smith int i; 28546f3ff79SMike Smith 28646f3ff79SMike Smith if (!txmith) 28746f3ff79SMike Smith txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 28846f3ff79SMike Smith 28946f3ff79SMike Smith if (!txmith) 29046f3ff79SMike Smith return 1; 29146f3ff79SMike Smith 29246f3ff79SMike Smith if (!ctxmith) 29346f3ff79SMike Smith ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 29446f3ff79SMike Smith 29546f3ff79SMike Smith if (!ctxmith) 29646f3ff79SMike Smith return 1; 29746f3ff79SMike Smith 29846f3ff79SMike Smith for (i=0; i < LPIPTBLSIZE; i++) { 29946f3ff79SMike Smith ctxmith[i] = (i & 0xF0) >> 4; 30046f3ff79SMike Smith ctxmitl[i] = 0x10 | (i & 0x0F); 30146f3ff79SMike Smith ctrecvh[i] = (i & 0x78) << 1; 30246f3ff79SMike Smith ctrecvl[i] = (i & 0x78) >> 3; 30346f3ff79SMike Smith } 30446f3ff79SMike Smith 30546f3ff79SMike Smith for (i=0; i < LPIPTBLSIZE; i++) { 30646f3ff79SMike Smith txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 30746f3ff79SMike Smith txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 30846f3ff79SMike Smith trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 30946f3ff79SMike Smith trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 31046f3ff79SMike Smith } 31146f3ff79SMike Smith 31246f3ff79SMike Smith return 0; 31346f3ff79SMike Smith } 31446f3ff79SMike Smith 31546f3ff79SMike Smith /* 31646f3ff79SMike Smith * Process an ioctl request. 31746f3ff79SMike Smith */ 31846f3ff79SMike Smith 31946f3ff79SMike Smith static int 32046f3ff79SMike Smith lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 32146f3ff79SMike Smith { 32246f3ff79SMike Smith struct lpt_softc *sc = lpdata[ifp->if_unit]; 32346f3ff79SMike Smith struct ifaddr *ifa = (struct ifaddr *)data; 32446f3ff79SMike Smith struct ifreq *ifr = (struct ifreq *)data; 32546f3ff79SMike Smith u_char *ptr; 32646f3ff79SMike Smith int error; 32746f3ff79SMike Smith 32846f3ff79SMike Smith switch (cmd) { 32946f3ff79SMike Smith 33046f3ff79SMike Smith case SIOCSIFDSTADDR: 33146f3ff79SMike Smith case SIOCAIFADDR: 33246f3ff79SMike Smith case SIOCSIFADDR: 33346f3ff79SMike Smith if (ifa->ifa_addr->sa_family != AF_INET) 33446f3ff79SMike Smith return EAFNOSUPPORT; 33546f3ff79SMike Smith 33646f3ff79SMike Smith ifp->if_flags |= IFF_UP; 33746f3ff79SMike Smith /* FALLTHROUGH */ 33846f3ff79SMike Smith case SIOCSIFFLAGS: 33946f3ff79SMike Smith if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 34046f3ff79SMike Smith 34146f3ff79SMike Smith ppb_wctr(&sc->lp_dev, 0x00); 34246f3ff79SMike Smith ifp->if_flags &= ~IFF_RUNNING; 34346f3ff79SMike Smith 34446f3ff79SMike Smith /* IFF_UP is not set, try to release the bus anyway */ 34546f3ff79SMike Smith ppb_release_bus(&sc->lp_dev); 34646f3ff79SMike Smith break; 34746f3ff79SMike Smith } 34846f3ff79SMike Smith if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 34946f3ff79SMike Smith 35046f3ff79SMike Smith /* 35146f3ff79SMike Smith * Try to allocate the ppbus as soon as possible 35246f3ff79SMike Smith * With ppbus allocation, interrupts are enabled 35346f3ff79SMike Smith * Now IFF_UP means that we own the bus 35446f3ff79SMike Smith * 35546f3ff79SMike Smith * XXX 35646f3ff79SMike Smith * Should the request be interruptible? 35746f3ff79SMike Smith */ 35846f3ff79SMike Smith if ((error = ppb_request_bus(&sc->lp_dev, PPB_WAIT|PPB_INTR))) 35946f3ff79SMike Smith return (error); 36046f3ff79SMike Smith 36146f3ff79SMike Smith if (lpinittables()) { 36246f3ff79SMike Smith ppb_release_bus(&sc->lp_dev); 36346f3ff79SMike Smith return ENOBUFS; 36446f3ff79SMike Smith } 36546f3ff79SMike Smith 36646f3ff79SMike Smith sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, 36746f3ff79SMike Smith M_DEVBUF, M_WAITOK); 36846f3ff79SMike Smith if (!sc->sc_ifbuf) { 36946f3ff79SMike Smith ppb_release_bus(&sc->lp_dev); 37046f3ff79SMike Smith return ENOBUFS; 37146f3ff79SMike Smith } 37246f3ff79SMike Smith 37346f3ff79SMike Smith ppb_wctr(&sc->lp_dev, LPC_ENA); 37446f3ff79SMike Smith ifp->if_flags |= IFF_RUNNING; 37546f3ff79SMike Smith } 37646f3ff79SMike Smith break; 37746f3ff79SMike Smith 37846f3ff79SMike Smith case SIOCSIFMTU: 37946f3ff79SMike Smith ptr = sc->sc_ifbuf; 38046f3ff79SMike Smith sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 38146f3ff79SMike Smith if (!sc->sc_ifbuf) { 38246f3ff79SMike Smith sc->sc_ifbuf = ptr; 38346f3ff79SMike Smith return ENOBUFS; 38446f3ff79SMike Smith } 38546f3ff79SMike Smith if (ptr) 38646f3ff79SMike Smith free(ptr,M_DEVBUF); 38746f3ff79SMike Smith sc->sc_if.if_mtu = ifr->ifr_mtu; 38846f3ff79SMike Smith break; 38946f3ff79SMike Smith 39046f3ff79SMike Smith case SIOCGIFMTU: 39146f3ff79SMike Smith ifr->ifr_mtu = sc->sc_if.if_mtu; 39246f3ff79SMike Smith break; 39346f3ff79SMike Smith 39446f3ff79SMike Smith case SIOCADDMULTI: 39546f3ff79SMike Smith case SIOCDELMULTI: 39646f3ff79SMike Smith if (ifr == 0) { 39746f3ff79SMike Smith return EAFNOSUPPORT; /* XXX */ 39846f3ff79SMike Smith } 39946f3ff79SMike Smith switch (ifr->ifr_addr.sa_family) { 40046f3ff79SMike Smith 40146f3ff79SMike Smith case AF_INET: 40246f3ff79SMike Smith break; 40346f3ff79SMike Smith 40446f3ff79SMike Smith default: 40546f3ff79SMike Smith return EAFNOSUPPORT; 40646f3ff79SMike Smith } 40746f3ff79SMike Smith break; 40846f3ff79SMike Smith 40946f3ff79SMike Smith default: 41046f3ff79SMike Smith lprintf("LP:ioctl(0x%x)\n",cmd); 41146f3ff79SMike Smith return EINVAL; 41246f3ff79SMike Smith } 41346f3ff79SMike Smith return 0; 41446f3ff79SMike Smith } 41546f3ff79SMike Smith 41646f3ff79SMike Smith static __inline int 41746f3ff79SMike Smith clpoutbyte (u_char byte, int spin, struct ppb_device *dev) 41846f3ff79SMike Smith { 41946f3ff79SMike Smith ppb_wdtr(dev, ctxmitl[byte]); 42046f3ff79SMike Smith while (ppb_rstr(dev) & CLPIP_SHAKE) 42146f3ff79SMike Smith if (--spin == 0) { 42246f3ff79SMike Smith return 1; 42346f3ff79SMike Smith } 42446f3ff79SMike Smith ppb_wdtr(dev, ctxmith[byte]); 42546f3ff79SMike Smith while (!(ppb_rstr(dev) & CLPIP_SHAKE)) 42646f3ff79SMike Smith if (--spin == 0) { 42746f3ff79SMike Smith return 1; 42846f3ff79SMike Smith } 42946f3ff79SMike Smith return 0; 43046f3ff79SMike Smith } 43146f3ff79SMike Smith 43246f3ff79SMike Smith static __inline int 43346f3ff79SMike Smith clpinbyte (int spin, struct ppb_device *dev) 43446f3ff79SMike Smith { 43546f3ff79SMike Smith int c, cl; 43646f3ff79SMike Smith 43746f3ff79SMike Smith while((ppb_rstr(dev) & CLPIP_SHAKE)) 43846f3ff79SMike Smith if(!--spin) { 43946f3ff79SMike Smith return -1; 44046f3ff79SMike Smith } 44146f3ff79SMike Smith cl = ppb_rstr(dev); 44246f3ff79SMike Smith ppb_wdtr(dev, 0x10); 44346f3ff79SMike Smith 44446f3ff79SMike Smith while(!(ppb_rstr(dev) & CLPIP_SHAKE)) 44546f3ff79SMike Smith if(!--spin) { 44646f3ff79SMike Smith return -1; 44746f3ff79SMike Smith } 44846f3ff79SMike Smith c = ppb_rstr(dev); 44946f3ff79SMike Smith ppb_wdtr(dev, 0x00); 45046f3ff79SMike Smith 45146f3ff79SMike Smith return (ctrecvl[cl] | ctrecvh[c]); 45246f3ff79SMike Smith } 45346f3ff79SMike Smith 45446f3ff79SMike Smith static void 45546f3ff79SMike Smith lpintr (int unit) 45646f3ff79SMike Smith { 45746f3ff79SMike Smith struct lpt_softc *sc = lpdata[unit]; 45846f3ff79SMike Smith int len, s, j; 45946f3ff79SMike Smith u_char *bp; 46046f3ff79SMike Smith u_char c, cl; 46146f3ff79SMike Smith struct mbuf *top; 46246f3ff79SMike Smith 46346f3ff79SMike Smith s = splhigh(); 46446f3ff79SMike Smith 46546f3ff79SMike Smith if (sc->sc_if.if_flags & IFF_LINK0) { 46646f3ff79SMike Smith 46746f3ff79SMike Smith /* Ack. the request */ 46846f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, 0x01); 46946f3ff79SMike Smith 47046f3ff79SMike Smith /* Get the packet length */ 47146f3ff79SMike Smith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 47246f3ff79SMike Smith if (j == -1) 47346f3ff79SMike Smith goto err; 47446f3ff79SMike Smith len = j; 47546f3ff79SMike Smith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 47646f3ff79SMike Smith if (j == -1) 47746f3ff79SMike Smith goto err; 47846f3ff79SMike Smith len = len + (j << 8); 47946f3ff79SMike Smith if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) 48046f3ff79SMike Smith goto err; 48146f3ff79SMike Smith 48246f3ff79SMike Smith bp = sc->sc_ifbuf; 48346f3ff79SMike Smith 48446f3ff79SMike Smith while (len--) { 48546f3ff79SMike Smith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 48646f3ff79SMike Smith if (j == -1) { 48746f3ff79SMike Smith goto err; 48846f3ff79SMike Smith } 48946f3ff79SMike Smith *bp++ = j; 49046f3ff79SMike Smith } 49146f3ff79SMike Smith /* Get and ignore checksum */ 49246f3ff79SMike Smith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 49346f3ff79SMike Smith if (j == -1) { 49446f3ff79SMike Smith goto err; 49546f3ff79SMike Smith } 49646f3ff79SMike Smith 49746f3ff79SMike Smith len = bp - sc->sc_ifbuf; 49846f3ff79SMike Smith if (len <= CLPIPHDRLEN) 49946f3ff79SMike Smith goto err; 50046f3ff79SMike Smith 50146f3ff79SMike Smith sc->sc_iferrs = 0; 50246f3ff79SMike Smith 50346f3ff79SMike Smith if (IF_QFULL(&ipintrq)) { 50446f3ff79SMike Smith lprintf("DROP"); 50546f3ff79SMike Smith IF_DROP(&ipintrq); 50646f3ff79SMike Smith goto done; 50746f3ff79SMike Smith } 50846f3ff79SMike Smith len -= CLPIPHDRLEN; 50946f3ff79SMike Smith sc->sc_if.if_ipackets++; 51046f3ff79SMike Smith sc->sc_if.if_ibytes += len; 51146f3ff79SMike Smith top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); 51246f3ff79SMike Smith if (top) { 51346f3ff79SMike Smith IF_ENQUEUE(&ipintrq, top); 51446f3ff79SMike Smith schednetisr(NETISR_IP); 51546f3ff79SMike Smith } 51646f3ff79SMike Smith goto done; 51746f3ff79SMike Smith } 51846f3ff79SMike Smith while ((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) { 51946f3ff79SMike Smith len = sc->sc_if.if_mtu + LPIPHDRLEN; 52046f3ff79SMike Smith bp = sc->sc_ifbuf; 52146f3ff79SMike Smith while (len--) { 52246f3ff79SMike Smith 52346f3ff79SMike Smith cl = ppb_rstr(&sc->lp_dev); 52446f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, 8); 52546f3ff79SMike Smith 52646f3ff79SMike Smith j = LPMAXSPIN2; 52746f3ff79SMike Smith while((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) 52846f3ff79SMike Smith if(!--j) goto err; 52946f3ff79SMike Smith 53046f3ff79SMike Smith c = ppb_rstr(&sc->lp_dev); 53146f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, 0); 53246f3ff79SMike Smith 53346f3ff79SMike Smith *bp++= trecvh[cl] | trecvl[c]; 53446f3ff79SMike Smith 53546f3ff79SMike Smith j = LPMAXSPIN2; 53646f3ff79SMike Smith while (!((cl=ppb_rstr(&sc->lp_dev)) & LPIP_SHAKE)) { 53746f3ff79SMike Smith if (cl != c && 53846f3ff79SMike Smith (((cl = ppb_rstr(&sc->lp_dev)) ^ 0xb8) & 0xf8) == 53946f3ff79SMike Smith (c & 0xf8)) 54046f3ff79SMike Smith goto end; 54146f3ff79SMike Smith if (!--j) goto err; 54246f3ff79SMike Smith } 54346f3ff79SMike Smith } 54446f3ff79SMike Smith 54546f3ff79SMike Smith end: 54646f3ff79SMike Smith len = bp - sc->sc_ifbuf; 54746f3ff79SMike Smith if (len <= LPIPHDRLEN) 54846f3ff79SMike Smith goto err; 54946f3ff79SMike Smith 55046f3ff79SMike Smith sc->sc_iferrs = 0; 55146f3ff79SMike Smith 55246f3ff79SMike Smith if (IF_QFULL(&ipintrq)) { 55346f3ff79SMike Smith lprintf("DROP"); 55446f3ff79SMike Smith IF_DROP(&ipintrq); 55546f3ff79SMike Smith goto done; 55646f3ff79SMike Smith } 55746f3ff79SMike Smith #if NBPFILTER > 0 55846f3ff79SMike Smith if (sc->sc_if.if_bpf) { 55946f3ff79SMike Smith bpf_tap(&sc->sc_if, sc->sc_ifbuf, len); 56046f3ff79SMike Smith } 56146f3ff79SMike Smith #endif 56246f3ff79SMike Smith len -= LPIPHDRLEN; 56346f3ff79SMike Smith sc->sc_if.if_ipackets++; 56446f3ff79SMike Smith sc->sc_if.if_ibytes += len; 56546f3ff79SMike Smith top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); 56646f3ff79SMike Smith if (top) { 56746f3ff79SMike Smith IF_ENQUEUE(&ipintrq, top); 56846f3ff79SMike Smith schednetisr(NETISR_IP); 56946f3ff79SMike Smith } 57046f3ff79SMike Smith } 57146f3ff79SMike Smith goto done; 57246f3ff79SMike Smith 57346f3ff79SMike Smith err: 57446f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, 0); 57546f3ff79SMike Smith lprintf("R"); 57646f3ff79SMike Smith sc->sc_if.if_ierrors++; 57746f3ff79SMike Smith sc->sc_iferrs++; 57846f3ff79SMike Smith 57946f3ff79SMike Smith /* 58046f3ff79SMike Smith * We are not able to send receive anything for now, 58146f3ff79SMike Smith * so stop wasting our time 58246f3ff79SMike Smith */ 58346f3ff79SMike Smith if (sc->sc_iferrs > LPMAXERRS) { 58446f3ff79SMike Smith printf("lp%d: Too many errors, Going off-line.\n", unit); 58546f3ff79SMike Smith ppb_wctr(&sc->lp_dev, 0x00); 58646f3ff79SMike Smith sc->sc_if.if_flags &= ~IFF_RUNNING; 58746f3ff79SMike Smith sc->sc_iferrs=0; 58846f3ff79SMike Smith } 58946f3ff79SMike Smith 59046f3ff79SMike Smith done: 59146f3ff79SMike Smith splx(s); 59246f3ff79SMike Smith return; 59346f3ff79SMike Smith } 59446f3ff79SMike Smith 59546f3ff79SMike Smith static __inline int 59646f3ff79SMike Smith lpoutbyte (u_char byte, int spin, struct ppb_device *dev) 59746f3ff79SMike Smith { 59846f3ff79SMike Smith ppb_wdtr(dev, txmith[byte]); 59946f3ff79SMike Smith while (!(ppb_rstr(dev) & LPIP_SHAKE)) 60046f3ff79SMike Smith if (--spin == 0) 60146f3ff79SMike Smith return 1; 60246f3ff79SMike Smith ppb_wdtr(dev, txmitl[byte]); 60346f3ff79SMike Smith while (ppb_rstr(dev) & LPIP_SHAKE) 60446f3ff79SMike Smith if (--spin == 0) 60546f3ff79SMike Smith return 1; 60646f3ff79SMike Smith return 0; 60746f3ff79SMike Smith } 60846f3ff79SMike Smith 60946f3ff79SMike Smith static int 61046f3ff79SMike Smith lpoutput (struct ifnet *ifp, struct mbuf *m, 61146f3ff79SMike Smith struct sockaddr *dst, struct rtentry *rt) 61246f3ff79SMike Smith { 61346f3ff79SMike Smith struct lpt_softc *sc = lpdata[ifp->if_unit]; 61446f3ff79SMike Smith int s, err; 61546f3ff79SMike Smith struct mbuf *mm; 61646f3ff79SMike Smith u_char *cp = "\0\0"; 61746f3ff79SMike Smith u_char chksum = 0; 61846f3ff79SMike Smith int count = 0; 61946f3ff79SMike Smith int i; 62046f3ff79SMike Smith int spin; 62146f3ff79SMike Smith 62246f3ff79SMike Smith /* We need a sensible value if we abort */ 62346f3ff79SMike Smith cp++; 62446f3ff79SMike Smith ifp->if_flags |= IFF_RUNNING; 62546f3ff79SMike Smith 62646f3ff79SMike Smith err = 1; /* assume we're aborting because of an error */ 62746f3ff79SMike Smith 62846f3ff79SMike Smith s = splhigh(); 62946f3ff79SMike Smith 63046f3ff79SMike Smith /* Suspend (on laptops) or receive-errors might have taken us offline */ 63146f3ff79SMike Smith ppb_wctr(&sc->lp_dev, LPC_ENA); 63246f3ff79SMike Smith 63346f3ff79SMike Smith if (ifp->if_flags & IFF_LINK0) { 63446f3ff79SMike Smith 63546f3ff79SMike Smith if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) { 63646f3ff79SMike Smith lprintf("&"); 63746f3ff79SMike Smith lpintr(ifp->if_unit); 63846f3ff79SMike Smith } 63946f3ff79SMike Smith 64046f3ff79SMike Smith /* Alert other end to pending packet */ 64146f3ff79SMike Smith spin = LPMAXSPIN1; 64246f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, 0x08); 64346f3ff79SMike Smith while ((ppb_rstr(&sc->lp_dev) & 0x08) == 0) 64446f3ff79SMike Smith if (--spin == 0) { 64546f3ff79SMike Smith goto nend; 64646f3ff79SMike Smith } 64746f3ff79SMike Smith 64846f3ff79SMike Smith /* Calculate length of packet, then send that */ 64946f3ff79SMike Smith 65046f3ff79SMike Smith count += 14; /* Ethernet header len */ 65146f3ff79SMike Smith 65246f3ff79SMike Smith mm = m; 65346f3ff79SMike Smith for (mm = m; mm; mm = mm->m_next) { 65446f3ff79SMike Smith count += mm->m_len; 65546f3ff79SMike Smith } 65646f3ff79SMike Smith if (clpoutbyte(count & 0xFF, LPMAXSPIN1, &sc->lp_dev)) 65746f3ff79SMike Smith goto nend; 65846f3ff79SMike Smith if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, &sc->lp_dev)) 65946f3ff79SMike Smith goto nend; 66046f3ff79SMike Smith 66146f3ff79SMike Smith /* Send dummy ethernet header */ 66246f3ff79SMike Smith for (i = 0; i < 12; i++) { 66346f3ff79SMike Smith if (clpoutbyte(i, LPMAXSPIN1, &sc->lp_dev)) 66446f3ff79SMike Smith goto nend; 66546f3ff79SMike Smith chksum += i; 66646f3ff79SMike Smith } 66746f3ff79SMike Smith 66846f3ff79SMike Smith if (clpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev)) 66946f3ff79SMike Smith goto nend; 67046f3ff79SMike Smith if (clpoutbyte(0x00, LPMAXSPIN1, &sc->lp_dev)) 67146f3ff79SMike Smith goto nend; 67246f3ff79SMike Smith chksum += 0x08 + 0x00; /* Add into checksum */ 67346f3ff79SMike Smith 67446f3ff79SMike Smith mm = m; 67546f3ff79SMike Smith do { 67646f3ff79SMike Smith cp = mtod(mm, u_char *); 67746f3ff79SMike Smith while (mm->m_len--) { 67846f3ff79SMike Smith chksum += *cp; 67946f3ff79SMike Smith if (clpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev)) 68046f3ff79SMike Smith goto nend; 68146f3ff79SMike Smith } 68246f3ff79SMike Smith } while ((mm = mm->m_next)); 68346f3ff79SMike Smith 68446f3ff79SMike Smith /* Send checksum */ 68546f3ff79SMike Smith if (clpoutbyte(chksum, LPMAXSPIN2, &sc->lp_dev)) 68646f3ff79SMike Smith goto nend; 68746f3ff79SMike Smith 68846f3ff79SMike Smith /* Go quiescent */ 68946f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, 0); 69046f3ff79SMike Smith 69146f3ff79SMike Smith err = 0; /* No errors */ 69246f3ff79SMike Smith 69346f3ff79SMike Smith nend: 69446f3ff79SMike Smith if (err) { /* if we didn't timeout... */ 69546f3ff79SMike Smith ifp->if_oerrors++; 69646f3ff79SMike Smith lprintf("X"); 69746f3ff79SMike Smith } else { 69846f3ff79SMike Smith ifp->if_opackets++; 69946f3ff79SMike Smith ifp->if_obytes += m->m_pkthdr.len; 70046f3ff79SMike Smith } 70146f3ff79SMike Smith 70246f3ff79SMike Smith m_freem(m); 70346f3ff79SMike Smith 70446f3ff79SMike Smith if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) { 70546f3ff79SMike Smith lprintf("^"); 70646f3ff79SMike Smith lpintr(ifp->if_unit); 70746f3ff79SMike Smith } 70846f3ff79SMike Smith (void) splx(s); 70946f3ff79SMike Smith return 0; 71046f3ff79SMike Smith } 71146f3ff79SMike Smith 71246f3ff79SMike Smith if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) { 71346f3ff79SMike Smith lprintf("&"); 71446f3ff79SMike Smith lpintr(ifp->if_unit); 71546f3ff79SMike Smith } 71646f3ff79SMike Smith 71746f3ff79SMike Smith if (lpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev)) 71846f3ff79SMike Smith goto end; 71946f3ff79SMike Smith if (lpoutbyte(0x00, LPMAXSPIN2, &sc->lp_dev)) 72046f3ff79SMike Smith goto end; 72146f3ff79SMike Smith 72246f3ff79SMike Smith mm = m; 72346f3ff79SMike Smith do { 72446f3ff79SMike Smith cp = mtod(mm,u_char *); 72546f3ff79SMike Smith while (mm->m_len--) 72646f3ff79SMike Smith if (lpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev)) 72746f3ff79SMike Smith goto end; 72846f3ff79SMike Smith } while ((mm = mm->m_next)); 72946f3ff79SMike Smith 73046f3ff79SMike Smith err = 0; /* no errors were encountered */ 73146f3ff79SMike Smith 73246f3ff79SMike Smith end: 73346f3ff79SMike Smith --cp; 73446f3ff79SMike Smith ppb_wdtr(&sc->lp_dev, txmitl[*cp] ^ 0x17); 73546f3ff79SMike Smith 73646f3ff79SMike Smith if (err) { /* if we didn't timeout... */ 73746f3ff79SMike Smith ifp->if_oerrors++; 73846f3ff79SMike Smith lprintf("X"); 73946f3ff79SMike Smith } else { 74046f3ff79SMike Smith ifp->if_opackets++; 74146f3ff79SMike Smith ifp->if_obytes += m->m_pkthdr.len; 74246f3ff79SMike Smith #if NBPFILTER > 0 74346f3ff79SMike Smith if (ifp->if_bpf) { 74446f3ff79SMike Smith /* 74546f3ff79SMike Smith * We need to prepend the packet type as 74646f3ff79SMike Smith * a two byte field. Cons up a dummy header 74746f3ff79SMike Smith * to pacify bpf. This is safe because bpf 74846f3ff79SMike Smith * will only read from the mbuf (i.e., it won't 74946f3ff79SMike Smith * try to free it or keep a pointer to it). 75046f3ff79SMike Smith */ 75146f3ff79SMike Smith struct mbuf m0; 75246f3ff79SMike Smith u_short hdr = 0x800; 75346f3ff79SMike Smith 75446f3ff79SMike Smith m0.m_next = m; 75546f3ff79SMike Smith m0.m_len = 2; 75646f3ff79SMike Smith m0.m_data = (char *)&hdr; 75746f3ff79SMike Smith 75846f3ff79SMike Smith bpf_mtap(ifp, &m0); 75946f3ff79SMike Smith } 76046f3ff79SMike Smith #endif 76146f3ff79SMike Smith } 76246f3ff79SMike Smith 76346f3ff79SMike Smith m_freem(m); 76446f3ff79SMike Smith 76546f3ff79SMike Smith if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) { 76646f3ff79SMike Smith lprintf("^"); 76746f3ff79SMike Smith lpintr(ifp->if_unit); 76846f3ff79SMike Smith } 76946f3ff79SMike Smith 77046f3ff79SMike Smith (void) splx(s); 77146f3ff79SMike Smith return 0; 77246f3ff79SMike Smith } 773