146f3ff79SMike Smith /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 446f3ff79SMike Smith * Copyright (c) 1997 Poul-Henning Kamp 546f3ff79SMike Smith * All rights reserved. 646f3ff79SMike Smith * 746f3ff79SMike Smith * Redistribution and use in source and binary forms, with or without 846f3ff79SMike Smith * modification, are permitted provided that the following conditions 946f3ff79SMike Smith * are met: 1046f3ff79SMike Smith * 1. Redistributions of source code must retain the above copyright 1146f3ff79SMike Smith * notice, this list of conditions and the following disclaimer. 1246f3ff79SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1346f3ff79SMike Smith * notice, this list of conditions and the following disclaimer in the 1446f3ff79SMike Smith * documentation and/or other materials provided with the distribution. 1546f3ff79SMike Smith * 1646f3ff79SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1746f3ff79SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1846f3ff79SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1946f3ff79SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2046f3ff79SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2146f3ff79SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2246f3ff79SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2346f3ff79SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2446f3ff79SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2546f3ff79SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2646f3ff79SMike Smith * SUCH DAMAGE. 2746f3ff79SMike Smith * 2846f3ff79SMike Smith * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 2946f3ff79SMike Smith */ 3046f3ff79SMike Smith 31aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 33aad970f1SDavid E. O'Brien 3446f3ff79SMike Smith /* 3546f3ff79SMike Smith * Parallel port TCP/IP interfaces added. I looked at the driver from 3646f3ff79SMike Smith * MACH but this is a complete rewrite, and btw. incompatible, and it 3746f3ff79SMike Smith * should perform better too. I have never run the MACH driver though. 3846f3ff79SMike Smith * 3946f3ff79SMike Smith * This driver sends two bytes (0x08, 0x00) in front of each packet, 4046f3ff79SMike Smith * to allow us to distinguish another format later. 4146f3ff79SMike Smith * 42d64ada50SJens Schweikhardt * Now added a Linux/Crynwr compatibility mode which is enabled using 4346f3ff79SMike Smith * IF_LINK0 - Tim Wilkinson. 4446f3ff79SMike Smith * 4546f3ff79SMike Smith * TODO: 4646f3ff79SMike Smith * Make HDLC/PPP mode, use IF_LLC1 to enable. 4746f3ff79SMike Smith * 4846f3ff79SMike Smith * Connect the two computers using a Laplink parallel cable to use this 4946f3ff79SMike Smith * feature: 5046f3ff79SMike Smith * 5146f3ff79SMike Smith * +----------------------------------------+ 5246f3ff79SMike Smith * |A-name A-End B-End Descr. Port/Bit | 5346f3ff79SMike Smith * +----------------------------------------+ 5446f3ff79SMike Smith * |DATA0 2 15 Data 0/0x01 | 5546f3ff79SMike Smith * |-ERROR 15 2 1/0x08 | 5646f3ff79SMike Smith * +----------------------------------------+ 5746f3ff79SMike Smith * |DATA1 3 13 Data 0/0x02 | 5846f3ff79SMike Smith * |+SLCT 13 3 1/0x10 | 5946f3ff79SMike Smith * +----------------------------------------+ 6046f3ff79SMike Smith * |DATA2 4 12 Data 0/0x04 | 6146f3ff79SMike Smith * |+PE 12 4 1/0x20 | 6246f3ff79SMike Smith * +----------------------------------------+ 6346f3ff79SMike Smith * |DATA3 5 10 Strobe 0/0x08 | 6446f3ff79SMike Smith * |-ACK 10 5 1/0x40 | 6546f3ff79SMike Smith * +----------------------------------------+ 6646f3ff79SMike Smith * |DATA4 6 11 Data 0/0x10 | 6746f3ff79SMike Smith * |BUSY 11 6 1/~0x80 | 6846f3ff79SMike Smith * +----------------------------------------+ 6946f3ff79SMike Smith * |GND 18-25 18-25 GND - | 7046f3ff79SMike Smith * +----------------------------------------+ 7146f3ff79SMike Smith * 7246f3ff79SMike Smith * Expect transfer-rates up to 75 kbyte/sec. 7346f3ff79SMike Smith * 7446f3ff79SMike Smith * If GCC could correctly grok 7546f3ff79SMike Smith * register int port asm("edx") 7646f3ff79SMike Smith * the code would be cleaner 7746f3ff79SMike Smith * 7846f3ff79SMike Smith * Poul-Henning Kamp <phk@freebsd.org> 7946f3ff79SMike Smith */ 8046f3ff79SMike Smith 8146f3ff79SMike Smith /* 8246f3ff79SMike Smith * Update for ppbus, PLIP support only - Nicolas Souchu 8346f3ff79SMike Smith */ 840f210c92SNicolas Souchu 850f210c92SNicolas Souchu #include "opt_plip.h" 8646f3ff79SMike Smith 8746f3ff79SMike Smith #include <sys/param.h> 8846f3ff79SMike Smith #include <sys/systm.h> 890f210c92SNicolas Souchu #include <sys/module.h> 900f210c92SNicolas Souchu #include <sys/bus.h> 9146f3ff79SMike Smith #include <sys/mbuf.h> 9246f3ff79SMike Smith #include <sys/socket.h> 9346f3ff79SMike Smith #include <sys/sockio.h> 9446f3ff79SMike Smith #include <sys/kernel.h> 9546f3ff79SMike Smith #include <sys/malloc.h> 9646f3ff79SMike Smith 970f210c92SNicolas Souchu #include <machine/bus.h> 980f210c92SNicolas Souchu #include <machine/resource.h> 990f210c92SNicolas Souchu #include <sys/rman.h> 1000f210c92SNicolas Souchu 10146f3ff79SMike Smith #include <net/if.h> 10276039bc8SGleb Smirnoff #include <net/if_var.h> 10346f3ff79SMike Smith #include <net/if_types.h> 10446f3ff79SMike Smith #include <net/netisr.h> 105279aa3d4SKip Macy #include <net/route.h> 10646f3ff79SMike Smith 10746f3ff79SMike Smith #include <netinet/in.h> 10846f3ff79SMike Smith #include <netinet/in_var.h> 10946f3ff79SMike Smith 11046f3ff79SMike Smith #include <net/bpf.h> 11146f3ff79SMike Smith 11246f3ff79SMike Smith #include <dev/ppbus/ppbconf.h> 1130f210c92SNicolas Souchu #include "ppbus_if.h" 1140f210c92SNicolas Souchu #include <dev/ppbus/ppbio.h> 1157b7bf77eSNicolas Souchu 11646f3ff79SMike Smith #ifndef LPMTU /* MTU for the lp# interfaces */ 11746f3ff79SMike Smith #define LPMTU 1500 11846f3ff79SMike Smith #endif 11946f3ff79SMike Smith 12046f3ff79SMike Smith #ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 12146f3ff79SMike Smith #define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 12246f3ff79SMike Smith #endif 12346f3ff79SMike Smith 12446f3ff79SMike Smith #ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 12546f3ff79SMike Smith #define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 12646f3ff79SMike Smith #endif 12746f3ff79SMike Smith 12846f3ff79SMike Smith #ifndef LPMAXERRS /* Max errors before !RUNNING */ 12946f3ff79SMike Smith #define LPMAXERRS 100 13046f3ff79SMike Smith #endif 13146f3ff79SMike Smith 13246f3ff79SMike Smith #define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 13346f3ff79SMike Smith #define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 13446f3ff79SMike Smith #define MLPIPHDRLEN CLPIPHDRLEN 13546f3ff79SMike Smith 13646f3ff79SMike Smith #define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 13746f3ff79SMike Smith #define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 13846f3ff79SMike Smith #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 13946f3ff79SMike Smith #define MLPIPHDRLEN LPIPHDRLEN 14046f3ff79SMike Smith #endif 14146f3ff79SMike Smith 14246f3ff79SMike Smith #define LPIPTBLSIZE 256 /* Size of octet translation table */ 14346f3ff79SMike Smith 14446f3ff79SMike Smith #define lprintf if (lptflag) printf 14520240fa3SNicolas Souchu 14620240fa3SNicolas Souchu #ifdef PLIP_DEBUG 14746f3ff79SMike Smith static int volatile lptflag = 1; 14820240fa3SNicolas Souchu #else 14920240fa3SNicolas Souchu static int volatile lptflag = 0; 15046f3ff79SMike Smith #endif 15146f3ff79SMike Smith 1520f210c92SNicolas Souchu struct lp_data { 153fc74a9f9SBrooks Davis struct ifnet *sc_ifp; 154ae6b868aSJohn Baldwin device_t sc_dev; 15546f3ff79SMike Smith u_char *sc_ifbuf; 15646f3ff79SMike Smith int sc_iferrs; 1570f210c92SNicolas Souchu 1580f210c92SNicolas Souchu struct resource *res_irq; 1592067d312SJohn Baldwin void *sc_intr_cookie; 16046f3ff79SMike Smith }; 16146f3ff79SMike Smith 1622067d312SJohn Baldwin static struct mtx lp_tables_lock; 1632067d312SJohn Baldwin MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF); 1642067d312SJohn Baldwin 16546f3ff79SMike Smith /* Tables for the lp# interface */ 16646f3ff79SMike Smith static u_char *txmith; 16746f3ff79SMike Smith #define txmitl (txmith + (1 * LPIPTBLSIZE)) 16846f3ff79SMike Smith #define trecvh (txmith + (2 * LPIPTBLSIZE)) 16946f3ff79SMike Smith #define trecvl (txmith + (3 * LPIPTBLSIZE)) 17046f3ff79SMike Smith 17146f3ff79SMike Smith static u_char *ctxmith; 17246f3ff79SMike Smith #define ctxmitl (ctxmith + (1 * LPIPTBLSIZE)) 17346f3ff79SMike Smith #define ctrecvh (ctxmith + (2 * LPIPTBLSIZE)) 17446f3ff79SMike Smith #define ctrecvl (ctxmith + (3 * LPIPTBLSIZE)) 17546f3ff79SMike Smith 17646f3ff79SMike Smith /* Functions for the lp# interface */ 17746f3ff79SMike Smith static int lpinittables(void); 178*2568cd2aSJustin Hibbits static int lpioctl(if_t, u_long, caddr_t); 179*2568cd2aSJustin Hibbits static int lpoutput(if_t, struct mbuf *, const struct sockaddr *, 180279aa3d4SKip Macy struct route *); 1812067d312SJohn Baldwin static void lpstop(struct lp_data *); 1820f210c92SNicolas Souchu static void lp_intr(void *); 1832067d312SJohn Baldwin static int lp_module_handler(module_t, int, void *); 18446f3ff79SMike Smith 1850f210c92SNicolas Souchu #define DEVTOSOFTC(dev) \ 1860f210c92SNicolas Souchu ((struct lp_data *)device_get_softc(dev)) 18746f3ff79SMike Smith 1882067d312SJohn Baldwin static int 1892067d312SJohn Baldwin lp_module_handler(module_t mod, int what, void *arg) 1902067d312SJohn Baldwin { 1912067d312SJohn Baldwin 1922067d312SJohn Baldwin switch (what) { 1932067d312SJohn Baldwin case MOD_UNLOAD: 1942067d312SJohn Baldwin mtx_lock(&lp_tables_lock); 1952067d312SJohn Baldwin if (txmith != NULL) { 1962067d312SJohn Baldwin free(txmith, M_DEVBUF); 1972067d312SJohn Baldwin txmith = NULL; 1982067d312SJohn Baldwin } 1992067d312SJohn Baldwin if (ctxmith != NULL) { 2002067d312SJohn Baldwin free(ctxmith, M_DEVBUF); 2012067d312SJohn Baldwin ctxmith = NULL; 2022067d312SJohn Baldwin } 2032067d312SJohn Baldwin mtx_unlock(&lp_tables_lock); 2042067d312SJohn Baldwin break; 2052067d312SJohn Baldwin case MOD_LOAD: 2062067d312SJohn Baldwin case MOD_QUIESCE: 2072067d312SJohn Baldwin break; 2082067d312SJohn Baldwin default: 2092067d312SJohn Baldwin return (EOPNOTSUPP); 2102067d312SJohn Baldwin } 2112067d312SJohn Baldwin return (0); 2122067d312SJohn Baldwin } 2132067d312SJohn Baldwin 2140f063508SPeter Wemm static void 2150f063508SPeter Wemm lp_identify(driver_t *driver, device_t parent) 2160f063508SPeter Wemm { 217a5c7e3bbSGuido van Rooij device_t dev; 2180f210c92SNicolas Souchu 21966de9771SJohn Baldwin dev = device_find_child(parent, "plip", -1); 220a5c7e3bbSGuido van Rooij if (!dev) 221338cad62SBernd Walter BUS_ADD_CHILD(parent, 0, "plip", -1); 2220f063508SPeter Wemm } 223c26864e0SJohn Baldwin 2240f210c92SNicolas Souchu static int 2250f210c92SNicolas Souchu lp_probe(device_t dev) 22646f3ff79SMike Smith { 22746f3ff79SMike Smith 2280f210c92SNicolas Souchu device_set_desc(dev, "PLIP network interface"); 22946f3ff79SMike Smith 2300f210c92SNicolas Souchu return (0); 23146f3ff79SMike Smith } 23246f3ff79SMike Smith 23346f3ff79SMike Smith static int 2340f210c92SNicolas Souchu lp_attach(device_t dev) 23546f3ff79SMike Smith { 2360f210c92SNicolas Souchu struct lp_data *lp = DEVTOSOFTC(dev); 237*2568cd2aSJustin Hibbits if_t ifp; 2382067d312SJohn Baldwin int error, rid = 0; 239ca3d3795SJohn Baldwin 240ae6b868aSJohn Baldwin lp->sc_dev = dev; 241ae6b868aSJohn Baldwin 242ca3d3795SJohn Baldwin /* 243ca3d3795SJohn Baldwin * Reserve the interrupt resource. If we don't have one, the 244ca3d3795SJohn Baldwin * attach fails. 245ca3d3795SJohn Baldwin */ 246ca3d3795SJohn Baldwin lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 247ca3d3795SJohn Baldwin RF_SHAREABLE); 2484d24901aSPedro F. Giffuni if (lp->res_irq == NULL) { 249ca3d3795SJohn Baldwin device_printf(dev, "cannot reserve interrupt, failed.\n"); 250ca3d3795SJohn Baldwin return (ENXIO); 251ca3d3795SJohn Baldwin } 252fc74a9f9SBrooks Davis 253fc74a9f9SBrooks Davis ifp = lp->sc_ifp = if_alloc(IFT_PARA); 254fc74a9f9SBrooks Davis if (ifp == NULL) { 255fc74a9f9SBrooks Davis return (ENOSPC); 256fc74a9f9SBrooks Davis } 25746f3ff79SMike Smith 258*2568cd2aSJustin Hibbits if_setsoftc(ifp, lp); 2599bf40edeSBrooks Davis if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 260*2568cd2aSJustin Hibbits if_setmtu(ifp, LPMTU); 261*2568cd2aSJustin Hibbits if_setflags(ifp, IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST); 262*2568cd2aSJustin Hibbits if_setioctlfn(ifp, lpioctl); 263*2568cd2aSJustin Hibbits if_setoutputfn(ifp, lpoutput); 264*2568cd2aSJustin Hibbits if_setsendqlen(ifp, ifqmaxlen); 26546f3ff79SMike Smith if_attach(ifp); 26646f3ff79SMike Smith 2678f84257eSDag-Erling Smørgrav bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 26846f3ff79SMike Smith 2692067d312SJohn Baldwin /* 2702067d312SJohn Baldwin * Attach our interrupt handler. It is only called while we 2712067d312SJohn Baldwin * own the ppbus. 2722067d312SJohn Baldwin */ 2732067d312SJohn Baldwin error = bus_setup_intr(dev, lp->res_irq, INTR_TYPE_NET | INTR_MPSAFE, 2742067d312SJohn Baldwin NULL, lp_intr, lp, &lp->sc_intr_cookie); 2752067d312SJohn Baldwin if (error) { 2762067d312SJohn Baldwin bpfdetach(ifp); 2772067d312SJohn Baldwin if_detach(ifp); 2782067d312SJohn Baldwin bus_release_resource(dev, SYS_RES_IRQ, 0, lp->res_irq); 2792067d312SJohn Baldwin device_printf(dev, "Unable to register interrupt handler\n"); 2802067d312SJohn Baldwin return (error); 2812067d312SJohn Baldwin } 2822067d312SJohn Baldwin 2830f210c92SNicolas Souchu return (0); 28446f3ff79SMike Smith } 2852067d312SJohn Baldwin 2862067d312SJohn Baldwin static int 2872067d312SJohn Baldwin lp_detach(device_t dev) 2882067d312SJohn Baldwin { 2892067d312SJohn Baldwin struct lp_data *sc = device_get_softc(dev); 2902067d312SJohn Baldwin device_t ppbus = device_get_parent(dev); 2912067d312SJohn Baldwin 2922067d312SJohn Baldwin ppb_lock(ppbus); 2932067d312SJohn Baldwin lpstop(sc); 2942067d312SJohn Baldwin ppb_unlock(ppbus); 2952067d312SJohn Baldwin bpfdetach(sc->sc_ifp); 2962067d312SJohn Baldwin if_detach(sc->sc_ifp); 2972067d312SJohn Baldwin bus_teardown_intr(dev, sc->res_irq, sc->sc_intr_cookie); 2982067d312SJohn Baldwin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res_irq); 2992067d312SJohn Baldwin return (0); 3002067d312SJohn Baldwin } 3012067d312SJohn Baldwin 30246f3ff79SMike Smith /* 30346f3ff79SMike Smith * Build the translation tables for the LPIP (BSD unix) protocol. 30446f3ff79SMike Smith * We don't want to calculate these nasties in our tight loop, so we 30546f3ff79SMike Smith * precalculate them when we initialize. 30646f3ff79SMike Smith */ 30746f3ff79SMike Smith static int 30846f3ff79SMike Smith lpinittables(void) 30946f3ff79SMike Smith { 31046f3ff79SMike Smith int i; 31146f3ff79SMike Smith 3122067d312SJohn Baldwin mtx_lock(&lp_tables_lock); 313c26864e0SJohn Baldwin if (txmith == NULL) 31446f3ff79SMike Smith txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 31546f3ff79SMike Smith 3162067d312SJohn Baldwin if (txmith == NULL) { 3172067d312SJohn Baldwin mtx_unlock(&lp_tables_lock); 318c26864e0SJohn Baldwin return (1); 3192067d312SJohn Baldwin } 32046f3ff79SMike Smith 321c26864e0SJohn Baldwin if (ctxmith == NULL) 32246f3ff79SMike Smith ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 32346f3ff79SMike Smith 3242067d312SJohn Baldwin if (ctxmith == NULL) { 3252067d312SJohn Baldwin mtx_unlock(&lp_tables_lock); 326c26864e0SJohn Baldwin return (1); 3272067d312SJohn Baldwin } 32846f3ff79SMike Smith 32946f3ff79SMike Smith for (i = 0; i < LPIPTBLSIZE; i++) { 33046f3ff79SMike Smith ctxmith[i] = (i & 0xF0) >> 4; 33146f3ff79SMike Smith ctxmitl[i] = 0x10 | (i & 0x0F); 33246f3ff79SMike Smith ctrecvh[i] = (i & 0x78) << 1; 33346f3ff79SMike Smith ctrecvl[i] = (i & 0x78) >> 3; 33446f3ff79SMike Smith } 33546f3ff79SMike Smith 33646f3ff79SMike Smith for (i = 0; i < LPIPTBLSIZE; i++) { 33746f3ff79SMike Smith txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 33846f3ff79SMike Smith txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 33946f3ff79SMike Smith trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 34046f3ff79SMike Smith trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 34146f3ff79SMike Smith } 3422067d312SJohn Baldwin mtx_unlock(&lp_tables_lock); 34346f3ff79SMike Smith 344c26864e0SJohn Baldwin return (0); 34546f3ff79SMike Smith } 34646f3ff79SMike Smith 3472067d312SJohn Baldwin static void 3482067d312SJohn Baldwin lpstop(struct lp_data *sc) 3492067d312SJohn Baldwin { 3502067d312SJohn Baldwin device_t ppbus = device_get_parent(sc->sc_dev); 3512067d312SJohn Baldwin 3522067d312SJohn Baldwin ppb_assert_locked(ppbus); 3532067d312SJohn Baldwin ppb_wctr(ppbus, 0x00); 354*2568cd2aSJustin Hibbits if_setdrvflagbits(sc->sc_ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 3552067d312SJohn Baldwin free(sc->sc_ifbuf, M_DEVBUF); 3562067d312SJohn Baldwin sc->sc_ifbuf = NULL; 3572067d312SJohn Baldwin 3582067d312SJohn Baldwin /* IFF_UP is not set, try to release the bus anyway */ 3592067d312SJohn Baldwin ppb_release_bus(ppbus, sc->sc_dev); 3602067d312SJohn Baldwin } 3612067d312SJohn Baldwin 3622067d312SJohn Baldwin static int 363*2568cd2aSJustin Hibbits lpinit_locked(if_t ifp) 3642067d312SJohn Baldwin { 365*2568cd2aSJustin Hibbits struct lp_data *sc = if_getsoftc(ifp); 3662067d312SJohn Baldwin device_t dev = sc->sc_dev; 3672067d312SJohn Baldwin device_t ppbus = device_get_parent(dev); 3682067d312SJohn Baldwin int error; 3692067d312SJohn Baldwin 3702067d312SJohn Baldwin ppb_assert_locked(ppbus); 3712067d312SJohn Baldwin error = ppb_request_bus(ppbus, dev, PPB_DONTWAIT); 3722067d312SJohn Baldwin if (error) 3732067d312SJohn Baldwin return (error); 3742067d312SJohn Baldwin 3752067d312SJohn Baldwin /* Now IFF_UP means that we own the bus */ 3762067d312SJohn Baldwin ppb_set_mode(ppbus, PPB_COMPATIBLE); 3772067d312SJohn Baldwin 3782067d312SJohn Baldwin if (lpinittables()) { 3792067d312SJohn Baldwin ppb_release_bus(ppbus, dev); 3802067d312SJohn Baldwin return (ENOBUFS); 3812067d312SJohn Baldwin } 3822067d312SJohn Baldwin 383*2568cd2aSJustin Hibbits sc->sc_ifbuf = malloc(if_getmtu(sc->sc_ifp) + MLPIPHDRLEN, 3842067d312SJohn Baldwin M_DEVBUF, M_NOWAIT); 3852067d312SJohn Baldwin if (sc->sc_ifbuf == NULL) { 3862067d312SJohn Baldwin ppb_release_bus(ppbus, dev); 3872067d312SJohn Baldwin return (ENOBUFS); 3882067d312SJohn Baldwin } 3892067d312SJohn Baldwin 3902067d312SJohn Baldwin ppb_wctr(ppbus, IRQENABLE); 3912067d312SJohn Baldwin 392*2568cd2aSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 393*2568cd2aSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 3942067d312SJohn Baldwin return (0); 3952067d312SJohn Baldwin } 3962067d312SJohn Baldwin 39746f3ff79SMike Smith /* 39846f3ff79SMike Smith * Process an ioctl request. 39946f3ff79SMike Smith */ 40046f3ff79SMike Smith static int 401*2568cd2aSJustin Hibbits lpioctl(if_t ifp, u_long cmd, caddr_t data) 40246f3ff79SMike Smith { 403*2568cd2aSJustin Hibbits struct lp_data *sc = if_getsoftc(ifp); 404ae6b868aSJohn Baldwin device_t dev = sc->sc_dev; 4050f210c92SNicolas Souchu device_t ppbus = device_get_parent(dev); 40646f3ff79SMike Smith struct ifaddr *ifa = (struct ifaddr *)data; 40746f3ff79SMike Smith struct ifreq *ifr = (struct ifreq *)data; 40846f3ff79SMike Smith u_char *ptr; 40946f3ff79SMike Smith int error; 41046f3ff79SMike Smith 41146f3ff79SMike Smith switch (cmd) { 41246f3ff79SMike Smith case SIOCAIFADDR: 41346f3ff79SMike Smith case SIOCSIFADDR: 41446f3ff79SMike Smith if (ifa->ifa_addr->sa_family != AF_INET) 415c26864e0SJohn Baldwin return (EAFNOSUPPORT); 41646f3ff79SMike Smith 417*2568cd2aSJustin Hibbits if_setflagbits(ifp, IFF_UP, 0); 41846f3ff79SMike Smith /* FALLTHROUGH */ 41946f3ff79SMike Smith case SIOCSIFFLAGS: 4202067d312SJohn Baldwin error = 0; 4212067d312SJohn Baldwin ppb_lock(ppbus); 422*2568cd2aSJustin Hibbits if ((!(if_getflags(ifp) & IFF_UP)) && 423*2568cd2aSJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING)) 4242067d312SJohn Baldwin lpstop(sc); 425*2568cd2aSJustin Hibbits else if (((if_getflags(ifp) & IFF_UP)) && 426*2568cd2aSJustin Hibbits (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) 4272067d312SJohn Baldwin error = lpinit_locked(ifp); 4282067d312SJohn Baldwin ppb_unlock(ppbus); 42946f3ff79SMike Smith return (error); 43046f3ff79SMike Smith 43146f3ff79SMike Smith case SIOCSIFMTU: 4322067d312SJohn Baldwin ppb_lock(ppbus); 433*2568cd2aSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 4342067d312SJohn Baldwin ptr = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF, 435c26864e0SJohn Baldwin M_NOWAIT); 4362067d312SJohn Baldwin if (ptr == NULL) { 4372067d312SJohn Baldwin ppb_unlock(ppbus); 438c26864e0SJohn Baldwin return (ENOBUFS); 43946f3ff79SMike Smith } 4402067d312SJohn Baldwin if (sc->sc_ifbuf) 4412067d312SJohn Baldwin free(sc->sc_ifbuf, M_DEVBUF); 4422067d312SJohn Baldwin sc->sc_ifbuf = ptr; 4432067d312SJohn Baldwin } 444*2568cd2aSJustin Hibbits if_setmtu(ifp, ifr->ifr_mtu); 4452067d312SJohn Baldwin ppb_unlock(ppbus); 44646f3ff79SMike Smith break; 44746f3ff79SMike Smith 44846f3ff79SMike Smith case SIOCGIFMTU: 449*2568cd2aSJustin Hibbits ifr->ifr_mtu = if_getmtu(sc->sc_ifp); 45046f3ff79SMike Smith break; 45146f3ff79SMike Smith 45246f3ff79SMike Smith case SIOCADDMULTI: 45346f3ff79SMike Smith case SIOCDELMULTI: 4544d24901aSPedro F. Giffuni if (ifr == NULL) { 455c26864e0SJohn Baldwin return (EAFNOSUPPORT); /* XXX */ 45646f3ff79SMike Smith } 45746f3ff79SMike Smith switch (ifr->ifr_addr.sa_family) { 45846f3ff79SMike Smith case AF_INET: 45946f3ff79SMike Smith break; 46046f3ff79SMike Smith default: 461c26864e0SJohn Baldwin return (EAFNOSUPPORT); 46246f3ff79SMike Smith } 46346f3ff79SMike Smith break; 46446f3ff79SMike Smith 46580015f13SMike Smith case SIOCGIFMEDIA: 46680015f13SMike Smith /* 46780015f13SMike Smith * No ifmedia support at this stage; maybe use it 46880015f13SMike Smith * in future for eg. protocol selection. 46980015f13SMike Smith */ 470c26864e0SJohn Baldwin return (EINVAL); 47180015f13SMike Smith 47246f3ff79SMike Smith default: 473162886e2SBruce Evans lprintf("LP:ioctl(0x%lx)\n", cmd); 474c26864e0SJohn Baldwin return (EINVAL); 47546f3ff79SMike Smith } 476c26864e0SJohn Baldwin return (0); 47746f3ff79SMike Smith } 47846f3ff79SMike Smith 47946f3ff79SMike Smith static __inline int 4800f210c92SNicolas Souchu clpoutbyte(u_char byte, int spin, device_t ppbus) 48146f3ff79SMike Smith { 482c26864e0SJohn Baldwin 4830f210c92SNicolas Souchu ppb_wdtr(ppbus, ctxmitl[byte]); 4840f210c92SNicolas Souchu while (ppb_rstr(ppbus) & CLPIP_SHAKE) 48546f3ff79SMike Smith if (--spin == 0) { 486c26864e0SJohn Baldwin return (1); 48746f3ff79SMike Smith } 4880f210c92SNicolas Souchu ppb_wdtr(ppbus, ctxmith[byte]); 4890f210c92SNicolas Souchu while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 49046f3ff79SMike Smith if (--spin == 0) { 491c26864e0SJohn Baldwin return (1); 49246f3ff79SMike Smith } 493c26864e0SJohn Baldwin return (0); 49446f3ff79SMike Smith } 49546f3ff79SMike Smith 49646f3ff79SMike Smith static __inline int 4970f210c92SNicolas Souchu clpinbyte(int spin, device_t ppbus) 49846f3ff79SMike Smith { 49924063475SNicolas Souchu u_char c, cl; 50046f3ff79SMike Smith 5010f210c92SNicolas Souchu while ((ppb_rstr(ppbus) & CLPIP_SHAKE)) 50246f3ff79SMike Smith if (!--spin) { 503c26864e0SJohn Baldwin return (-1); 50446f3ff79SMike Smith } 5050f210c92SNicolas Souchu cl = ppb_rstr(ppbus); 5060f210c92SNicolas Souchu ppb_wdtr(ppbus, 0x10); 50746f3ff79SMike Smith 5080f210c92SNicolas Souchu while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 50946f3ff79SMike Smith if (!--spin) { 510c26864e0SJohn Baldwin return (-1); 51146f3ff79SMike Smith } 5120f210c92SNicolas Souchu c = ppb_rstr(ppbus); 5130f210c92SNicolas Souchu ppb_wdtr(ppbus, 0x00); 51446f3ff79SMike Smith 51546f3ff79SMike Smith return (ctrecvl[cl] | ctrecvh[c]); 51646f3ff79SMike Smith } 51746f3ff79SMike Smith 5188f84257eSDag-Erling Smørgrav static void 519*2568cd2aSJustin Hibbits lptap(if_t ifp, struct mbuf *m) 5208f84257eSDag-Erling Smørgrav { 5218f84257eSDag-Erling Smørgrav u_int32_t af = AF_INET; 522c26864e0SJohn Baldwin 523*2568cd2aSJustin Hibbits bpf_mtap2_if(ifp, &af, sizeof(af), m); 5248f84257eSDag-Erling Smørgrav } 5258f84257eSDag-Erling Smørgrav 52646f3ff79SMike Smith static void 5270f210c92SNicolas Souchu lp_intr(void *arg) 52846f3ff79SMike Smith { 5292067d312SJohn Baldwin struct lp_data *sc = arg; 5302067d312SJohn Baldwin device_t ppbus = device_get_parent(sc->sc_dev); 5312067d312SJohn Baldwin int len, j; 53246f3ff79SMike Smith u_char *bp; 53346f3ff79SMike Smith u_char c, cl; 53446f3ff79SMike Smith struct mbuf *top; 53546f3ff79SMike Smith 5362067d312SJohn Baldwin ppb_assert_locked(ppbus); 537*2568cd2aSJustin Hibbits if (if_getflags(sc->sc_ifp) & IFF_LINK0) { 53846f3ff79SMike Smith /* Ack. the request */ 5390f210c92SNicolas Souchu ppb_wdtr(ppbus, 0x01); 54046f3ff79SMike Smith 54146f3ff79SMike Smith /* Get the packet length */ 5420f210c92SNicolas Souchu j = clpinbyte(LPMAXSPIN2, ppbus); 54346f3ff79SMike Smith if (j == -1) 54446f3ff79SMike Smith goto err; 54546f3ff79SMike Smith len = j; 5460f210c92SNicolas Souchu j = clpinbyte(LPMAXSPIN2, ppbus); 54746f3ff79SMike Smith if (j == -1) 54846f3ff79SMike Smith goto err; 54946f3ff79SMike Smith len = len + (j << 8); 550*2568cd2aSJustin Hibbits if (len > if_getmtu(sc->sc_ifp) + MLPIPHDRLEN) 55146f3ff79SMike Smith goto err; 55246f3ff79SMike Smith 55346f3ff79SMike Smith bp = sc->sc_ifbuf; 55446f3ff79SMike Smith 55546f3ff79SMike Smith while (len--) { 5560f210c92SNicolas Souchu j = clpinbyte(LPMAXSPIN2, ppbus); 55746f3ff79SMike Smith if (j == -1) { 55846f3ff79SMike Smith goto err; 55946f3ff79SMike Smith } 56046f3ff79SMike Smith *bp++ = j; 56146f3ff79SMike Smith } 562c26864e0SJohn Baldwin 56346f3ff79SMike Smith /* Get and ignore checksum */ 5640f210c92SNicolas Souchu j = clpinbyte(LPMAXSPIN2, ppbus); 56546f3ff79SMike Smith if (j == -1) { 56646f3ff79SMike Smith goto err; 56746f3ff79SMike Smith } 56846f3ff79SMike Smith 56946f3ff79SMike Smith len = bp - sc->sc_ifbuf; 57046f3ff79SMike Smith if (len <= CLPIPHDRLEN) 57146f3ff79SMike Smith goto err; 57246f3ff79SMike Smith 57346f3ff79SMike Smith sc->sc_iferrs = 0; 57446f3ff79SMike Smith 57546f3ff79SMike Smith len -= CLPIPHDRLEN; 576c8dfaf38SGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); 577c8dfaf38SGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len); 578c26864e0SJohn Baldwin top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp, 579c26864e0SJohn Baldwin 0); 58046f3ff79SMike Smith if (top) { 5812067d312SJohn Baldwin ppb_unlock(ppbus); 582fc74a9f9SBrooks Davis lptap(sc->sc_ifp, top); 583c26864e0SJohn Baldwin 584*2568cd2aSJustin Hibbits M_SETFIB(top, if_getfib(sc->sc_ifp)); 585a34c6aebSBjoern A. Zeeb 586c26864e0SJohn Baldwin /* mbuf is free'd on failure. */ 587c26864e0SJohn Baldwin netisr_queue(NETISR_IP, top); 5882067d312SJohn Baldwin ppb_lock(ppbus); 589df5e1987SJonathan Lemon } 5902067d312SJohn Baldwin return; 59146f3ff79SMike Smith } 5920f210c92SNicolas Souchu while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { 593*2568cd2aSJustin Hibbits len = if_getmtu(sc->sc_ifp) + LPIPHDRLEN; 59446f3ff79SMike Smith bp = sc->sc_ifbuf; 59546f3ff79SMike Smith while (len--) { 5960f210c92SNicolas Souchu cl = ppb_rstr(ppbus); 5970f210c92SNicolas Souchu ppb_wdtr(ppbus, 8); 59846f3ff79SMike Smith 59946f3ff79SMike Smith j = LPMAXSPIN2; 6000f210c92SNicolas Souchu while ((ppb_rstr(ppbus) & LPIP_SHAKE)) 601c26864e0SJohn Baldwin if (!--j) 602c26864e0SJohn Baldwin goto err; 60346f3ff79SMike Smith 6040f210c92SNicolas Souchu c = ppb_rstr(ppbus); 6050f210c92SNicolas Souchu ppb_wdtr(ppbus, 0); 60646f3ff79SMike Smith 60746f3ff79SMike Smith *bp++= trecvh[cl] | trecvl[c]; 60846f3ff79SMike Smith 60946f3ff79SMike Smith j = LPMAXSPIN2; 6100f210c92SNicolas Souchu while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) { 61146f3ff79SMike Smith if (cl != c && 6120f210c92SNicolas Souchu (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) == 61346f3ff79SMike Smith (c & 0xf8)) 61446f3ff79SMike Smith goto end; 615c26864e0SJohn Baldwin if (!--j) 616c26864e0SJohn Baldwin goto err; 61746f3ff79SMike Smith } 61846f3ff79SMike Smith } 61946f3ff79SMike Smith 62046f3ff79SMike Smith end: 62146f3ff79SMike Smith len = bp - sc->sc_ifbuf; 62246f3ff79SMike Smith if (len <= LPIPHDRLEN) 62346f3ff79SMike Smith goto err; 62446f3ff79SMike Smith 62546f3ff79SMike Smith sc->sc_iferrs = 0; 62646f3ff79SMike Smith 62746f3ff79SMike Smith len -= LPIPHDRLEN; 628c8dfaf38SGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); 629c8dfaf38SGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len); 630c26864e0SJohn Baldwin top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp, 631c26864e0SJohn Baldwin 0); 63246f3ff79SMike Smith if (top) { 6332067d312SJohn Baldwin ppb_unlock(ppbus); 634fc74a9f9SBrooks Davis lptap(sc->sc_ifp, top); 635c26864e0SJohn Baldwin 636*2568cd2aSJustin Hibbits M_SETFIB(top, if_getfib(sc->sc_ifp)); 637a34c6aebSBjoern A. Zeeb 638c26864e0SJohn Baldwin /* mbuf is free'd on failure. */ 639c26864e0SJohn Baldwin netisr_queue(NETISR_IP, top); 6402067d312SJohn Baldwin ppb_lock(ppbus); 64146f3ff79SMike Smith } 642df5e1987SJonathan Lemon } 6432067d312SJohn Baldwin return; 64446f3ff79SMike Smith 64546f3ff79SMike Smith err: 6460f210c92SNicolas Souchu ppb_wdtr(ppbus, 0); 64746f3ff79SMike Smith lprintf("R"); 648c8dfaf38SGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); 64946f3ff79SMike Smith sc->sc_iferrs++; 65046f3ff79SMike Smith 65146f3ff79SMike Smith /* 65246f3ff79SMike Smith * We are not able to send receive anything for now, 65346f3ff79SMike Smith * so stop wasting our time 65446f3ff79SMike Smith */ 65546f3ff79SMike Smith if (sc->sc_iferrs > LPMAXERRS) { 656ae6b868aSJohn Baldwin if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n"); 6570f210c92SNicolas Souchu ppb_wctr(ppbus, 0x00); 658*2568cd2aSJustin Hibbits if_setdrvflagbits(sc->sc_ifp, 0, IFF_DRV_RUNNING); 65946f3ff79SMike Smith sc->sc_iferrs = 0; 66046f3ff79SMike Smith } 66146f3ff79SMike Smith } 66246f3ff79SMike Smith 66346f3ff79SMike Smith static __inline int 6640f210c92SNicolas Souchu lpoutbyte(u_char byte, int spin, device_t ppbus) 66546f3ff79SMike Smith { 666c26864e0SJohn Baldwin 6670f210c92SNicolas Souchu ppb_wdtr(ppbus, txmith[byte]); 6680f210c92SNicolas Souchu while (!(ppb_rstr(ppbus) & LPIP_SHAKE)) 66946f3ff79SMike Smith if (--spin == 0) 670c26864e0SJohn Baldwin return (1); 6710f210c92SNicolas Souchu ppb_wdtr(ppbus, txmitl[byte]); 6720f210c92SNicolas Souchu while (ppb_rstr(ppbus) & LPIP_SHAKE) 67346f3ff79SMike Smith if (--spin == 0) 674c26864e0SJohn Baldwin return (1); 675c26864e0SJohn Baldwin return (0); 67646f3ff79SMike Smith } 67746f3ff79SMike Smith 67846f3ff79SMike Smith static int 679*2568cd2aSJustin Hibbits lpoutput(if_t ifp, struct mbuf *m, const struct sockaddr *dst, 680279aa3d4SKip Macy struct route *ro) 68146f3ff79SMike Smith { 682*2568cd2aSJustin Hibbits struct lp_data *sc = if_getsoftc(ifp); 683ae6b868aSJohn Baldwin device_t dev = sc->sc_dev; 6840f210c92SNicolas Souchu device_t ppbus = device_get_parent(dev); 6852067d312SJohn Baldwin int err; 68646f3ff79SMike Smith struct mbuf *mm; 68746f3ff79SMike Smith u_char *cp = "\0\0"; 68846f3ff79SMike Smith u_char chksum = 0; 68946f3ff79SMike Smith int count = 0; 6908f84257eSDag-Erling Smørgrav int i, len, spin; 69146f3ff79SMike Smith 69246f3ff79SMike Smith /* We need a sensible value if we abort */ 69346f3ff79SMike Smith cp++; 6942067d312SJohn Baldwin ppb_lock(ppbus); 695*2568cd2aSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 69646f3ff79SMike Smith 69746f3ff79SMike Smith err = 1; /* assume we're aborting because of an error */ 69846f3ff79SMike Smith 69946f3ff79SMike Smith /* Suspend (on laptops) or receive-errors might have taken us offline */ 7000f210c92SNicolas Souchu ppb_wctr(ppbus, IRQENABLE); 70146f3ff79SMike Smith 702*2568cd2aSJustin Hibbits if (if_getflags(ifp) & IFF_LINK0) { 7030f210c92SNicolas Souchu if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 70446f3ff79SMike Smith lprintf("&"); 7052067d312SJohn Baldwin lp_intr(sc); 70646f3ff79SMike Smith } 70746f3ff79SMike Smith 70846f3ff79SMike Smith /* Alert other end to pending packet */ 70946f3ff79SMike Smith spin = LPMAXSPIN1; 7100f210c92SNicolas Souchu ppb_wdtr(ppbus, 0x08); 7110f210c92SNicolas Souchu while ((ppb_rstr(ppbus) & 0x08) == 0) 71246f3ff79SMike Smith if (--spin == 0) { 71346f3ff79SMike Smith goto nend; 71446f3ff79SMike Smith } 71546f3ff79SMike Smith 71646f3ff79SMike Smith /* Calculate length of packet, then send that */ 71746f3ff79SMike Smith 71846f3ff79SMike Smith count += 14; /* Ethernet header len */ 71946f3ff79SMike Smith 72046f3ff79SMike Smith mm = m; 72146f3ff79SMike Smith for (mm = m; mm; mm = mm->m_next) { 72246f3ff79SMike Smith count += mm->m_len; 72346f3ff79SMike Smith } 7240f210c92SNicolas Souchu if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 72546f3ff79SMike Smith goto nend; 7260f210c92SNicolas Souchu if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 72746f3ff79SMike Smith goto nend; 72846f3ff79SMike Smith 72946f3ff79SMike Smith /* Send dummy ethernet header */ 73046f3ff79SMike Smith for (i = 0; i < 12; i++) { 7310f210c92SNicolas Souchu if (clpoutbyte(i, LPMAXSPIN1, ppbus)) 73246f3ff79SMike Smith goto nend; 73346f3ff79SMike Smith chksum += i; 73446f3ff79SMike Smith } 73546f3ff79SMike Smith 7360f210c92SNicolas Souchu if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 73746f3ff79SMike Smith goto nend; 7380f210c92SNicolas Souchu if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 73946f3ff79SMike Smith goto nend; 74046f3ff79SMike Smith chksum += 0x08 + 0x00; /* Add into checksum */ 74146f3ff79SMike Smith 74246f3ff79SMike Smith mm = m; 74346f3ff79SMike Smith do { 74446f3ff79SMike Smith cp = mtod(mm, u_char *); 7458f84257eSDag-Erling Smørgrav len = mm->m_len; 7468f84257eSDag-Erling Smørgrav while (len--) { 74746f3ff79SMike Smith chksum += *cp; 7480f210c92SNicolas Souchu if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 74946f3ff79SMike Smith goto nend; 75046f3ff79SMike Smith } 75146f3ff79SMike Smith } while ((mm = mm->m_next)); 75246f3ff79SMike Smith 75346f3ff79SMike Smith /* Send checksum */ 7540f210c92SNicolas Souchu if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 75546f3ff79SMike Smith goto nend; 75646f3ff79SMike Smith 75746f3ff79SMike Smith /* Go quiescent */ 7580f210c92SNicolas Souchu ppb_wdtr(ppbus, 0); 75946f3ff79SMike Smith 76046f3ff79SMike Smith err = 0; /* No errors */ 76146f3ff79SMike Smith 76246f3ff79SMike Smith nend: 763*2568cd2aSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 76446f3ff79SMike Smith if (err) { /* if we didn't timeout... */ 765c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 76646f3ff79SMike Smith lprintf("X"); 76746f3ff79SMike Smith } else { 768c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 769c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 7708f84257eSDag-Erling Smørgrav lptap(ifp, m); 77146f3ff79SMike Smith } 77246f3ff79SMike Smith 77346f3ff79SMike Smith m_freem(m); 77446f3ff79SMike Smith 7750f210c92SNicolas Souchu if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 77646f3ff79SMike Smith lprintf("^"); 7772067d312SJohn Baldwin lp_intr(sc); 77846f3ff79SMike Smith } 7792067d312SJohn Baldwin ppb_unlock(ppbus); 780c26864e0SJohn Baldwin return (0); 78146f3ff79SMike Smith } 78246f3ff79SMike Smith 7830f210c92SNicolas Souchu if (ppb_rstr(ppbus) & LPIP_SHAKE) { 78446f3ff79SMike Smith lprintf("&"); 7852067d312SJohn Baldwin lp_intr(sc); 78646f3ff79SMike Smith } 78746f3ff79SMike Smith 7880f210c92SNicolas Souchu if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 78946f3ff79SMike Smith goto end; 7900f210c92SNicolas Souchu if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 79146f3ff79SMike Smith goto end; 79246f3ff79SMike Smith 79346f3ff79SMike Smith mm = m; 79446f3ff79SMike Smith do { 79546f3ff79SMike Smith cp = mtod(mm, u_char *); 7968f84257eSDag-Erling Smørgrav len = mm->m_len; 7978f84257eSDag-Erling Smørgrav while (len--) 7980f210c92SNicolas Souchu if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 79946f3ff79SMike Smith goto end; 80046f3ff79SMike Smith } while ((mm = mm->m_next)); 80146f3ff79SMike Smith 80246f3ff79SMike Smith err = 0; /* no errors were encountered */ 80346f3ff79SMike Smith 80446f3ff79SMike Smith end: 80546f3ff79SMike Smith --cp; 8060f210c92SNicolas Souchu ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); 80746f3ff79SMike Smith 808*2568cd2aSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 80946f3ff79SMike Smith if (err) { /* if we didn't timeout... */ 810c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 81146f3ff79SMike Smith lprintf("X"); 81246f3ff79SMike Smith } else { 813c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 814c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 8158f84257eSDag-Erling Smørgrav lptap(ifp, m); 81646f3ff79SMike Smith } 81746f3ff79SMike Smith 81846f3ff79SMike Smith m_freem(m); 81946f3ff79SMike Smith 8200f210c92SNicolas Souchu if (ppb_rstr(ppbus) & LPIP_SHAKE) { 82146f3ff79SMike Smith lprintf("^"); 8222067d312SJohn Baldwin lp_intr(sc); 82346f3ff79SMike Smith } 82446f3ff79SMike Smith 8252067d312SJohn Baldwin ppb_unlock(ppbus); 826c26864e0SJohn Baldwin return (0); 82746f3ff79SMike Smith } 8280f210c92SNicolas Souchu 8290f063508SPeter Wemm static device_method_t lp_methods[] = { 8300f063508SPeter Wemm /* device interface */ 8310f063508SPeter Wemm DEVMETHOD(device_identify, lp_identify), 8320f063508SPeter Wemm DEVMETHOD(device_probe, lp_probe), 8330f063508SPeter Wemm DEVMETHOD(device_attach, lp_attach), 8342067d312SJohn Baldwin DEVMETHOD(device_detach, lp_detach), 8350f063508SPeter Wemm { 0, 0 } 8360f063508SPeter Wemm }; 8370f063508SPeter Wemm 8380f063508SPeter Wemm static driver_t lp_driver = { 8390f063508SPeter Wemm "plip", 8400f063508SPeter Wemm lp_methods, 8410f063508SPeter Wemm sizeof(struct lp_data), 8420f063508SPeter Wemm }; 8430f063508SPeter Wemm 8446d588090SJohn Baldwin DRIVER_MODULE(plip, ppbus, lp_driver, lp_module_handler, NULL); 845f5fd5611SRuslan Ermilov MODULE_DEPEND(plip, ppbus, 1, 1, 1); 846