if_plip.c revision 184896
1170159Sariff/*- 2170159Sariff * Copyright (c) 1997 Poul-Henning Kamp 3170159Sariff * All rights reserved. 4170159Sariff * 5170159Sariff * Redistribution and use in source and binary forms, with or without 6170159Sariff * modification, are permitted provided that the following conditions 7170159Sariff * are met: 8170159Sariff * 1. Redistributions of source code must retain the above copyright 9170159Sariff * notice, this list of conditions and the following disclaimer. 10170159Sariff * 2. Redistributions in binary form must reproduce the above copyright 11170159Sariff * notice, this list of conditions and the following disclaimer in the 12170159Sariff * documentation and/or other materials provided with the distribution. 13170159Sariff * 14170159Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15170159Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16170159Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17170159Sariff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18170159Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19170159Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20170159Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21170159Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22170159Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23170159Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24170159Sariff * SUCH DAMAGE. 25170159Sariff * 26170159Sariff * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 27170159Sariff */ 28170159Sariff 29170159Sariff#include <sys/cdefs.h> 30170159Sariff__FBSDID("$FreeBSD: head/sys/dev/ppbus/if_plip.c 184896 2008-11-12 22:14:05Z jhb $"); 31170159Sariff 32170159Sariff/* 33170159Sariff * Parallel port TCP/IP interfaces added. I looked at the driver from 34170159Sariff * MACH but this is a complete rewrite, and btw. incompatible, and it 35170159Sariff * should perform better too. I have never run the MACH driver though. 36170159Sariff * 37170159Sariff * This driver sends two bytes (0x08, 0x00) in front of each packet, 38170159Sariff * to allow us to distinguish another format later. 39170159Sariff * 40170159Sariff * Now added a Linux/Crynwr compatibility mode which is enabled using 41170159Sariff * IF_LINK0 - Tim Wilkinson. 42170159Sariff * 43170159Sariff * TODO: 44170159Sariff * Make HDLC/PPP mode, use IF_LLC1 to enable. 45170159Sariff * 46170159Sariff * Connect the two computers using a Laplink parallel cable to use this 47170159Sariff * feature: 48170159Sariff * 49170159Sariff * +----------------------------------------+ 50170159Sariff * |A-name A-End B-End Descr. Port/Bit | 51170159Sariff * +----------------------------------------+ 52170159Sariff * |DATA0 2 15 Data 0/0x01 | 53170159Sariff * |-ERROR 15 2 1/0x08 | 54170159Sariff * +----------------------------------------+ 55170159Sariff * |DATA1 3 13 Data 0/0x02 | 56170159Sariff * |+SLCT 13 3 1/0x10 | 57170159Sariff * +----------------------------------------+ 58170159Sariff * |DATA2 4 12 Data 0/0x04 | 59170159Sariff * |+PE 12 4 1/0x20 | 60170159Sariff * +----------------------------------------+ 61170159Sariff * |DATA3 5 10 Strobe 0/0x08 | 62170159Sariff * |-ACK 10 5 1/0x40 | 63170159Sariff * +----------------------------------------+ 64170159Sariff * |DATA4 6 11 Data 0/0x10 | 65170159Sariff * |BUSY 11 6 1/~0x80 | 66170159Sariff * +----------------------------------------+ 67170159Sariff * |GND 18-25 18-25 GND - | 68170159Sariff * +----------------------------------------+ 69170159Sariff * 70170159Sariff * Expect transfer-rates up to 75 kbyte/sec. 71170159Sariff * 72170159Sariff * If GCC could correctly grok 73170159Sariff * register int port asm("edx") 74170159Sariff * the code would be cleaner 75170159Sariff * 76170159Sariff * Poul-Henning Kamp <phk@freebsd.org> 77170159Sariff */ 78170159Sariff 79170159Sariff/* 80170159Sariff * Update for ppbus, PLIP support only - Nicolas Souchu 81170159Sariff */ 82170159Sariff 83170159Sariff#include "opt_plip.h" 84170159Sariff 85170159Sariff#include <sys/param.h> 86170159Sariff#include <sys/systm.h> 87170159Sariff#include <sys/module.h> 88170159Sariff#include <sys/bus.h> 89170159Sariff#include <sys/mbuf.h> 90170159Sariff#include <sys/socket.h> 91170159Sariff#include <sys/sockio.h> 92170159Sariff#include <sys/kernel.h> 93170159Sariff#include <sys/malloc.h> 94170159Sariff 95170159Sariff#include <machine/bus.h> 96170159Sariff#include <machine/resource.h> 97170159Sariff#include <sys/rman.h> 98170159Sariff 99170159Sariff#include <net/if.h> 100170159Sariff#include <net/if_types.h> 101170159Sariff#include <net/netisr.h> 102170159Sariff 103170159Sariff#include <netinet/in.h> 104170159Sariff#include <netinet/in_var.h> 105170159Sariff 106170159Sariff#include <net/bpf.h> 107170159Sariff 108170159Sariff#include <dev/ppbus/ppbconf.h> 109170159Sariff#include "ppbus_if.h" 110170159Sariff#include <dev/ppbus/ppbio.h> 111170159Sariff 112170159Sariff#ifndef LPMTU /* MTU for the lp# interfaces */ 113170159Sariff#define LPMTU 1500 114170159Sariff#endif 115170159Sariff 116170159Sariff#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 117170159Sariff#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 118170159Sariff#endif 119170159Sariff 120170159Sariff#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 121170159Sariff#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 122170159Sariff#endif 123170159Sariff 124170159Sariff#ifndef LPMAXERRS /* Max errors before !RUNNING */ 125170159Sariff#define LPMAXERRS 100 126170159Sariff#endif 127170159Sariff 128170159Sariff#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 129170159Sariff#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 130170159Sariff#define MLPIPHDRLEN CLPIPHDRLEN 131170159Sariff 132170159Sariff#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 133170159Sariff#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 134170159Sariff#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 135170159Sariff#define MLPIPHDRLEN LPIPHDRLEN 136170159Sariff#endif 137170159Sariff 138170159Sariff#define LPIPTBLSIZE 256 /* Size of octet translation table */ 139170159Sariff 140170159Sariff#define lprintf if (lptflag) printf 141170159Sariff 142170159Sariff#ifdef PLIP_DEBUG 143170159Sariffstatic int volatile lptflag = 1; 144170159Sariff#else 145170159Sariffstatic int volatile lptflag = 0; 146170159Sariff#endif 147170159Sariff 148170159Sariffstruct lp_data { 149170159Sariff struct ifnet *sc_ifp; 150170159Sariff device_t sc_dev; 151170159Sariff u_char *sc_ifbuf; 152170159Sariff int sc_iferrs; 153170159Sariff 154170159Sariff struct resource *res_irq; 155170159Sariff}; 156170159Sariff 157170159Sariff/* Tables for the lp# interface */ 158170159Sariffstatic u_char *txmith; 159170159Sariff#define txmitl (txmith + (1 * LPIPTBLSIZE)) 160170159Sariff#define trecvh (txmith + (2 * LPIPTBLSIZE)) 161170159Sariff#define trecvl (txmith + (3 * LPIPTBLSIZE)) 162170159Sariff 163170159Sariffstatic u_char *ctxmith; 164170159Sariff#define ctxmitl (ctxmith + (1 * LPIPTBLSIZE)) 165170159Sariff#define ctrecvh (ctxmith + (2 * LPIPTBLSIZE)) 166170159Sariff#define ctrecvl (ctxmith + (3 * LPIPTBLSIZE)) 167170159Sariff 168170159Sariff/* Functions for the lp# interface */ 169170159Sariffstatic int lpinittables(void); 170170159Sariffstatic int lpioctl(struct ifnet *, u_long, caddr_t); 171170159Sariffstatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 172170159Sariff struct rtentry *); 173170159Sariffstatic void lp_intr(void *); 174170159Sariff 175170159Sariff#define DEVTOSOFTC(dev) \ 176170159Sariff ((struct lp_data *)device_get_softc(dev)) 177170159Sariff 178170159Sariffstatic devclass_t lp_devclass; 179170159Sariff 180170159Sariffstatic void 181170159Sarifflp_identify(driver_t *driver, device_t parent) 182170159Sariff{ 183170159Sariff device_t dev; 184170159Sariff 185170159Sariff dev = device_find_child(parent, "plip", -1); 186170159Sariff if (!dev) 187170159Sariff BUS_ADD_CHILD(parent, 0, "plip", -1); 188170159Sariff} 189170159Sariff 190170159Sariffstatic int 191170159Sarifflp_probe(device_t dev) 192170159Sariff{ 193170159Sariff 194170159Sariff device_set_desc(dev, "PLIP network interface"); 195170159Sariff 196170159Sariff return (0); 197170159Sariff} 198170159Sariff 199170159Sariffstatic int 200170159Sarifflp_attach(device_t dev) 201170159Sariff{ 202170159Sariff struct lp_data *lp = DEVTOSOFTC(dev); 203170159Sariff struct ifnet *ifp; 204170159Sariff int rid = 0; 205170159Sariff 206170159Sariff lp->sc_dev = dev; 207170159Sariff 208170159Sariff /* 209170159Sariff * Reserve the interrupt resource. If we don't have one, the 210170159Sariff * attach fails. 211170159Sariff */ 212170159Sariff lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 213170159Sariff RF_SHAREABLE); 214170159Sariff if (lp->res_irq == 0) { 215170159Sariff device_printf(dev, "cannot reserve interrupt, failed.\n"); 216170159Sariff return (ENXIO); 217170159Sariff } 218170159Sariff 219170159Sariff ifp = lp->sc_ifp = if_alloc(IFT_PARA); 220170159Sariff if (ifp == NULL) { 221170159Sariff return (ENOSPC); 222170159Sariff } 223170159Sariff 224170159Sariff ifp->if_softc = lp; 225170159Sariff if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 226170159Sariff ifp->if_mtu = LPMTU; 227170159Sariff ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST | 228170159Sariff IFF_NEEDSGIANT; 229170159Sariff ifp->if_ioctl = lpioctl; 230170159Sariff ifp->if_output = lpoutput; 231170159Sariff ifp->if_hdrlen = 0; 232170159Sariff ifp->if_addrlen = 0; 233170159Sariff ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 234170159Sariff if_attach(ifp); 235170159Sariff 236170159Sariff bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 237170159Sariff 238170159Sariff return (0); 239170159Sariff} 240170159Sariff/* 241170159Sariff * Build the translation tables for the LPIP (BSD unix) protocol. 242170159Sariff * We don't want to calculate these nasties in our tight loop, so we 243170159Sariff * precalculate them when we initialize. 244170159Sariff */ 245170159Sariffstatic int 246170159Sarifflpinittables(void) 247170159Sariff{ 248170159Sariff int i; 249170159Sariff 250170159Sariff if (txmith == NULL) 251170159Sariff txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 252170159Sariff 253170159Sariff if (txmith == NULL) 254170159Sariff return (1); 255170159Sariff 256170159Sariff if (ctxmith == NULL) 257170159Sariff ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 258170159Sariff 259170159Sariff if (ctxmith == NULL) 260170159Sariff return (1); 261170159Sariff 262170159Sariff for (i = 0; i < LPIPTBLSIZE; i++) { 263170159Sariff ctxmith[i] = (i & 0xF0) >> 4; 264170159Sariff ctxmitl[i] = 0x10 | (i & 0x0F); 265170159Sariff ctrecvh[i] = (i & 0x78) << 1; 266170159Sariff ctrecvl[i] = (i & 0x78) >> 3; 267170159Sariff } 268170159Sariff 269170159Sariff for (i = 0; i < LPIPTBLSIZE; i++) { 270170159Sariff txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 271170159Sariff txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 272170159Sariff trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 273170159Sariff trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 274170159Sariff } 275170159Sariff 276170159Sariff return (0); 277170159Sariff} 278170159Sariff 279170159Sariff/* 280170159Sariff * Process an ioctl request. 281170159Sariff */ 282170159Sariffstatic int 283170159Sarifflpioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 284170159Sariff{ 285170159Sariff struct lp_data *sc = ifp->if_softc; 286170159Sariff device_t dev = sc->sc_dev; 287170159Sariff device_t ppbus = device_get_parent(dev); 288170159Sariff struct ifaddr *ifa = (struct ifaddr *)data; 289170159Sariff struct ifreq *ifr = (struct ifreq *)data; 290170159Sariff u_char *ptr; 291170159Sariff void *ih; 292170159Sariff int error; 293170159Sariff 294170159Sariff switch (cmd) { 295170159Sariff case SIOCSIFDSTADDR: 296170159Sariff case SIOCAIFADDR: 297170159Sariff case SIOCSIFADDR: 298170159Sariff if (ifa->ifa_addr->sa_family != AF_INET) 299170159Sariff return (EAFNOSUPPORT); 300170159Sariff 301170159Sariff ifp->if_flags |= IFF_UP; 302170159Sariff /* FALLTHROUGH */ 303170159Sariff case SIOCSIFFLAGS: 304170159Sariff if ((!(ifp->if_flags & IFF_UP)) && 305170159Sariff (ifp->if_drv_flags & IFF_DRV_RUNNING)) { 306170159Sariff 307170159Sariff ppb_wctr(ppbus, 0x00); 308170159Sariff ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 309170159Sariff 310170159Sariff /* IFF_UP is not set, try to release the bus anyway */ 311170159Sariff ppb_release_bus(ppbus, dev); 312170159Sariff break; 313170159Sariff } 314170159Sariff if (((ifp->if_flags & IFF_UP)) && 315170159Sariff (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { 316170159Sariff 317170159Sariff /* XXX 318170159Sariff * Should the request be interruptible? 319170159Sariff */ 320170159Sariff if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT | 321170159Sariff PPB_INTR))) 322170159Sariff return (error); 323170159Sariff 324170159Sariff /* Now IFF_UP means that we own the bus */ 325170159Sariff ppb_set_mode(ppbus, PPB_COMPATIBLE); 326170159Sariff 327170159Sariff if (lpinittables()) { 328170159Sariff ppb_release_bus(ppbus, dev); 329170159Sariff return (ENOBUFS); 330170159Sariff } 331170159Sariff 332170159Sariff sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN, 333170159Sariff M_DEVBUF, M_WAITOK); 334170159Sariff if (sc->sc_ifbuf == NULL) { 335170159Sariff ppb_release_bus(ppbus, dev); 336170159Sariff return (ENOBUFS); 337170159Sariff } 338170159Sariff 339170159Sariff /* 340170159Sariff * Attach our interrupt handler. It is 341170159Sariff * detached later when the bus is released. 342170159Sariff */ 343170159Sariff if ((error = bus_setup_intr(dev, sc->res_irq, 344170159Sariff INTR_TYPE_NET, NULL, lp_intr, dev, &ih))) { 345170159Sariff ppb_release_bus(ppbus, dev); 346170159Sariff return (error); 347170159Sariff } 348170159Sariff 349170159Sariff ppb_wctr(ppbus, IRQENABLE); 350170159Sariff ifp->if_drv_flags |= IFF_DRV_RUNNING; 351170159Sariff } 352170159Sariff break; 353170159Sariff 354170159Sariff case SIOCSIFMTU: 355170159Sariff ptr = sc->sc_ifbuf; 356170159Sariff sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF, 357170159Sariff M_NOWAIT); 358170159Sariff if (sc->sc_ifbuf == NULL) { 359170159Sariff sc->sc_ifbuf = ptr; 360170159Sariff return (ENOBUFS); 361170159Sariff } 362170159Sariff if (ptr) 363170159Sariff free(ptr, M_DEVBUF); 364170159Sariff sc->sc_ifp->if_mtu = ifr->ifr_mtu; 365170159Sariff break; 366170159Sariff 367170159Sariff case SIOCGIFMTU: 368170159Sariff ifr->ifr_mtu = sc->sc_ifp->if_mtu; 369170159Sariff break; 370170159Sariff 371170159Sariff case SIOCADDMULTI: 372170159Sariff case SIOCDELMULTI: 373170159Sariff if (ifr == 0) { 374170159Sariff return (EAFNOSUPPORT); /* XXX */ 375170159Sariff } 376170159Sariff switch (ifr->ifr_addr.sa_family) { 377170159Sariff case AF_INET: 378170159Sariff break; 379170159Sariff default: 380170159Sariff return (EAFNOSUPPORT); 381170159Sariff } 382170159Sariff break; 383170159Sariff 384170159Sariff case SIOCGIFMEDIA: 385170159Sariff /* 386170159Sariff * No ifmedia support at this stage; maybe use it 387170159Sariff * in future for eg. protocol selection. 388170159Sariff */ 389170159Sariff return (EINVAL); 390170159Sariff 391170159Sariff default: 392170159Sariff lprintf("LP:ioctl(0x%lx)\n", cmd); 393170159Sariff return (EINVAL); 394170159Sariff } 395170159Sariff return (0); 396170159Sariff} 397170159Sariff 398170159Sariffstatic __inline int 399170159Sariffclpoutbyte(u_char byte, int spin, device_t ppbus) 400170159Sariff{ 401170159Sariff 402170159Sariff ppb_wdtr(ppbus, ctxmitl[byte]); 403170159Sariff while (ppb_rstr(ppbus) & CLPIP_SHAKE) 404170159Sariff if (--spin == 0) { 405170159Sariff return (1); 406170159Sariff } 407170159Sariff ppb_wdtr(ppbus, ctxmith[byte]); 408170159Sariff while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 409170159Sariff if (--spin == 0) { 410170159Sariff return (1); 411170159Sariff } 412170159Sariff return (0); 413170159Sariff} 414170159Sariff 415170159Sariffstatic __inline int 416170159Sariffclpinbyte(int spin, device_t ppbus) 417170159Sariff{ 418170159Sariff u_char c, cl; 419170159Sariff 420170159Sariff while((ppb_rstr(ppbus) & CLPIP_SHAKE)) 421170159Sariff if (!--spin) { 422170159Sariff return (-1); 423170159Sariff } 424170159Sariff cl = ppb_rstr(ppbus); 425170159Sariff ppb_wdtr(ppbus, 0x10); 426170159Sariff 427170159Sariff while(!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 428170159Sariff if (!--spin) { 429170159Sariff return (-1); 430170159Sariff } 431170159Sariff c = ppb_rstr(ppbus); 432170159Sariff ppb_wdtr(ppbus, 0x00); 433170159Sariff 434170159Sariff return (ctrecvl[cl] | ctrecvh[c]); 435170159Sariff} 436170159Sariff 437170159Sariffstatic void 438170159Sarifflptap(struct ifnet *ifp, struct mbuf *m) 439170159Sariff{ 440170159Sariff u_int32_t af = AF_INET; 441170159Sariff 442170159Sariff bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 443170159Sariff} 444170159Sariff 445170159Sariffstatic void 446170159Sarifflp_intr(void *arg) 447170159Sariff{ 448170159Sariff device_t dev = (device_t)arg; 449170159Sariff device_t ppbus = device_get_parent(dev); 450170159Sariff struct lp_data *sc = DEVTOSOFTC(dev); 451170159Sariff int len, s, j; 452170159Sariff u_char *bp; 453170159Sariff u_char c, cl; 454170159Sariff struct mbuf *top; 455170159Sariff 456170159Sariff s = splhigh(); 457170159Sariff 458170159Sariff if (sc->sc_ifp->if_flags & IFF_LINK0) { 459170159Sariff 460170159Sariff /* Ack. the request */ 461170159Sariff ppb_wdtr(ppbus, 0x01); 462170159Sariff 463170159Sariff /* Get the packet length */ 464170159Sariff j = clpinbyte(LPMAXSPIN2, ppbus); 465170159Sariff if (j == -1) 466170159Sariff goto err; 467170159Sariff len = j; 468170159Sariff j = clpinbyte(LPMAXSPIN2, ppbus); 469170159Sariff if (j == -1) 470170159Sariff goto err; 471170159Sariff len = len + (j << 8); 472170159Sariff if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN) 473170159Sariff goto err; 474170159Sariff 475170159Sariff bp = sc->sc_ifbuf; 476170159Sariff 477170159Sariff while (len--) { 478170159Sariff j = clpinbyte(LPMAXSPIN2, ppbus); 479170159Sariff if (j == -1) { 480170159Sariff goto err; 481170159Sariff } 482170159Sariff *bp++ = j; 483170159Sariff } 484170159Sariff 485170159Sariff /* Get and ignore checksum */ 486170159Sariff j = clpinbyte(LPMAXSPIN2, ppbus); 487170159Sariff if (j == -1) { 488170159Sariff goto err; 489170159Sariff } 490170159Sariff 491170159Sariff len = bp - sc->sc_ifbuf; 492170159Sariff if (len <= CLPIPHDRLEN) 493170159Sariff goto err; 494170159Sariff 495170159Sariff sc->sc_iferrs = 0; 496170159Sariff 497170159Sariff len -= CLPIPHDRLEN; 498170159Sariff sc->sc_ifp->if_ipackets++; 499170159Sariff sc->sc_ifp->if_ibytes += len; 500170159Sariff top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp, 501170159Sariff 0); 502170159Sariff if (top) { 503170159Sariff if (bpf_peers_present(sc->sc_ifp->if_bpf)) 504170159Sariff lptap(sc->sc_ifp, top); 505170159Sariff 506170159Sariff /* mbuf is free'd on failure. */ 507170159Sariff netisr_queue(NETISR_IP, top); 508170159Sariff } 509170159Sariff goto done; 510170159Sariff } 511170159Sariff while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { 512170159Sariff len = sc->sc_ifp->if_mtu + LPIPHDRLEN; 513170159Sariff bp = sc->sc_ifbuf; 514170159Sariff while (len--) { 515170159Sariff 516170159Sariff cl = ppb_rstr(ppbus); 517170159Sariff ppb_wdtr(ppbus, 8); 518170159Sariff 519170159Sariff j = LPMAXSPIN2; 520170159Sariff while((ppb_rstr(ppbus) & LPIP_SHAKE)) 521170159Sariff if (!--j) 522170159Sariff goto err; 523170159Sariff 524170159Sariff c = ppb_rstr(ppbus); 525170159Sariff ppb_wdtr(ppbus, 0); 526170159Sariff 527170159Sariff *bp++= trecvh[cl] | trecvl[c]; 528170159Sariff 529170159Sariff j = LPMAXSPIN2; 530170159Sariff while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) { 531170159Sariff if (cl != c && 532170159Sariff (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) == 533170159Sariff (c & 0xf8)) 534170159Sariff goto end; 535170159Sariff if (!--j) 536170159Sariff goto err; 537170159Sariff } 538170159Sariff } 539170159Sariff 540170159Sariff end: 541170159Sariff len = bp - sc->sc_ifbuf; 542170159Sariff if (len <= LPIPHDRLEN) 543170159Sariff goto err; 544170159Sariff 545170159Sariff sc->sc_iferrs = 0; 546170159Sariff 547170159Sariff len -= LPIPHDRLEN; 548170159Sariff sc->sc_ifp->if_ipackets++; 549170159Sariff sc->sc_ifp->if_ibytes += len; 550170159Sariff top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp, 551170159Sariff 0); 552170159Sariff if (top) { 553170159Sariff if (bpf_peers_present(sc->sc_ifp->if_bpf)) 554170159Sariff lptap(sc->sc_ifp, top); 555170159Sariff 556170159Sariff /* mbuf is free'd on failure. */ 557170159Sariff netisr_queue(NETISR_IP, top); 558170159Sariff } 559170159Sariff } 560170159Sariff goto done; 561170159Sariff 562170159Sariff err: 563170159Sariff ppb_wdtr(ppbus, 0); 564170159Sariff lprintf("R"); 565170159Sariff sc->sc_ifp->if_ierrors++; 566170159Sariff sc->sc_iferrs++; 567170159Sariff 568170159Sariff /* 569170159Sariff * We are not able to send receive anything for now, 570170159Sariff * so stop wasting our time 571170159Sariff */ 572170159Sariff if (sc->sc_iferrs > LPMAXERRS) { 573170159Sariff if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n"); 574170159Sariff ppb_wctr(ppbus, 0x00); 575170159Sariff sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 576170159Sariff sc->sc_iferrs = 0; 577170159Sariff } 578170159Sariff 579170159Sariff done: 580170159Sariff splx(s); 581170159Sariff} 582170159Sariff 583170159Sariffstatic __inline int 584170159Sarifflpoutbyte (u_char byte, int spin, device_t ppbus) 585170159Sariff{ 586170159Sariff 587170159Sariff ppb_wdtr(ppbus, txmith[byte]); 588170159Sariff while (!(ppb_rstr(ppbus) & LPIP_SHAKE)) 589170159Sariff if (--spin == 0) 590170159Sariff return (1); 591170159Sariff ppb_wdtr(ppbus, txmitl[byte]); 592170159Sariff while (ppb_rstr(ppbus) & LPIP_SHAKE) 593170159Sariff if (--spin == 0) 594170159Sariff return (1); 595170159Sariff return (0); 596170159Sariff} 597170159Sariff 598170159Sariffstatic int 599170159Sarifflpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 600170159Sariff struct rtentry *rt) 601170159Sariff{ 602170159Sariff struct lp_data *sc = ifp->if_softc; 603170159Sariff device_t dev = sc->sc_dev; 604170159Sariff device_t ppbus = device_get_parent(dev); 605170159Sariff int s, err; 606170159Sariff struct mbuf *mm; 607170159Sariff u_char *cp = "\0\0"; 608170159Sariff u_char chksum = 0; 609170159Sariff int count = 0; 610170159Sariff int i, len, spin; 611170159Sariff 612170159Sariff /* We need a sensible value if we abort */ 613170159Sariff cp++; 614170159Sariff ifp->if_drv_flags |= IFF_DRV_RUNNING; 615170159Sariff 616170159Sariff err = 1; /* assume we're aborting because of an error */ 617170159Sariff 618170159Sariff s = splhigh(); 619170159Sariff 620170159Sariff /* Suspend (on laptops) or receive-errors might have taken us offline */ 621170159Sariff ppb_wctr(ppbus, IRQENABLE); 622170159Sariff 623170159Sariff if (ifp->if_flags & IFF_LINK0) { 624170159Sariff if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 625170159Sariff lprintf("&"); 626170159Sariff lp_intr(dev); 627170159Sariff } 628170159Sariff 629170159Sariff /* Alert other end to pending packet */ 630170159Sariff spin = LPMAXSPIN1; 631170159Sariff ppb_wdtr(ppbus, 0x08); 632170159Sariff while ((ppb_rstr(ppbus) & 0x08) == 0) 633170159Sariff if (--spin == 0) { 634170159Sariff goto nend; 635170159Sariff } 636170159Sariff 637170159Sariff /* Calculate length of packet, then send that */ 638170159Sariff 639170159Sariff count += 14; /* Ethernet header len */ 640170159Sariff 641170159Sariff mm = m; 642170159Sariff for (mm = m; mm; mm = mm->m_next) { 643170159Sariff count += mm->m_len; 644170159Sariff } 645170159Sariff if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 646170159Sariff goto nend; 647170159Sariff if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 648170159Sariff goto nend; 649170159Sariff 650170159Sariff /* Send dummy ethernet header */ 651170159Sariff for (i = 0; i < 12; i++) { 652170159Sariff if (clpoutbyte(i, LPMAXSPIN1, ppbus)) 653170159Sariff goto nend; 654170159Sariff chksum += i; 655170159Sariff } 656170159Sariff 657170159Sariff if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 658170159Sariff goto nend; 659170159Sariff if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 660170159Sariff goto nend; 661170159Sariff chksum += 0x08 + 0x00; /* Add into checksum */ 662170159Sariff 663170159Sariff mm = m; 664170159Sariff do { 665170159Sariff cp = mtod(mm, u_char *); 666170159Sariff len = mm->m_len; 667170159Sariff while (len--) { 668170159Sariff chksum += *cp; 669170159Sariff if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 670170159Sariff goto nend; 671170159Sariff } 672170159Sariff } while ((mm = mm->m_next)); 673170159Sariff 674170159Sariff /* Send checksum */ 675170159Sariff if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 676170159Sariff goto nend; 677170159Sariff 678170159Sariff /* Go quiescent */ 679170159Sariff ppb_wdtr(ppbus, 0); 680170159Sariff 681170159Sariff err = 0; /* No errors */ 682170159Sariff 683170159Sariff nend: 684170159Sariff if (err) { /* if we didn't timeout... */ 685170159Sariff ifp->if_oerrors++; 686170159Sariff lprintf("X"); 687170159Sariff } else { 688170159Sariff ifp->if_opackets++; 689170159Sariff ifp->if_obytes += m->m_pkthdr.len; 690170159Sariff if (bpf_peers_present(ifp->if_bpf)) 691170159Sariff lptap(ifp, m); 692170159Sariff } 693170159Sariff 694170159Sariff m_freem(m); 695170159Sariff 696170159Sariff if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 697170159Sariff lprintf("^"); 698170159Sariff lp_intr(dev); 699170159Sariff } 700170159Sariff (void) splx(s); 701170159Sariff return (0); 702170159Sariff } 703170159Sariff 704170159Sariff if (ppb_rstr(ppbus) & LPIP_SHAKE) { 705170159Sariff lprintf("&"); 706170159Sariff lp_intr(dev); 707170159Sariff } 708170159Sariff 709170159Sariff if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 710170159Sariff goto end; 711170159Sariff if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 712170159Sariff goto end; 713170159Sariff 714170159Sariff mm = m; 715170159Sariff do { 716170159Sariff cp = mtod(mm, u_char *); 717170159Sariff len = mm->m_len; 718170159Sariff while (len--) 719170159Sariff if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 720170159Sariff goto end; 721170159Sariff } while ((mm = mm->m_next)); 722170159Sariff 723170159Sariff err = 0; /* no errors were encountered */ 724170159Sariff 725170159Sariffend: 726170159Sariff --cp; 727170159Sariff ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); 728170159Sariff 729170159Sariff if (err) { /* if we didn't timeout... */ 730170159Sariff ifp->if_oerrors++; 731170159Sariff lprintf("X"); 732170159Sariff } else { 733170159Sariff ifp->if_opackets++; 734170159Sariff ifp->if_obytes += m->m_pkthdr.len; 735170159Sariff if (bpf_peers_present(ifp->if_bpf)) 736170159Sariff lptap(ifp, m); 737170159Sariff } 738170159Sariff 739170159Sariff m_freem(m); 740170159Sariff 741170159Sariff if (ppb_rstr(ppbus) & LPIP_SHAKE) { 742170159Sariff lprintf("^"); 743170159Sariff lp_intr(dev); 744170159Sariff } 745170159Sariff 746170159Sariff (void) splx(s); 747170159Sariff return (0); 748170159Sariff} 749170159Sariff 750170159Sariffstatic device_method_t lp_methods[] = { 751170159Sariff /* device interface */ 752170159Sariff DEVMETHOD(device_identify, lp_identify), 753170159Sariff DEVMETHOD(device_probe, lp_probe), 754170159Sariff DEVMETHOD(device_attach, lp_attach), 755170159Sariff 756170159Sariff { 0, 0 } 757170159Sariff}; 758170159Sariff 759170159Sariffstatic driver_t lp_driver = { 760170159Sariff "plip", 761170159Sariff lp_methods, 762170159Sariff sizeof(struct lp_data), 763170159Sariff}; 764170159Sariff 765170159SariffDRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0); 766170159SariffMODULE_DEPEND(plip, ppbus, 1, 1, 1); 767170159Sariff