if_plip.c revision 42443
138061Smsmith/*- 238061Smsmith * Copyright (c) 1997 Poul-Henning Kamp 338061Smsmith * All rights reserved. 438061Smsmith * 538061Smsmith * Redistribution and use in source and binary forms, with or without 638061Smsmith * modification, are permitted provided that the following conditions 738061Smsmith * are met: 838061Smsmith * 1. Redistributions of source code must retain the above copyright 938061Smsmith * notice, this list of conditions and the following disclaimer. 1038061Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138061Smsmith * notice, this list of conditions and the following disclaimer in the 1238061Smsmith * documentation and/or other materials provided with the distribution. 1338061Smsmith * 1438061Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538061Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638061Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738061Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838061Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938061Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038061Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138061Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238061Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338061Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438061Smsmith * SUCH DAMAGE. 2538061Smsmith * 2638061Smsmith * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 2742443Snsouch * $Id: if_plip.c,v 1.6 1998/11/07 14:35:41 nsouch Exp $ 2838061Smsmith */ 2938061Smsmith 3038061Smsmith/* 3138061Smsmith * Parallel port TCP/IP interfaces added. I looked at the driver from 3238061Smsmith * MACH but this is a complete rewrite, and btw. incompatible, and it 3338061Smsmith * should perform better too. I have never run the MACH driver though. 3438061Smsmith * 3538061Smsmith * This driver sends two bytes (0x08, 0x00) in front of each packet, 3638061Smsmith * to allow us to distinguish another format later. 3738061Smsmith * 3838061Smsmith * Now added an Linux/Crynwr compatibility mode which is enabled using 3938061Smsmith * IF_LINK0 - Tim Wilkinson. 4038061Smsmith * 4138061Smsmith * TODO: 4238061Smsmith * Make HDLC/PPP mode, use IF_LLC1 to enable. 4338061Smsmith * 4438061Smsmith * Connect the two computers using a Laplink parallel cable to use this 4538061Smsmith * feature: 4638061Smsmith * 4738061Smsmith * +----------------------------------------+ 4838061Smsmith * |A-name A-End B-End Descr. Port/Bit | 4938061Smsmith * +----------------------------------------+ 5038061Smsmith * |DATA0 2 15 Data 0/0x01 | 5138061Smsmith * |-ERROR 15 2 1/0x08 | 5238061Smsmith * +----------------------------------------+ 5338061Smsmith * |DATA1 3 13 Data 0/0x02 | 5438061Smsmith * |+SLCT 13 3 1/0x10 | 5538061Smsmith * +----------------------------------------+ 5638061Smsmith * |DATA2 4 12 Data 0/0x04 | 5738061Smsmith * |+PE 12 4 1/0x20 | 5838061Smsmith * +----------------------------------------+ 5938061Smsmith * |DATA3 5 10 Strobe 0/0x08 | 6038061Smsmith * |-ACK 10 5 1/0x40 | 6138061Smsmith * +----------------------------------------+ 6238061Smsmith * |DATA4 6 11 Data 0/0x10 | 6338061Smsmith * |BUSY 11 6 1/~0x80 | 6438061Smsmith * +----------------------------------------+ 6538061Smsmith * |GND 18-25 18-25 GND - | 6638061Smsmith * +----------------------------------------+ 6738061Smsmith * 6838061Smsmith * Expect transfer-rates up to 75 kbyte/sec. 6938061Smsmith * 7038061Smsmith * If GCC could correctly grok 7138061Smsmith * register int port asm("edx") 7238061Smsmith * the code would be cleaner 7338061Smsmith * 7438061Smsmith * Poul-Henning Kamp <phk@freebsd.org> 7538061Smsmith */ 7638061Smsmith 7738061Smsmith/* 7838061Smsmith * Update for ppbus, PLIP support only - Nicolas Souchu 7938061Smsmith */ 8038061Smsmith 8138061Smsmith#include <sys/param.h> 8238061Smsmith#include <sys/systm.h> 8338061Smsmith#include <sys/mbuf.h> 8438061Smsmith#include <sys/socket.h> 8538061Smsmith#include <sys/sockio.h> 8638061Smsmith#include <sys/kernel.h> 8738061Smsmith#include <sys/malloc.h> 8838061Smsmith 8938061Smsmith#include <net/if.h> 9038061Smsmith#include <net/if_types.h> 9138061Smsmith#include <net/netisr.h> 9238061Smsmith 9338061Smsmith#include <netinet/in.h> 9438061Smsmith#include <netinet/in_var.h> 9538061Smsmith 9638061Smsmith#include "bpfilter.h" 9738061Smsmith#if NBPFILTER > 0 9838061Smsmith#include <net/bpf.h> 9938061Smsmith#endif 10038061Smsmith 10138061Smsmith#include <dev/ppbus/ppbconf.h> 10238061Smsmith#include <dev/ppbus/nlpt.h> 10338061Smsmith 10438061Smsmith#ifndef LPMTU /* MTU for the lp# interfaces */ 10538061Smsmith#define LPMTU 1500 10638061Smsmith#endif 10738061Smsmith 10838061Smsmith#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 10938061Smsmith#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 11038061Smsmith#endif 11138061Smsmith 11238061Smsmith#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 11338061Smsmith#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 11438061Smsmith#endif 11538061Smsmith 11638061Smsmith#ifndef LPMAXERRS /* Max errors before !RUNNING */ 11738061Smsmith#define LPMAXERRS 100 11838061Smsmith#endif 11938061Smsmith 12038061Smsmith#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 12138061Smsmith#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 12238061Smsmith#define MLPIPHDRLEN CLPIPHDRLEN 12338061Smsmith 12438061Smsmith#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 12538061Smsmith#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 12638061Smsmith#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 12738061Smsmith#define MLPIPHDRLEN LPIPHDRLEN 12838061Smsmith#endif 12938061Smsmith 13038061Smsmith#define LPIPTBLSIZE 256 /* Size of octet translation table */ 13138061Smsmith 13240993Snsouch#ifndef DEBUG 13338061Smsmith#define DEBUG 13440993Snsouch#endif 13538061Smsmith 13638061Smsmith#ifndef DEBUG 13738061Smsmith#define lprintf (void) 13838061Smsmith#else 13938061Smsmith#define lprintf if (lptflag) printf 14038061Smsmithstatic int volatile lptflag = 1; 14138061Smsmith#endif 14238061Smsmith 14338061Smsmithstruct lpt_softc { 14438061Smsmith unsigned short lp_unit; 14538061Smsmith 14638061Smsmith struct ppb_device lp_dev; 14738061Smsmith 14838061Smsmith struct ifnet sc_if; 14938061Smsmith u_char *sc_ifbuf; 15038061Smsmith int sc_iferrs; 15138061Smsmith}; 15238061Smsmith 15338061Smsmithstatic int nlp = 0; 15438061Smsmith#define MAXPLIP 8 /* XXX not much better! */ 15538061Smsmithstatic struct lpt_softc *lpdata[MAXPLIP]; 15638061Smsmith 15738061Smsmith 15838061Smsmith/* Tables for the lp# interface */ 15938061Smsmithstatic u_char *txmith; 16038061Smsmith#define txmitl (txmith+(1*LPIPTBLSIZE)) 16138061Smsmith#define trecvh (txmith+(2*LPIPTBLSIZE)) 16238061Smsmith#define trecvl (txmith+(3*LPIPTBLSIZE)) 16338061Smsmith 16438061Smsmithstatic u_char *ctxmith; 16538061Smsmith#define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 16638061Smsmith#define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 16738061Smsmith#define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 16838061Smsmith 16938061Smsmith/* Functions for the lp# interface */ 17038061Smsmithstatic struct ppb_device *lpprobe(struct ppb_data *); 17138061Smsmithstatic int lpattach(struct ppb_device *); 17238061Smsmith 17338061Smsmithstatic int lpinittables(void); 17438061Smsmithstatic int lpioctl(struct ifnet *, u_long, caddr_t); 17538061Smsmithstatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 17638061Smsmith struct rtentry *); 17738061Smsmithstatic void lpintr(int); 17838061Smsmith 17938061Smsmith/* 18038061Smsmith * Make ourselves visible as a ppbus driver 18138061Smsmith */ 18238061Smsmith 18338061Smsmithstatic struct ppb_driver lpdriver = { 18438061Smsmith lpprobe, lpattach, "lp" 18538061Smsmith}; 18638061SmsmithDATA_SET(ppbdriver_set, lpdriver); 18738061Smsmith 18838061Smsmith 18938061Smsmith/* 19038061Smsmith * lpprobe() 19138061Smsmith */ 19238061Smsmithstatic struct ppb_device * 19338061Smsmithlpprobe(struct ppb_data *ppb) 19438061Smsmith{ 19538061Smsmith struct lpt_softc *lp; 19638061Smsmith 19738061Smsmith /* if we haven't interrupts, the probe fails */ 19838061Smsmith if (!ppb->ppb_link->id_irq) 19938061Smsmith return (0); 20038061Smsmith 20138061Smsmith lp = (struct lpt_softc *) malloc(sizeof(struct lpt_softc), 20238061Smsmith M_TEMP, M_NOWAIT); 20338061Smsmith if (!lp) { 20438061Smsmith printf("lp: cannot malloc!\n"); 20538061Smsmith return (0); 20638061Smsmith } 20738061Smsmith bzero(lp, sizeof(struct lpt_softc)); 20838061Smsmith 20938061Smsmith lpdata[nlp] = lp; 21038061Smsmith 21138061Smsmith /* 21238061Smsmith * lp dependent initialisation. 21338061Smsmith */ 21438061Smsmith lp->lp_unit = nlp; 21538061Smsmith 21638061Smsmith if (bootverbose) 21740039Sdes printf("plip: irq %d\n", ppb->ppb_link->id_irq); 21838061Smsmith 21938061Smsmith /* 22038061Smsmith * ppbus dependent initialisation. 22138061Smsmith */ 22238061Smsmith lp->lp_dev.id_unit = lp->lp_unit; 22338061Smsmith lp->lp_dev.name = lpdriver.name; 22438061Smsmith lp->lp_dev.ppb = ppb; 22538061Smsmith lp->lp_dev.intr = lpintr; 22638061Smsmith 22738061Smsmith /* Ok, go to next device on next probe */ 22838061Smsmith nlp ++; 22938061Smsmith 23038061Smsmith return (&lp->lp_dev); 23138061Smsmith} 23238061Smsmith 23338061Smsmithstatic int 23438061Smsmithlpattach (struct ppb_device *dev) 23538061Smsmith{ 23638061Smsmith int unit = dev->id_unit; 23738061Smsmith struct lpt_softc *sc = lpdata[unit]; 23838061Smsmith struct ifnet *ifp = &sc->sc_if; 23938061Smsmith 24038061Smsmith /* 24138061Smsmith * Report ourselves 24238061Smsmith */ 24338061Smsmith printf("plip%d: <PLIP network interface> on ppbus %d\n", 24438061Smsmith dev->id_unit, dev->ppb->ppb_link->adapter_unit); 24538061Smsmith 24638061Smsmith ifp->if_softc = sc; 24738061Smsmith ifp->if_name = "lp"; 24838061Smsmith ifp->if_unit = unit; 24938061Smsmith ifp->if_mtu = LPMTU; 25038061Smsmith ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 25138061Smsmith ifp->if_ioctl = lpioctl; 25238061Smsmith ifp->if_output = lpoutput; 25338061Smsmith ifp->if_type = IFT_PARA; 25438061Smsmith ifp->if_hdrlen = 0; 25538061Smsmith ifp->if_addrlen = 0; 25638061Smsmith ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 25738061Smsmith if_attach(ifp); 25838061Smsmith 25938061Smsmith#if NBPFILTER > 0 26038061Smsmith bpfattach(ifp, DLT_NULL, LPIPHDRLEN); 26138061Smsmith#endif 26238061Smsmith 26338061Smsmith return (1); 26438061Smsmith} 26538061Smsmith/* 26638061Smsmith * Build the translation tables for the LPIP (BSD unix) protocol. 26738061Smsmith * We don't want to calculate these nasties in our tight loop, so we 26838061Smsmith * precalculate them when we initialize. 26938061Smsmith */ 27038061Smsmithstatic int 27138061Smsmithlpinittables (void) 27238061Smsmith{ 27338061Smsmith int i; 27438061Smsmith 27538061Smsmith if (!txmith) 27638061Smsmith txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 27738061Smsmith 27838061Smsmith if (!txmith) 27938061Smsmith return 1; 28038061Smsmith 28138061Smsmith if (!ctxmith) 28238061Smsmith ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 28338061Smsmith 28438061Smsmith if (!ctxmith) 28538061Smsmith return 1; 28638061Smsmith 28738061Smsmith for (i=0; i < LPIPTBLSIZE; i++) { 28838061Smsmith ctxmith[i] = (i & 0xF0) >> 4; 28938061Smsmith ctxmitl[i] = 0x10 | (i & 0x0F); 29038061Smsmith ctrecvh[i] = (i & 0x78) << 1; 29138061Smsmith ctrecvl[i] = (i & 0x78) >> 3; 29238061Smsmith } 29338061Smsmith 29438061Smsmith for (i=0; i < LPIPTBLSIZE; i++) { 29538061Smsmith txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 29638061Smsmith txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 29738061Smsmith trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 29838061Smsmith trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 29938061Smsmith } 30038061Smsmith 30138061Smsmith return 0; 30238061Smsmith} 30338061Smsmith 30438061Smsmith/* 30538061Smsmith * Process an ioctl request. 30638061Smsmith */ 30738061Smsmith 30838061Smsmithstatic int 30938061Smsmithlpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 31038061Smsmith{ 31138061Smsmith struct lpt_softc *sc = lpdata[ifp->if_unit]; 31238061Smsmith struct ifaddr *ifa = (struct ifaddr *)data; 31338061Smsmith struct ifreq *ifr = (struct ifreq *)data; 31438061Smsmith u_char *ptr; 31538061Smsmith int error; 31638061Smsmith 31738061Smsmith switch (cmd) { 31838061Smsmith 31938061Smsmith case SIOCSIFDSTADDR: 32038061Smsmith case SIOCAIFADDR: 32138061Smsmith case SIOCSIFADDR: 32238061Smsmith if (ifa->ifa_addr->sa_family != AF_INET) 32338061Smsmith return EAFNOSUPPORT; 32438061Smsmith 32538061Smsmith ifp->if_flags |= IFF_UP; 32638061Smsmith /* FALLTHROUGH */ 32738061Smsmith case SIOCSIFFLAGS: 32838061Smsmith if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 32938061Smsmith 33038061Smsmith ppb_wctr(&sc->lp_dev, 0x00); 33138061Smsmith ifp->if_flags &= ~IFF_RUNNING; 33238061Smsmith 33338061Smsmith /* IFF_UP is not set, try to release the bus anyway */ 33438061Smsmith ppb_release_bus(&sc->lp_dev); 33538061Smsmith break; 33638061Smsmith } 33738061Smsmith if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 33838061Smsmith 33942443Snsouch /* XXX 34038061Smsmith * Should the request be interruptible? 34138061Smsmith */ 34238061Smsmith if ((error = ppb_request_bus(&sc->lp_dev, PPB_WAIT|PPB_INTR))) 34338061Smsmith return (error); 34438061Smsmith 34542443Snsouch /* Now IFF_UP means that we own the bus */ 34642443Snsouch 34742443Snsouch ppb_set_mode(&sc->lp_dev, PPB_COMPATIBLE); 34842443Snsouch 34938061Smsmith if (lpinittables()) { 35038061Smsmith ppb_release_bus(&sc->lp_dev); 35138061Smsmith return ENOBUFS; 35238061Smsmith } 35338061Smsmith 35438061Smsmith sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, 35538061Smsmith M_DEVBUF, M_WAITOK); 35638061Smsmith if (!sc->sc_ifbuf) { 35738061Smsmith ppb_release_bus(&sc->lp_dev); 35838061Smsmith return ENOBUFS; 35938061Smsmith } 36038061Smsmith 36138061Smsmith ppb_wctr(&sc->lp_dev, LPC_ENA); 36238061Smsmith ifp->if_flags |= IFF_RUNNING; 36338061Smsmith } 36438061Smsmith break; 36538061Smsmith 36638061Smsmith case SIOCSIFMTU: 36738061Smsmith ptr = sc->sc_ifbuf; 36838061Smsmith sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 36938061Smsmith if (!sc->sc_ifbuf) { 37038061Smsmith sc->sc_ifbuf = ptr; 37138061Smsmith return ENOBUFS; 37238061Smsmith } 37338061Smsmith if (ptr) 37438061Smsmith free(ptr,M_DEVBUF); 37538061Smsmith sc->sc_if.if_mtu = ifr->ifr_mtu; 37638061Smsmith break; 37738061Smsmith 37838061Smsmith case SIOCGIFMTU: 37938061Smsmith ifr->ifr_mtu = sc->sc_if.if_mtu; 38038061Smsmith break; 38138061Smsmith 38238061Smsmith case SIOCADDMULTI: 38338061Smsmith case SIOCDELMULTI: 38438061Smsmith if (ifr == 0) { 38538061Smsmith return EAFNOSUPPORT; /* XXX */ 38638061Smsmith } 38738061Smsmith switch (ifr->ifr_addr.sa_family) { 38838061Smsmith 38938061Smsmith case AF_INET: 39038061Smsmith break; 39138061Smsmith 39238061Smsmith default: 39338061Smsmith return EAFNOSUPPORT; 39438061Smsmith } 39538061Smsmith break; 39638061Smsmith 39740626Smsmith case SIOCGIFMEDIA: 39840626Smsmith /* 39940626Smsmith * No ifmedia support at this stage; maybe use it 40040626Smsmith * in future for eg. protocol selection. 40140626Smsmith */ 40240626Smsmith return EINVAL; 40340626Smsmith 40438061Smsmith default: 40538373Sbde lprintf("LP:ioctl(0x%lx)\n", cmd); 40638061Smsmith return EINVAL; 40738061Smsmith } 40838061Smsmith return 0; 40938061Smsmith} 41038061Smsmith 41138061Smsmithstatic __inline int 41238061Smsmithclpoutbyte (u_char byte, int spin, struct ppb_device *dev) 41338061Smsmith{ 41438061Smsmith ppb_wdtr(dev, ctxmitl[byte]); 41538061Smsmith while (ppb_rstr(dev) & CLPIP_SHAKE) 41638061Smsmith if (--spin == 0) { 41738061Smsmith return 1; 41838061Smsmith } 41938061Smsmith ppb_wdtr(dev, ctxmith[byte]); 42038061Smsmith while (!(ppb_rstr(dev) & CLPIP_SHAKE)) 42138061Smsmith if (--spin == 0) { 42238061Smsmith return 1; 42338061Smsmith } 42438061Smsmith return 0; 42538061Smsmith} 42638061Smsmith 42738061Smsmithstatic __inline int 42838061Smsmithclpinbyte (int spin, struct ppb_device *dev) 42938061Smsmith{ 43042443Snsouch u_char c, cl; 43138061Smsmith 43238061Smsmith while((ppb_rstr(dev) & CLPIP_SHAKE)) 43338061Smsmith if(!--spin) { 43438061Smsmith return -1; 43538061Smsmith } 43638061Smsmith cl = ppb_rstr(dev); 43738061Smsmith ppb_wdtr(dev, 0x10); 43838061Smsmith 43938061Smsmith while(!(ppb_rstr(dev) & CLPIP_SHAKE)) 44038061Smsmith if(!--spin) { 44138061Smsmith return -1; 44238061Smsmith } 44338061Smsmith c = ppb_rstr(dev); 44438061Smsmith ppb_wdtr(dev, 0x00); 44538061Smsmith 44638061Smsmith return (ctrecvl[cl] | ctrecvh[c]); 44738061Smsmith} 44838061Smsmith 44938061Smsmithstatic void 45038061Smsmithlpintr (int unit) 45138061Smsmith{ 45238061Smsmith struct lpt_softc *sc = lpdata[unit]; 45338061Smsmith int len, s, j; 45438061Smsmith u_char *bp; 45538061Smsmith u_char c, cl; 45638061Smsmith struct mbuf *top; 45738061Smsmith 45838061Smsmith s = splhigh(); 45938061Smsmith 46038061Smsmith if (sc->sc_if.if_flags & IFF_LINK0) { 46138061Smsmith 46238061Smsmith /* Ack. the request */ 46338061Smsmith ppb_wdtr(&sc->lp_dev, 0x01); 46438061Smsmith 46538061Smsmith /* Get the packet length */ 46638061Smsmith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 46738061Smsmith if (j == -1) 46838061Smsmith goto err; 46938061Smsmith len = j; 47038061Smsmith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 47138061Smsmith if (j == -1) 47238061Smsmith goto err; 47338061Smsmith len = len + (j << 8); 47438061Smsmith if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) 47538061Smsmith goto err; 47638061Smsmith 47738061Smsmith bp = sc->sc_ifbuf; 47838061Smsmith 47938061Smsmith while (len--) { 48038061Smsmith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 48138061Smsmith if (j == -1) { 48238061Smsmith goto err; 48338061Smsmith } 48438061Smsmith *bp++ = j; 48538061Smsmith } 48638061Smsmith /* Get and ignore checksum */ 48738061Smsmith j = clpinbyte(LPMAXSPIN2, &sc->lp_dev); 48838061Smsmith if (j == -1) { 48938061Smsmith goto err; 49038061Smsmith } 49138061Smsmith 49238061Smsmith len = bp - sc->sc_ifbuf; 49338061Smsmith if (len <= CLPIPHDRLEN) 49438061Smsmith goto err; 49538061Smsmith 49638061Smsmith sc->sc_iferrs = 0; 49738061Smsmith 49838061Smsmith if (IF_QFULL(&ipintrq)) { 49938061Smsmith lprintf("DROP"); 50038061Smsmith IF_DROP(&ipintrq); 50138061Smsmith goto done; 50238061Smsmith } 50338061Smsmith len -= CLPIPHDRLEN; 50438061Smsmith sc->sc_if.if_ipackets++; 50538061Smsmith sc->sc_if.if_ibytes += len; 50638061Smsmith top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); 50738061Smsmith if (top) { 50838061Smsmith IF_ENQUEUE(&ipintrq, top); 50938061Smsmith schednetisr(NETISR_IP); 51038061Smsmith } 51138061Smsmith goto done; 51238061Smsmith } 51338061Smsmith while ((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) { 51438061Smsmith len = sc->sc_if.if_mtu + LPIPHDRLEN; 51538061Smsmith bp = sc->sc_ifbuf; 51638061Smsmith while (len--) { 51738061Smsmith 51838061Smsmith cl = ppb_rstr(&sc->lp_dev); 51938061Smsmith ppb_wdtr(&sc->lp_dev, 8); 52038061Smsmith 52138061Smsmith j = LPMAXSPIN2; 52238061Smsmith while((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) 52338061Smsmith if(!--j) goto err; 52438061Smsmith 52538061Smsmith c = ppb_rstr(&sc->lp_dev); 52638061Smsmith ppb_wdtr(&sc->lp_dev, 0); 52738061Smsmith 52838061Smsmith *bp++= trecvh[cl] | trecvl[c]; 52938061Smsmith 53038061Smsmith j = LPMAXSPIN2; 53138061Smsmith while (!((cl=ppb_rstr(&sc->lp_dev)) & LPIP_SHAKE)) { 53238061Smsmith if (cl != c && 53338061Smsmith (((cl = ppb_rstr(&sc->lp_dev)) ^ 0xb8) & 0xf8) == 53438061Smsmith (c & 0xf8)) 53538061Smsmith goto end; 53638061Smsmith if (!--j) goto err; 53738061Smsmith } 53838061Smsmith } 53938061Smsmith 54038061Smsmith end: 54138061Smsmith len = bp - sc->sc_ifbuf; 54238061Smsmith if (len <= LPIPHDRLEN) 54338061Smsmith goto err; 54438061Smsmith 54538061Smsmith sc->sc_iferrs = 0; 54638061Smsmith 54738061Smsmith if (IF_QFULL(&ipintrq)) { 54838061Smsmith lprintf("DROP"); 54938061Smsmith IF_DROP(&ipintrq); 55038061Smsmith goto done; 55138061Smsmith } 55238061Smsmith#if NBPFILTER > 0 55338061Smsmith if (sc->sc_if.if_bpf) { 55438061Smsmith bpf_tap(&sc->sc_if, sc->sc_ifbuf, len); 55538061Smsmith } 55638061Smsmith#endif 55738061Smsmith len -= LPIPHDRLEN; 55838061Smsmith sc->sc_if.if_ipackets++; 55938061Smsmith sc->sc_if.if_ibytes += len; 56038061Smsmith top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); 56138061Smsmith if (top) { 56238061Smsmith IF_ENQUEUE(&ipintrq, top); 56338061Smsmith schednetisr(NETISR_IP); 56438061Smsmith } 56538061Smsmith } 56638061Smsmith goto done; 56738061Smsmith 56838061Smsmith err: 56938061Smsmith ppb_wdtr(&sc->lp_dev, 0); 57038061Smsmith lprintf("R"); 57138061Smsmith sc->sc_if.if_ierrors++; 57238061Smsmith sc->sc_iferrs++; 57338061Smsmith 57438061Smsmith /* 57538061Smsmith * We are not able to send receive anything for now, 57638061Smsmith * so stop wasting our time 57738061Smsmith */ 57838061Smsmith if (sc->sc_iferrs > LPMAXERRS) { 57938061Smsmith printf("lp%d: Too many errors, Going off-line.\n", unit); 58038061Smsmith ppb_wctr(&sc->lp_dev, 0x00); 58138061Smsmith sc->sc_if.if_flags &= ~IFF_RUNNING; 58238061Smsmith sc->sc_iferrs=0; 58338061Smsmith } 58438061Smsmith 58538061Smsmith done: 58638061Smsmith splx(s); 58738061Smsmith return; 58838061Smsmith} 58938061Smsmith 59038061Smsmithstatic __inline int 59138061Smsmithlpoutbyte (u_char byte, int spin, struct ppb_device *dev) 59238061Smsmith{ 59338061Smsmith ppb_wdtr(dev, txmith[byte]); 59438061Smsmith while (!(ppb_rstr(dev) & LPIP_SHAKE)) 59538061Smsmith if (--spin == 0) 59638061Smsmith return 1; 59738061Smsmith ppb_wdtr(dev, txmitl[byte]); 59838061Smsmith while (ppb_rstr(dev) & LPIP_SHAKE) 59938061Smsmith if (--spin == 0) 60038061Smsmith return 1; 60138061Smsmith return 0; 60238061Smsmith} 60338061Smsmith 60438061Smsmithstatic int 60538061Smsmithlpoutput (struct ifnet *ifp, struct mbuf *m, 60638061Smsmith struct sockaddr *dst, struct rtentry *rt) 60738061Smsmith{ 60838061Smsmith struct lpt_softc *sc = lpdata[ifp->if_unit]; 60938061Smsmith int s, err; 61038061Smsmith struct mbuf *mm; 61138061Smsmith u_char *cp = "\0\0"; 61238061Smsmith u_char chksum = 0; 61338061Smsmith int count = 0; 61438061Smsmith int i; 61538061Smsmith int spin; 61638061Smsmith 61738061Smsmith /* We need a sensible value if we abort */ 61838061Smsmith cp++; 61938061Smsmith ifp->if_flags |= IFF_RUNNING; 62038061Smsmith 62138061Smsmith err = 1; /* assume we're aborting because of an error */ 62238061Smsmith 62338061Smsmith s = splhigh(); 62438061Smsmith 62538061Smsmith /* Suspend (on laptops) or receive-errors might have taken us offline */ 62638061Smsmith ppb_wctr(&sc->lp_dev, LPC_ENA); 62738061Smsmith 62838061Smsmith if (ifp->if_flags & IFF_LINK0) { 62938061Smsmith 63038061Smsmith if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) { 63138061Smsmith lprintf("&"); 63238061Smsmith lpintr(ifp->if_unit); 63338061Smsmith } 63438061Smsmith 63538061Smsmith /* Alert other end to pending packet */ 63638061Smsmith spin = LPMAXSPIN1; 63738061Smsmith ppb_wdtr(&sc->lp_dev, 0x08); 63838061Smsmith while ((ppb_rstr(&sc->lp_dev) & 0x08) == 0) 63938061Smsmith if (--spin == 0) { 64038061Smsmith goto nend; 64138061Smsmith } 64238061Smsmith 64338061Smsmith /* Calculate length of packet, then send that */ 64438061Smsmith 64538061Smsmith count += 14; /* Ethernet header len */ 64638061Smsmith 64738061Smsmith mm = m; 64838061Smsmith for (mm = m; mm; mm = mm->m_next) { 64938061Smsmith count += mm->m_len; 65038061Smsmith } 65138061Smsmith if (clpoutbyte(count & 0xFF, LPMAXSPIN1, &sc->lp_dev)) 65238061Smsmith goto nend; 65338061Smsmith if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, &sc->lp_dev)) 65438061Smsmith goto nend; 65538061Smsmith 65638061Smsmith /* Send dummy ethernet header */ 65738061Smsmith for (i = 0; i < 12; i++) { 65838061Smsmith if (clpoutbyte(i, LPMAXSPIN1, &sc->lp_dev)) 65938061Smsmith goto nend; 66038061Smsmith chksum += i; 66138061Smsmith } 66238061Smsmith 66338061Smsmith if (clpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev)) 66438061Smsmith goto nend; 66538061Smsmith if (clpoutbyte(0x00, LPMAXSPIN1, &sc->lp_dev)) 66638061Smsmith goto nend; 66738061Smsmith chksum += 0x08 + 0x00; /* Add into checksum */ 66838061Smsmith 66938061Smsmith mm = m; 67038061Smsmith do { 67138061Smsmith cp = mtod(mm, u_char *); 67238061Smsmith while (mm->m_len--) { 67338061Smsmith chksum += *cp; 67438061Smsmith if (clpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev)) 67538061Smsmith goto nend; 67638061Smsmith } 67738061Smsmith } while ((mm = mm->m_next)); 67838061Smsmith 67938061Smsmith /* Send checksum */ 68038061Smsmith if (clpoutbyte(chksum, LPMAXSPIN2, &sc->lp_dev)) 68138061Smsmith goto nend; 68238061Smsmith 68338061Smsmith /* Go quiescent */ 68438061Smsmith ppb_wdtr(&sc->lp_dev, 0); 68538061Smsmith 68638061Smsmith err = 0; /* No errors */ 68738061Smsmith 68838061Smsmith nend: 68938061Smsmith if (err) { /* if we didn't timeout... */ 69038061Smsmith ifp->if_oerrors++; 69138061Smsmith lprintf("X"); 69238061Smsmith } else { 69338061Smsmith ifp->if_opackets++; 69438061Smsmith ifp->if_obytes += m->m_pkthdr.len; 69538061Smsmith } 69638061Smsmith 69738061Smsmith m_freem(m); 69838061Smsmith 69938061Smsmith if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) { 70038061Smsmith lprintf("^"); 70138061Smsmith lpintr(ifp->if_unit); 70238061Smsmith } 70338061Smsmith (void) splx(s); 70438061Smsmith return 0; 70538061Smsmith } 70638061Smsmith 70738061Smsmith if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) { 70838061Smsmith lprintf("&"); 70938061Smsmith lpintr(ifp->if_unit); 71038061Smsmith } 71138061Smsmith 71238061Smsmith if (lpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev)) 71338061Smsmith goto end; 71438061Smsmith if (lpoutbyte(0x00, LPMAXSPIN2, &sc->lp_dev)) 71538061Smsmith goto end; 71638061Smsmith 71738061Smsmith mm = m; 71838061Smsmith do { 71938061Smsmith cp = mtod(mm,u_char *); 72038061Smsmith while (mm->m_len--) 72138061Smsmith if (lpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev)) 72238061Smsmith goto end; 72338061Smsmith } while ((mm = mm->m_next)); 72438061Smsmith 72538061Smsmith err = 0; /* no errors were encountered */ 72638061Smsmith 72738061Smsmith end: 72838061Smsmith --cp; 72938061Smsmith ppb_wdtr(&sc->lp_dev, txmitl[*cp] ^ 0x17); 73038061Smsmith 73138061Smsmith if (err) { /* if we didn't timeout... */ 73238061Smsmith ifp->if_oerrors++; 73338061Smsmith lprintf("X"); 73438061Smsmith } else { 73538061Smsmith ifp->if_opackets++; 73638061Smsmith ifp->if_obytes += m->m_pkthdr.len; 73738061Smsmith#if NBPFILTER > 0 73838061Smsmith if (ifp->if_bpf) { 73938061Smsmith /* 74038061Smsmith * We need to prepend the packet type as 74138061Smsmith * a two byte field. Cons up a dummy header 74238061Smsmith * to pacify bpf. This is safe because bpf 74338061Smsmith * will only read from the mbuf (i.e., it won't 74438061Smsmith * try to free it or keep a pointer to it). 74538061Smsmith */ 74638061Smsmith struct mbuf m0; 74738061Smsmith u_short hdr = 0x800; 74838061Smsmith 74938061Smsmith m0.m_next = m; 75038061Smsmith m0.m_len = 2; 75138061Smsmith m0.m_data = (char *)&hdr; 75238061Smsmith 75338061Smsmith bpf_mtap(ifp, &m0); 75438061Smsmith } 75538061Smsmith#endif 75638061Smsmith } 75738061Smsmith 75838061Smsmith m_freem(m); 75938061Smsmith 76038061Smsmith if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) { 76138061Smsmith lprintf("^"); 76238061Smsmith lpintr(ifp->if_unit); 76338061Smsmith } 76438061Smsmith 76538061Smsmith (void) splx(s); 76638061Smsmith return 0; 76738061Smsmith} 768