if_plip.c revision 106937
1139743Simp/*- 265577Sdes * Copyright (c) 1997 Poul-Henning Kamp 365577Sdes * All rights reserved. 459412Smsmith * 559412Smsmith * Redistribution and use in source and binary forms, with or without 659412Smsmith * modification, are permitted provided that the following conditions 759412Smsmith * are met: 859412Smsmith * 1. Redistributions of source code must retain the above copyright 959412Smsmith * notice, this list of conditions and the following disclaimer. 1059412Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1159412Smsmith * notice, this list of conditions and the following disclaimer in the 1259412Smsmith * documentation and/or other materials provided with the distribution. 1359412Smsmith * 1459412Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559412Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659412Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759412Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859412Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959412Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059412Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159412Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259412Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359412Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459412Smsmith * SUCH DAMAGE. 2559412Smsmith * 2659412Smsmith * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 2759412Smsmith * $FreeBSD: head/sys/dev/ppbus/if_plip.c 106937 2002-11-14 23:54:55Z sam $ 2859412Smsmith */ 2959412Smsmith 3059412Smsmith/* 3159412Smsmith * Parallel port TCP/IP interfaces added. I looked at the driver from 3259412Smsmith * MACH but this is a complete rewrite, and btw. incompatible, and it 3359412Smsmith * should perform better too. I have never run the MACH driver though. 3459412Smsmith * 3559412Smsmith * This driver sends two bytes (0x08, 0x00) in front of each packet, 3659412Smsmith * to allow us to distinguish another format later. 3759412Smsmith * 3859412Smsmith * Now added an Linux/Crynwr compatibility mode which is enabled using 3959412Smsmith * IF_LINK0 - Tim Wilkinson. 4059412Smsmith * 4159412Smsmith * TODO: 42116173Sobrien * Make HDLC/PPP mode, use IF_LLC1 to enable. 43116173Sobrien * 44116173Sobrien * Connect the two computers using a Laplink parallel cable to use this 4559412Smsmith * feature: 4683926Sdes * 4776166Smarkm * +----------------------------------------+ 4874135Sjlemon * |A-name A-End B-End Descr. Port/Bit | 4983926Sdes * +----------------------------------------+ 50119911Sdes * |DATA0 2 15 Data 0/0x01 | 5176166Smarkm * |-ERROR 15 2 1/0x08 | 5265633Sdes * +----------------------------------------+ 5383926Sdes * |DATA1 3 13 Data 0/0x02 | 5476166Smarkm * |+SLCT 13 3 1/0x10 | 5574135Sjlemon * +----------------------------------------+ 5678025Sdes * |DATA2 4 12 Data 0/0x04 | 5776827Salfred * |+PE 12 4 1/0x20 | 5885289Sdes * +----------------------------------------+ 5965633Sdes * |DATA3 5 10 Strobe 0/0x08 | 6065633Sdes * |-ACK 10 5 1/0x40 | 6169995Sdes * +----------------------------------------+ 62123246Sdes * |DATA4 6 11 Data 0/0x10 | 6383926Sdes * |BUSY 11 6 1/~0x80 | 6476839Sjlemon * +----------------------------------------+ 6583926Sdes * |GND 18-25 18-25 GND - | 6665633Sdes * +----------------------------------------+ 6783926Sdes * 6883926Sdes * Expect transfer-rates up to 75 kbyte/sec. 6959412Smsmith * 7059412Smsmith * If GCC could correctly grok 7183926Sdes * register int port asm("edx") 7283926Sdes * the code would be cleaner 7359412Smsmith * 7459412Smsmith * Poul-Henning Kamp <phk@freebsd.org> 7567588Sdes */ 7659412Smsmith 7760860Sdes/* 7859412Smsmith * Update for ppbus, PLIP support only - Nicolas Souchu 7969799Sdes */ 8067589Sdes 8178113Sdes#include "opt_plip.h" 82133822Stjr 8367589Sdes#include <sys/param.h> 8459412Smsmith#include <sys/systm.h> 85133822Stjr#include <sys/module.h> 8659412Smsmith#include <sys/bus.h> 87133822Stjr#include <sys/mbuf.h> 88140214Sobrien#include <sys/socket.h> 89140214Sobrien#include <sys/sockio.h> 90140214Sobrien#include <sys/kernel.h> 9187275Srwatson#include <sys/malloc.h> 92133822Stjr 9385129Sdes#include <machine/bus.h> 9469995Sdes#include <machine/resource.h> 9585289Sdes#include <sys/rman.h> 9678025Sdes 9784248Sdes#include <net/if.h> 9859412Smsmith#include <net/if_types.h> 9967588Sdes#include <net/netisr.h> 10067588Sdes 10167588Sdes#include <netinet/in.h> 10276405Sdes#include <netinet/in_var.h> 10367588Sdes 10467588Sdes#include <net/bpf.h> 10569799Sdes 10667588Sdes#include <dev/ppbus/ppbconf.h> 10767588Sdes#include "ppbus_if.h" 10874135Sjlemon#include <dev/ppbus/ppbio.h> 10978113Sdes 11078113Sdes#ifndef LPMTU /* MTU for the lp# interfaces */ 11178113Sdes#define LPMTU 1500 11278025Sdes#endif 11378025Sdes 11459412Smsmith#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 11559412Smsmith#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 11659412Smsmith#endif 11759412Smsmith 11859412Smsmith#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 11959412Smsmith#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 120113574Sjhb#endif 121113574Sjhb 122113574Sjhb#ifndef LPMAXERRS /* Max errors before !RUNNING */ 12360860Sdes#define LPMAXERRS 100 124117723Sphk#endif 12559412Smsmith 12659412Smsmith#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 12759412Smsmith#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 12859412Smsmith#define MLPIPHDRLEN CLPIPHDRLEN 12959412Smsmith 13059412Smsmith#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 13159412Smsmith#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 13259412Smsmith#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 13359412Smsmith#define MLPIPHDRLEN LPIPHDRLEN 13459412Smsmith#endif 13559412Smsmith 13659412Smsmith#define LPIPTBLSIZE 256 /* Size of octet translation table */ 13759412Smsmith 13859412Smsmith#define lprintf if (lptflag) printf 139117723Sphk 140153310Smlaier#ifdef PLIP_DEBUG 141153310Smlaierstatic int volatile lptflag = 1; 142117723Sphk#else 14360860Sdesstatic int volatile lptflag = 0; 144124082Salc#endif 14571471Sjhb 14660860Sdesstruct lp_data { 14760860Sdes unsigned short lp_unit; 148124082Salc 14960860Sdes struct ifnet sc_if; 15059412Smsmith u_char *sc_ifbuf; 15159412Smsmith int sc_iferrs; 15259412Smsmith 15359412Smsmith struct resource *res_irq; 15459412Smsmith}; 15559412Smsmith 15659412Smsmith/* Tables for the lp# interface */ 15759412Smsmithstatic u_char *txmith; 15859412Smsmith#define txmitl (txmith+(1*LPIPTBLSIZE)) 15959412Smsmith#define trecvh (txmith+(2*LPIPTBLSIZE)) 16059412Smsmith#define trecvl (txmith+(3*LPIPTBLSIZE)) 16178025Sdes 16278031Sdesstatic u_char *ctxmith; 16369799Sdes#define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 16476839Sjlemon#define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 16569799Sdes#define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 16669799Sdes 16769799Sdes/* Functions for the lp# interface */ 16869799Sdesstatic int lpinittables(void); 16969799Sdesstatic int lpioctl(struct ifnet *, u_long, caddr_t); 17076839Sjlemonstatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 17176839Sjlemon struct rtentry *); 17269799Sdesstatic void lp_intr(void *); 17369799Sdes 17469799Sdes#define DEVTOSOFTC(dev) \ 17569799Sdes ((struct lp_data *)device_get_softc(dev)) 17669799Sdes#define UNITOSOFTC(unit) \ 17759412Smsmith ((struct lp_data *)devclass_get_softc(lp_devclass, (unit))) 17878025Sdes#define UNITODEVICE(unit) \ 17959412Smsmith (devclass_get_device(lp_devclass, (unit))) 18059412Smsmith 181133822Stjrstatic devclass_t lp_devclass; 18278113Sdes 183133822Stjrstatic void 18478113Sdeslp_identify(driver_t *driver, device_t parent) 18578113Sdes{ 18678113Sdes 18778113Sdes BUS_ADD_CHILD(parent, 0, "plip", -1); 188159544Sdes} 189159544Sdes/* 190159544Sdes * lpprobe() 191123246Sdes */ 192118421Sdesstatic int 19359412Smsmithlp_probe(device_t dev) 19469799Sdes{ 19578031Sdes device_t ppbus = device_get_parent(dev); 19678031Sdes struct lp_data *lp; 19769799Sdes int zero = 0; 19878031Sdes uintptr_t irq; 19978031Sdes 20078031Sdes lp = DEVTOSOFTC(dev); 20178031Sdes bzero(lp, sizeof(struct lp_data)); 20278031Sdes 20378031Sdes /* retrieve the ppbus irq */ 20478031Sdes BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); 20567589Sdes 20667589Sdes /* if we haven't interrupts, the probe fails */ 20767589Sdes if (irq == -1) { 20859412Smsmith device_printf(dev, "not an interrupt driven port, failed.\n"); 209133822Stjr return (ENXIO); 21059412Smsmith } 21167589Sdes 21259412Smsmith /* reserve the interrupt resource, expecting irq is available to continue */ 21359412Smsmith lp->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1, 21467589Sdes RF_SHAREABLE); 21559412Smsmith if (lp->res_irq == 0) { 21659412Smsmith device_printf(dev, "cannot reserve interrupt, failed.\n"); 21767589Sdes return (ENXIO); 21859412Smsmith } 21959412Smsmith 22067589Sdes /* 22159412Smsmith * lp dependent initialisation. 22259412Smsmith */ 22367589Sdes lp->lp_unit = device_get_unit(dev); 22459412Smsmith 22559412Smsmith device_set_desc(dev, "PLIP network interface"); 22678031Sdes 22759412Smsmith return (0); 228159170Sdes} 229133822Stjr 230159170Sdesstatic int 231133822Stjrlp_attach (device_t dev) 232133822Stjr{ 23359412Smsmith struct lp_data *lp = DEVTOSOFTC(dev); 23459412Smsmith struct ifnet *ifp = &lp->sc_if; 235159544Sdes 236159544Sdes ifp->if_softc = lp; 237159544Sdes ifp->if_name = "lp"; 238159544Sdes ifp->if_unit = device_get_unit(dev); 239159544Sdes ifp->if_mtu = LPMTU; 240159544Sdes ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 241123246Sdes ifp->if_ioctl = lpioctl; 242118421Sdes ifp->if_output = lpoutput; 243118421Sdes ifp->if_type = IFT_PARA; 244118421Sdes ifp->if_hdrlen = 0; 245118421Sdes ifp->if_addrlen = 0; 246118421Sdes ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 247159544Sdes if_attach(ifp); 248118421Sdes 249159544Sdes bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 250159544Sdes 251118421Sdes return (0); 25259412Smsmith} 25378031Sdes/* 25478031Sdes * Build the translation tables for the LPIP (BSD unix) protocol. 25567589Sdes * We don't want to calculate these nasties in our tight loop, so we 25678031Sdes * precalculate them when we initialize. 25767589Sdes */ 25878031Sdesstatic int 25967589Sdeslpinittables (void) 26078031Sdes{ 261119068Sdes int i; 26278031Sdes 26367589Sdes if (!txmith) 26478025Sdes txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 26578025Sdes 26678031Sdes if (!txmith) 26769799Sdes return 1; 26869799Sdes 26978025Sdes if (!ctxmith) 27069799Sdes ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 27169799Sdes 27269799Sdes if (!ctxmith) 27378031Sdes return 1; 27469995Sdes 27578025Sdes for (i=0; i < LPIPTBLSIZE; i++) { 27659412Smsmith ctxmith[i] = (i & 0xF0) >> 4; 277133822Stjr ctxmitl[i] = 0x10 | (i & 0x0F); 27865633Sdes ctrecvh[i] = (i & 0x78) << 1; 27978113Sdes ctrecvl[i] = (i & 0x78) >> 3; 28085289Sdes } 28185289Sdes 28285289Sdes for (i=0; i < LPIPTBLSIZE; i++) { 28385289Sdes txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 28485289Sdes txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 28585289Sdes trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 28685289Sdes trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 28785289Sdes } 28885289Sdes 28985289Sdes return 0; 29091334Sjulian} 29191334Sjulian 29285289Sdes/* 29385289Sdes * Process an ioctl request. 29485289Sdes */ 29585289Sdes 29685289Sdesstatic int 29785289Sdeslpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 298124407Srwatson{ 29985289Sdes device_t dev = UNITODEVICE(ifp->if_unit); 30091334Sjulian device_t ppbus = device_get_parent(dev); 30191334Sjulian struct lp_data *sc = DEVTOSOFTC(dev); 30285289Sdes struct ifaddr *ifa = (struct ifaddr *)data; 303119068Sdes struct ifreq *ifr = (struct ifreq *)data; 30485289Sdes u_char *ptr; 30585289Sdes void *ih; 30685289Sdes int error; 30785289Sdes 30885289Sdes switch (cmd) { 309119068Sdes 31085289Sdes case SIOCSIFDSTADDR: 31185289Sdes case SIOCAIFADDR: 31285289Sdes case SIOCSIFADDR: 31385289Sdes if (ifa->ifa_addr->sa_family != AF_INET) 31485289Sdes return EAFNOSUPPORT; 31585289Sdes 31685289Sdes ifp->if_flags |= IFF_UP; 31785289Sdes /* FALLTHROUGH */ 31885289Sdes case SIOCSIFFLAGS: 31985289Sdes if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 32085289Sdes 32185289Sdes ppb_wctr(ppbus, 0x00); 322119068Sdes ifp->if_flags &= ~IFF_RUNNING; 323158311Sambrisko 324158311Sambrisko /* IFF_UP is not set, try to release the bus anyway */ 325158311Sambrisko ppb_release_bus(ppbus, dev); 326158311Sambrisko break; 327158311Sambrisko } 328158311Sambrisko if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 329158311Sambrisko 33085289Sdes /* XXX 33185289Sdes * Should the request be interruptible? 33285289Sdes */ 33385289Sdes if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR))) 33485289Sdes return (error); 33585289Sdes 33685289Sdes /* Now IFF_UP means that we own the bus */ 33785289Sdes 33885289Sdes ppb_set_mode(ppbus, PPB_COMPATIBLE); 33985289Sdes 34085289Sdes if (lpinittables()) { 34185289Sdes ppb_release_bus(ppbus, dev); 34285289Sdes return ENOBUFS; 34385289Sdes } 34485289Sdes 34585289Sdes sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, 34685289Sdes M_DEVBUF, M_WAITOK); 34785289Sdes if (!sc->sc_ifbuf) { 34885289Sdes ppb_release_bus(ppbus, dev); 34985289Sdes return ENOBUFS; 35085289Sdes } 35178113Sdes 35278113Sdes /* attach our interrupt handler, later detached when the bus is released */ 35378025Sdes if ((error = BUS_SETUP_INTR(ppbus, dev, sc->res_irq, 35478025Sdes INTR_TYPE_NET, lp_intr, dev, &ih))) { 35565633Sdes ppb_release_bus(ppbus, dev); 356123246Sdes return (error); 357120339Sdes } 358120339Sdes 359120339Sdes ppb_wctr(ppbus, IRQENABLE); 360120339Sdes ifp->if_flags |= IFF_RUNNING; 361120339Sdes } 362120339Sdes break; 363143194Ssobomax 364143194Ssobomax case SIOCSIFMTU: 365143194Ssobomax ptr = sc->sc_ifbuf; 366143194Ssobomax sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 367143194Ssobomax if (!sc->sc_ifbuf) { 368143194Ssobomax sc->sc_ifbuf = ptr; 36978025Sdes return ENOBUFS; 37069799Sdes } 37169799Sdes if (ptr) 37269799Sdes free(ptr,M_DEVBUF); 37369799Sdes sc->sc_if.if_mtu = ifr->ifr_mtu; 37469799Sdes break; 37585657Sdillon 37669799Sdes case SIOCGIFMTU: 37769799Sdes ifr->ifr_mtu = sc->sc_if.if_mtu; 37869799Sdes break; 37969799Sdes 38069799Sdes case SIOCADDMULTI: 38169799Sdes case SIOCDELMULTI: 382113574Sjhb if (ifr == 0) { 38378025Sdes return EAFNOSUPPORT; /* XXX */ 38465633Sdes } 38565633Sdes switch (ifr->ifr_addr.sa_family) { 38678113Sdes 38778113Sdes case AF_INET: 38878113Sdes break; 38978025Sdes 39078025Sdes default: 39165633Sdes return EAFNOSUPPORT; 39265633Sdes } 39365633Sdes break; 39465633Sdes 39585657Sdillon case SIOCGIFMEDIA: 396113574Sjhb /* 39769799Sdes * No ifmedia support at this stage; maybe use it 39878025Sdes * in future for eg. protocol selection. 39965633Sdes */ 40065633Sdes return EINVAL; 40178113Sdes 40278113Sdes default: 40378113Sdes lprintf("LP:ioctl(0x%lx)\n", cmd); 40478025Sdes return EINVAL; 40578025Sdes } 40665633Sdes return 0; 40787275Srwatson} 40887275Srwatson 40987275Srwatsonstatic __inline int 410112206Sjhbclpoutbyte (u_char byte, int spin, device_t ppbus) 411112206Sjhb{ 41287275Srwatson ppb_wdtr(ppbus, ctxmitl[byte]); 41378025Sdes while (ppb_rstr(ppbus) & CLPIP_SHAKE) 41469995Sdes if (--spin == 0) { 41587275Srwatson return 1; 41678025Sdes } 41765633Sdes ppb_wdtr(ppbus, ctxmith[byte]); 41865633Sdes while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 41978113Sdes if (--spin == 0) { 42078113Sdes return 1; 42178113Sdes } 42278025Sdes return 0; 42378025Sdes} 42476839Sjlemon 42578025Sdesstatic __inline int 42676839Sjlemonclpinbyte (int spin, device_t ppbus) 42776839Sjlemon{ 42876839Sjlemon u_char c, cl; 42976839Sjlemon 43076839Sjlemon while((ppb_rstr(ppbus) & CLPIP_SHAKE)) 43176839Sjlemon if(!--spin) { 43276839Sjlemon return -1; 43376839Sjlemon } 43476839Sjlemon cl = ppb_rstr(ppbus); 43578116Sdes ppb_wdtr(ppbus, 0x10); 43676839Sjlemon 437119068Sdes while(!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 43878025Sdes if(!--spin) { 43976839Sjlemon return -1; 44076839Sjlemon } 44178113Sdes c = ppb_rstr(ppbus); 44278113Sdes ppb_wdtr(ppbus, 0x00); 44378113Sdes 44478025Sdes return (ctrecvl[cl] | ctrecvh[c]); 44578025Sdes} 44667588Sdes 44769995Sdesstatic void 44867588Sdeslptap(struct ifnet *ifp, struct mbuf *m) 44994307Sjhb{ 45069995Sdes /* 45178025Sdes * Send a packet through bpf. We need to prepend the address family 45278025Sdes * as a four byte field. Cons up a dummy header to pacify bpf. This 45367588Sdes * is safe because bpf will only read from the mbuf (i.e., it won't 45467588Sdes * try to free it or keep a pointer to it). 45573923Sjhb */ 45667588Sdes u_int32_t af = AF_INET; 45767588Sdes struct mbuf m0; 45891140Stanimura 45967588Sdes m0.m_next = m; 46067588Sdes m0.m_len = sizeof(u_int32_t); 46167588Sdes m0.m_data = (char *)⁡ 46267588Sdes BPF_MTAP(ifp, &m0); 46367588Sdes} 46467588Sdes 46567588Sdesstatic void 46667588Sdeslp_intr (void *arg) 46767588Sdes{ 46867588Sdes device_t dev = (device_t)arg; 46967588Sdes device_t ppbus = device_get_parent(dev); 47067588Sdes struct lp_data *sc = DEVTOSOFTC(dev); 47167588Sdes int len, s, j; 47267588Sdes u_char *bp; 47367588Sdes u_char c, cl; 47467588Sdes struct mbuf *top; 475113574Sjhb 476113574Sjhb s = splhigh(); 47767588Sdes 47869995Sdes if (sc->sc_if.if_flags & IFF_LINK0) { 47967588Sdes 48067588Sdes /* Ack. the request */ 48169799Sdes ppb_wdtr(ppbus, 0x01); 48269799Sdes 48367588Sdes /* Get the packet length */ 48467588Sdes j = clpinbyte(LPMAXSPIN2, ppbus); 48567588Sdes if (j == -1) 48667588Sdes goto err; 48767588Sdes len = j; 48869799Sdes j = clpinbyte(LPMAXSPIN2, ppbus); 48969799Sdes if (j == -1) 49069799Sdes goto err; 49169799Sdes len = len + (j << 8); 49267588Sdes if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) 49378025Sdes goto err; 494119068Sdes 49578025Sdes bp = sc->sc_ifbuf; 49667588Sdes 49767588Sdes while (len--) { 49867588Sdes j = clpinbyte(LPMAXSPIN2, ppbus); 499119911Sdes if (j == -1) { 500119911Sdes goto err; 501119911Sdes } 502119911Sdes *bp++ = j; 503119911Sdes } 504119911Sdes /* Get and ignore checksum */ 505119911Sdes j = clpinbyte(LPMAXSPIN2, ppbus); 506120340Sdes if (j == -1) { 507119911Sdes goto err; 508119911Sdes } 509119911Sdes 510119911Sdes len = bp - sc->sc_ifbuf; 511119911Sdes if (len <= CLPIPHDRLEN) 512119911Sdes goto err; 513119911Sdes 514119911Sdes sc->sc_iferrs = 0; 515119911Sdes 516119911Sdes len -= CLPIPHDRLEN; 517119911Sdes sc->sc_if.if_ipackets++; 518119911Sdes sc->sc_if.if_ibytes += len; 519119911Sdes top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); 520119911Sdes if (top) { 521119911Sdes if (sc->sc_if.if_bpf) 522119911Sdes lptap(&sc->sc_if, top); 523119911Sdes if (! IF_HANDOFF(&ipintrq, top, NULL)) { 524119911Sdes lprintf("DROP"); 525119911Sdes } else { 526119911Sdes schednetisr(NETISR_IP); 527119911Sdes } 528119911Sdes } 529119911Sdes goto done; 53078113Sdes } 53178113Sdes while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { 53278025Sdes len = sc->sc_if.if_mtu + LPIPHDRLEN; 53378025Sdes bp = sc->sc_ifbuf; 53467588Sdes while (len--) { 53569995Sdes 53667588Sdes cl = ppb_rstr(ppbus); 53769799Sdes ppb_wdtr(ppbus, 8); 53899072Sjulian 539114983Sjhb j = LPMAXSPIN2; 54074135Sjlemon while((ppb_rstr(ppbus) & LPIP_SHAKE)) 54167588Sdes if(!--j) goto err; 542113611Sjhb 54399072Sjulian c = ppb_rstr(ppbus); 54499072Sjulian ppb_wdtr(ppbus, 0); 54599072Sjulian 54699072Sjulian *bp++= trecvh[cl] | trecvl[c]; 54799072Sjulian 548113611Sjhb j = LPMAXSPIN2; 54999072Sjulian while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) { 55099072Sjulian if (cl != c && 55199072Sjulian (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) == 55299072Sjulian (c & 0xf8)) 55399072Sjulian goto end; 55499072Sjulian if (!--j) goto err; 55599072Sjulian } 55699072Sjulian } 55799072Sjulian 55899072Sjulian end: 559103216Sjulian len = bp - sc->sc_ifbuf; 56099072Sjulian if (len <= LPIPHDRLEN) 56199072Sjulian goto err; 56299072Sjulian 56399072Sjulian sc->sc_iferrs = 0; 56499072Sjulian 56599072Sjulian len -= LPIPHDRLEN; 56699072Sjulian sc->sc_if.if_ipackets++; 56799072Sjulian sc->sc_if.if_ibytes += len; 56899072Sjulian top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); 56999072Sjulian if (top) { 57099072Sjulian if (sc->sc_if.if_bpf) 57199072Sjulian lptap(&sc->sc_if, top); 57299072Sjulian if (! IF_HANDOFF(&ipintrq, top, NULL)) { 57399072Sjulian lprintf("DROP"); 57499072Sjulian } else { 57599072Sjulian schednetisr(NETISR_IP); 57699072Sjulian } 57799072Sjulian } 578113611Sjhb } 57999072Sjulian goto done; 58067588Sdes 58169995Sdes err: 58278025Sdes ppb_wdtr(ppbus, 0); 58378031Sdes lprintf("R"); 58467588Sdes sc->sc_if.if_ierrors++; 58567588Sdes sc->sc_iferrs++; 58667588Sdes 58767588Sdes /* 58878025Sdes * We are not able to send receive anything for now, 58978025Sdes * so stop wasting our time 59073923Sjhb */ 59178031Sdes if (sc->sc_iferrs > LPMAXERRS) { 59278031Sdes printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev)); 59378031Sdes ppb_wctr(ppbus, 0x00); 59478031Sdes sc->sc_if.if_flags &= ~IFF_RUNNING; 59578031Sdes sc->sc_iferrs=0; 59678031Sdes } 59778031Sdes 59878031Sdes done: 59978031Sdes splx(s); 60078031Sdes return; 60178025Sdes} 60267588Sdes 60378031Sdesstatic __inline int 60471471Sjhblpoutbyte (u_char byte, int spin, device_t ppbus) 60578025Sdes{ 606119068Sdes ppb_wdtr(ppbus, txmith[byte]); 60767588Sdes while (!(ppb_rstr(ppbus) & LPIP_SHAKE)) 60867588Sdes if (--spin == 0) 60969799Sdes return 1; 61069799Sdes ppb_wdtr(ppbus, txmitl[byte]); 61169799Sdes while (ppb_rstr(ppbus) & LPIP_SHAKE) 61269799Sdes if (--spin == 0) 61369799Sdes return 1; 61469799Sdes return 0; 61569799Sdes} 61669799Sdes 61767588Sdesstatic int 618113574Sjhblpoutput (struct ifnet *ifp, struct mbuf *m, 61978025Sdes struct sockaddr *dst, struct rtentry *rt) 620113574Sjhb{ 621113574Sjhb device_t dev = UNITODEVICE(ifp->if_unit); 622113574Sjhb device_t ppbus = device_get_parent(dev); 623113574Sjhb int s, err; 62469995Sdes struct mbuf *mm; 62569995Sdes u_char *cp = "\0\0"; 626113574Sjhb u_char chksum = 0; 62767588Sdes int count = 0; 62867588Sdes int i, len, spin; 62967588Sdes 63067588Sdes /* We need a sensible value if we abort */ 63167588Sdes cp++; 63267588Sdes ifp->if_flags |= IFF_RUNNING; 63367588Sdes 63467588Sdes err = 1; /* assume we're aborting because of an error */ 63567588Sdes 63667588Sdes s = splhigh(); 63767588Sdes 63867588Sdes /* Suspend (on laptops) or receive-errors might have taken us offline */ 63971471Sjhb ppb_wctr(ppbus, IRQENABLE); 640104306Sjmallett 64169799Sdes if (ifp->if_flags & IFF_LINK0) { 64269799Sdes 64369799Sdes if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 64469799Sdes lprintf("&"); 64578025Sdes lp_intr(dev); 646114983Sjhb } 647114983Sjhb 648114983Sjhb /* Alert other end to pending packet */ 649114983Sjhb spin = LPMAXSPIN1; 650114983Sjhb ppb_wdtr(ppbus, 0x08); 65171471Sjhb while ((ppb_rstr(ppbus) & 0x08) == 0) 652119068Sdes if (--spin == 0) { 65367588Sdes goto nend; 65467588Sdes } 65567588Sdes 65667588Sdes /* Calculate length of packet, then send that */ 65767588Sdes 65878025Sdes count += 14; /* Ethernet header len */ 65978025Sdes 66078025Sdes mm = m; 661119068Sdes for (mm = m; mm; mm = mm->m_next) { 66278025Sdes count += mm->m_len; 66367588Sdes } 66474135Sjlemon if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 665119911Sdes goto nend; 66678113Sdes if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 667119911Sdes goto nend; 668119911Sdes 669119911Sdes /* Send dummy ethernet header */ 670119911Sdes for (i = 0; i < 12; i++) { 671119911Sdes if (clpoutbyte(i, LPMAXSPIN1, ppbus)) 672119911Sdes goto nend; 673119911Sdes chksum += i; 674119911Sdes } 675119911Sdes 676119911Sdes if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 677119911Sdes goto nend; 678119911Sdes if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 679119911Sdes goto nend; 680119911Sdes chksum += 0x08 + 0x00; /* Add into checksum */ 681119911Sdes 682119911Sdes mm = m; 683119911Sdes do { 684119911Sdes cp = mtod(mm, u_char *); 685119911Sdes len = mm->m_len; 686119911Sdes while (len--) { 687119911Sdes chksum += *cp; 688119911Sdes if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 689119911Sdes goto nend; 690119911Sdes } 691119911Sdes } while ((mm = mm->m_next)); 692119911Sdes 693119911Sdes /* Send checksum */ 694119911Sdes if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 695119911Sdes goto nend; 696119911Sdes 697119911Sdes /* Go quiescent */ 698119911Sdes ppb_wdtr(ppbus, 0); 699119911Sdes 700119911Sdes err = 0; /* No errors */ 70178113Sdes 70278113Sdes nend: 70378025Sdes if (err) { /* if we didn't timeout... */ 70478113Sdes ifp->if_oerrors++; 70578113Sdes lprintf("X"); 70678113Sdes } else { 707138281Scperciva ifp->if_opackets++; 70878113Sdes ifp->if_obytes += m->m_pkthdr.len; 70978113Sdes if (ifp->if_bpf) 71078113Sdes lptap(ifp, m); 71178113Sdes } 71278113Sdes 71378113Sdes m_freem(m); 71478113Sdes 71578113Sdes if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 71678113Sdes lprintf("^"); 71778113Sdes lp_intr(dev); 71878113Sdes } 71978113Sdes (void) splx(s); 72094620Sjhb return 0; 721127694Spjd } 72294620Sjhb 72394620Sjhb if (ppb_rstr(ppbus) & LPIP_SHAKE) { 72494620Sjhb lprintf("&"); 72594620Sjhb lp_intr(dev); 72694620Sjhb } 72794620Sjhb 72894620Sjhb if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 729103767Sjake goto end; 730103767Sjake if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 73194620Sjhb goto end; 73294620Sjhb 733138281Scperciva mm = m; 734138281Scperciva do { 735138281Scperciva cp = mtod(mm,u_char *); 736138281Scperciva len = mm->m_len; 737138281Scperciva while (len--) 738138281Scperciva if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 739138281Scperciva goto end; 740138281Scperciva } while ((mm = mm->m_next)); 741138281Scperciva 742138281Scperciva err = 0; /* no errors were encountered */ 74394620Sjhb 744138281Scperciva end: 74594620Sjhb --cp; 74678113Sdes ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); 747138281Scperciva 74878113Sdes if (err) { /* if we didn't timeout... */ 74978113Sdes ifp->if_oerrors++; 75078113Sdes lprintf("X"); 75178113Sdes } else { 75278113Sdes ifp->if_opackets++; 75378113Sdes ifp->if_obytes += m->m_pkthdr.len; 754116173Sobrien if (ifp->if_bpf) 755116173Sobrien lptap(ifp, m); 756116173Sobrien } 757116173Sobrien 758116173Sobrien m_freem(m); 759116173Sobrien 760116173Sobrien if (ppb_rstr(ppbus) & LPIP_SHAKE) { 761116173Sobrien lprintf("^"); 762116173Sobrien lp_intr(dev); 763116173Sobrien } 764116173Sobrien 765116173Sobrien (void) splx(s); 766116173Sobrien return 0; 767116173Sobrien} 768116173Sobrien 769116173Sobrienstatic device_method_t lp_methods[] = { 770121265Scognet /* device interface */ 771121246Scognet DEVMETHOD(device_identify, lp_identify), 772121246Scognet DEVMETHOD(device_probe, lp_probe), 773121265Scognet DEVMETHOD(device_attach, lp_attach), 774121265Scognet 775121265Scognet { 0, 0 } 776121265Scognet}; 777121265Scognet 778121265Scognetstatic driver_t lp_driver = { 779121265Scognet "plip", 780137507Sphk lp_methods, 781137507Sphk sizeof(struct lp_data), 782121246Scognet}; 783121246Scognet 784121246ScognetDRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0); 785121246Scognet