1 1.38 rjs /* $NetBSD: if_plip.c,v 1.38 2022/09/04 15:59:08 rjs Exp $ */ 2 1.3 bjh21 3 1.1 jdolecek /*- 4 1.1 jdolecek * Copyright (c) 1997 Poul-Henning Kamp 5 1.5 jdolecek * Copyright (c) 2003, 2004 Gary Thorpe <gathorpe (at) users.sourceforge.net> 6 1.1 jdolecek * All rights reserved. 7 1.1 jdolecek * 8 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 9 1.1 jdolecek * modification, are permitted provided that the following conditions 10 1.1 jdolecek * are met: 11 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 12 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 13 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 15 1.1 jdolecek * documentation and/or other materials provided with the distribution. 16 1.1 jdolecek * 17 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.1 jdolecek * SUCH DAMAGE. 28 1.1 jdolecek * 29 1.1 jdolecek * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 30 1.4 bjh21 * FreeBSD: src/sys/dev/ppbus/if_plip.c,v 1.19.2.1 2000/05/24 00:20:57 n_hibma Exp 31 1.1 jdolecek */ 32 1.1 jdolecek 33 1.4 bjh21 #include <sys/cdefs.h> 34 1.38 rjs __KERNEL_RCSID(0, "$NetBSD: if_plip.c,v 1.38 2022/09/04 15:59:08 rjs Exp $"); 35 1.4 bjh21 36 1.1 jdolecek /* 37 1.1 jdolecek * Parallel port TCP/IP interfaces added. I looked at the driver from 38 1.1 jdolecek * MACH but this is a complete rewrite, and btw. incompatible, and it 39 1.1 jdolecek * should perform better too. I have never run the MACH driver though. 40 1.1 jdolecek * 41 1.1 jdolecek * This driver sends two bytes (0x08, 0x00) in front of each packet, 42 1.1 jdolecek * to allow us to distinguish another format later. 43 1.1 jdolecek * 44 1.29 msaitoh * Now added a Linux/Crynwr compatibility mode which is enabled using 45 1.1 jdolecek * IF_LINK0 - Tim Wilkinson. 46 1.1 jdolecek * 47 1.1 jdolecek * TODO: 48 1.1 jdolecek * Make HDLC/PPP mode, use IF_LLC1 to enable. 49 1.1 jdolecek * 50 1.1 jdolecek * Connect the two computers using a Laplink parallel cable to use this 51 1.1 jdolecek * feature: 52 1.1 jdolecek * 53 1.1 jdolecek * +----------------------------------------+ 54 1.1 jdolecek * |A-name A-End B-End Descr. Port/Bit | 55 1.1 jdolecek * +----------------------------------------+ 56 1.1 jdolecek * |DATA0 2 15 Data 0/0x01 | 57 1.1 jdolecek * |-ERROR 15 2 1/0x08 | 58 1.1 jdolecek * +----------------------------------------+ 59 1.1 jdolecek * |DATA1 3 13 Data 0/0x02 | 60 1.1 jdolecek * |+SLCT 13 3 1/0x10 | 61 1.1 jdolecek * +----------------------------------------+ 62 1.1 jdolecek * |DATA2 4 12 Data 0/0x04 | 63 1.1 jdolecek * |+PE 12 4 1/0x20 | 64 1.1 jdolecek * +----------------------------------------+ 65 1.1 jdolecek * |DATA3 5 10 Strobe 0/0x08 | 66 1.1 jdolecek * |-ACK 10 5 1/0x40 | 67 1.1 jdolecek * +----------------------------------------+ 68 1.1 jdolecek * |DATA4 6 11 Data 0/0x10 | 69 1.1 jdolecek * |BUSY 11 6 1/~0x80 | 70 1.1 jdolecek * +----------------------------------------+ 71 1.1 jdolecek * |GND 18-25 18-25 GND - | 72 1.1 jdolecek * +----------------------------------------+ 73 1.1 jdolecek * 74 1.1 jdolecek * Expect transfer-rates up to 75 kbyte/sec. 75 1.1 jdolecek * 76 1.1 jdolecek * If GCC could correctly grok 77 1.9 perry * register int port __asm("edx") 78 1.1 jdolecek * the code would be cleaner 79 1.1 jdolecek * 80 1.1 jdolecek * Poul-Henning Kamp <phk (at) freebsd.org> 81 1.1 jdolecek */ 82 1.1 jdolecek 83 1.1 jdolecek /* 84 1.1 jdolecek * Update for ppbus, PLIP support only - Nicolas Souchu 85 1.6 perry */ 86 1.1 jdolecek 87 1.1 jdolecek #include "opt_inet.h" 88 1.1 jdolecek #include "opt_plip.h" 89 1.1 jdolecek 90 1.1 jdolecek #include <sys/systm.h> 91 1.1 jdolecek #include <sys/param.h> 92 1.1 jdolecek #include <sys/proc.h> 93 1.1 jdolecek #include <sys/types.h> 94 1.1 jdolecek #include <sys/device.h> 95 1.1 jdolecek #include <sys/ioctl.h> 96 1.1 jdolecek #include <sys/malloc.h> 97 1.1 jdolecek #include <sys/mbuf.h> 98 1.1 jdolecek 99 1.1 jdolecek #include <net/if.h> 100 1.1 jdolecek #include <net/if_types.h> 101 1.1 jdolecek 102 1.1 jdolecek #include <sys/time.h> 103 1.1 jdolecek #include <net/bpf.h> 104 1.1 jdolecek 105 1.1 jdolecek #ifdef INET 106 1.38 rjs #include <netinet/in.h> 107 1.38 rjs #include <netinet/in_systm.h> 108 1.1 jdolecek #include <netinet/in_var.h> 109 1.38 rjs #include <netinet/ip.h> 110 1.1 jdolecek #else 111 1.1 jdolecek #error Cannot config lp/plip without inet 112 1.1 jdolecek #endif 113 1.1 jdolecek 114 1.1 jdolecek #include <dev/ppbus/ppbus_base.h> 115 1.1 jdolecek #include <dev/ppbus/ppbus_device.h> 116 1.1 jdolecek #include <dev/ppbus/ppbus_io.h> 117 1.1 jdolecek #include <dev/ppbus/ppbus_var.h> 118 1.1 jdolecek 119 1.1 jdolecek #include <machine/types.h> 120 1.15 ad #include <sys/intr.h> 121 1.1 jdolecek 122 1.1 jdolecek #ifndef LPMTU /* MTU for the lp# interfaces */ 123 1.1 jdolecek #define LPMTU 1500 124 1.1 jdolecek #endif 125 1.1 jdolecek 126 1.1 jdolecek #ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 127 1.1 jdolecek #define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 128 1.1 jdolecek #endif 129 1.1 jdolecek 130 1.1 jdolecek #ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 131 1.1 jdolecek #define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 132 1.1 jdolecek #endif 133 1.1 jdolecek 134 1.1 jdolecek #ifndef LPMAXERRS /* Max errors before !RUNNING */ 135 1.1 jdolecek #define LPMAXERRS 100 136 1.1 jdolecek #endif 137 1.1 jdolecek 138 1.1 jdolecek #ifndef LPMAXRTRY 139 1.6 perry #define LPMAXRTRY 100 /* If channel busy, retry LPMAXRTRY 140 1.1 jdolecek consecutive times */ 141 1.1 jdolecek #endif 142 1.1 jdolecek 143 1.1 jdolecek #define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 144 1.1 jdolecek #define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 145 1.1 jdolecek #define MLPIPHDRLEN CLPIPHDRLEN 146 1.1 jdolecek 147 1.1 jdolecek #define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 148 1.1 jdolecek #define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 149 1.1 jdolecek #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 150 1.1 jdolecek #define MLPIPHDRLEN LPIPHDRLEN 151 1.1 jdolecek #endif 152 1.1 jdolecek 153 1.1 jdolecek #define LPIPTBLSIZE 256 /* Size of octet translation table */ 154 1.1 jdolecek 155 1.1 jdolecek #define LP_PRINTF if (lpflag) printf 156 1.1 jdolecek 157 1.1 jdolecek #ifdef PLIP_DEBUG 158 1.1 jdolecek static int volatile lpflag = 1; 159 1.1 jdolecek #else 160 1.1 jdolecek static int volatile lpflag = 0; 161 1.1 jdolecek #endif 162 1.1 jdolecek 163 1.1 jdolecek /* Tx/Rsv tables for the lp interface */ 164 1.1 jdolecek static u_char *txmith; 165 1.1 jdolecek #define txmitl (txmith+(1*LPIPTBLSIZE)) 166 1.1 jdolecek #define trecvh (txmith+(2*LPIPTBLSIZE)) 167 1.1 jdolecek #define trecvl (txmith+(3*LPIPTBLSIZE)) 168 1.1 jdolecek static u_char *ctxmith; 169 1.1 jdolecek #define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 170 1.1 jdolecek #define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 171 1.1 jdolecek #define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 172 1.1 jdolecek static uint16_t lp_count = 0; 173 1.1 jdolecek 174 1.1 jdolecek /* Autoconf functions */ 175 1.18 cegger static int lp_probe(device_t, cfdata_t, void *); 176 1.18 cegger static void lp_attach(device_t, device_t, void *); 177 1.18 cegger static int lp_detach(device_t, int); 178 1.1 jdolecek 179 1.1 jdolecek /* Soft config data */ 180 1.1 jdolecek struct lp_softc { 181 1.1 jdolecek struct ppbus_device_softc ppbus_dev; 182 1.1 jdolecek struct ifnet sc_if; 183 1.1 jdolecek u_char *sc_ifbuf; 184 1.1 jdolecek unsigned short sc_iferrs; 185 1.1 jdolecek unsigned short sc_xmit_rtry; 186 1.1 jdolecek u_int8_t sc_dev_ok; /* Zero means ok */ 187 1.1 jdolecek }; 188 1.1 jdolecek 189 1.1 jdolecek /* Autoconf structure */ 190 1.18 cegger CFATTACH_DECL_NEW(plip, sizeof(struct lp_softc), lp_probe, lp_attach, lp_detach, 191 1.1 jdolecek NULL); 192 1.1 jdolecek 193 1.1 jdolecek /* Functions for the lp interface */ 194 1.1 jdolecek static void lpinittables(void); 195 1.1 jdolecek static void lpfreetables(void); 196 1.12 christos static int lpioctl(struct ifnet *, u_long, void *); 197 1.13 drochner static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 198 1.29 msaitoh const struct rtentry *); 199 1.1 jdolecek static void lpstart(struct ifnet *); 200 1.1 jdolecek static void lp_intr(void *); 201 1.1 jdolecek 202 1.1 jdolecek 203 1.1 jdolecek static int 204 1.18 cegger lp_probe(device_t parent, cfdata_t match, void *aux) 205 1.1 jdolecek { 206 1.1 jdolecek struct ppbus_attach_args * args = aux; 207 1.6 perry 208 1.6 perry /* Fail if ppbus is not interrupt capable */ 209 1.29 msaitoh if (args->capabilities & PPBUS_HAS_INTR) 210 1.1 jdolecek return 1; 211 1.1 jdolecek 212 1.6 perry printf("%s(%s): not an interrupt-driven port.\n", __func__, 213 1.17 cegger device_xname(parent)); 214 1.1 jdolecek return 0; 215 1.1 jdolecek } 216 1.1 jdolecek 217 1.6 perry static void 218 1.18 cegger lp_attach(device_t parent, device_t self, void *aux) 219 1.1 jdolecek { 220 1.11 thorpej struct lp_softc * lp = device_private(self); 221 1.1 jdolecek struct ifnet * ifp = &lp->sc_if; 222 1.1 jdolecek 223 1.20 cegger lp->ppbus_dev.sc_dev = self; 224 1.1 jdolecek lp->sc_dev_ok = 0; 225 1.1 jdolecek lp->sc_ifbuf = NULL; 226 1.1 jdolecek lp->sc_iferrs = 0; 227 1.1 jdolecek lp->sc_xmit_rtry = 0; 228 1.1 jdolecek 229 1.11 thorpej ifp->if_softc = lp; 230 1.17 cegger strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); 231 1.1 jdolecek ifp->if_mtu = LPMTU; 232 1.1 jdolecek ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 233 1.1 jdolecek ifp->if_ioctl = lpioctl; 234 1.1 jdolecek ifp->if_output = lpoutput; 235 1.1 jdolecek ifp->if_start = lpstart; 236 1.1 jdolecek ifp->if_type = IFT_PARA; 237 1.1 jdolecek ifp->if_hdrlen = 0; 238 1.1 jdolecek ifp->if_addrlen = 0; 239 1.1 jdolecek ifp->if_dlt = DLT_NULL; 240 1.1 jdolecek IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 241 1.1 jdolecek IFQ_SET_READY(&ifp->if_snd); 242 1.1 jdolecek if_attach(ifp); 243 1.1 jdolecek if_alloc_sadl(ifp); 244 1.1 jdolecek 245 1.24 joerg bpf_attach(ifp, DLT_NULL, sizeof(u_int32_t)); 246 1.1 jdolecek 247 1.29 msaitoh if (lp_count++ == 0) 248 1.1 jdolecek lpinittables(); 249 1.1 jdolecek printf("\n"); 250 1.1 jdolecek } 251 1.1 jdolecek 252 1.1 jdolecek static int 253 1.18 cegger lp_detach(device_t self, int flags) 254 1.1 jdolecek { 255 1.1 jdolecek int error = 0; 256 1.11 thorpej struct lp_softc * lp = device_private(self); 257 1.18 cegger device_t ppbus = device_parent(self); 258 1.6 perry 259 1.29 msaitoh if (lp->sc_dev_ok) { 260 1.29 msaitoh if (!(flags & DETACH_QUIET)) 261 1.1 jdolecek LP_PRINTF("%s(%s): device not properly attached! " 262 1.6 perry "Skipping detach....\n", __func__, 263 1.17 cegger device_xname(self)); 264 1.1 jdolecek return error; 265 1.1 jdolecek } 266 1.1 jdolecek 267 1.1 jdolecek /* If interface is up, bring it down and release ppbus */ 268 1.29 msaitoh if (lp->sc_if.if_flags & IFF_RUNNING) { 269 1.1 jdolecek ppbus_wctr(ppbus, 0x00); 270 1.1 jdolecek if_detach(&lp->sc_if); 271 1.1 jdolecek error = ppbus_remove_handler(ppbus, lp_intr); 272 1.29 msaitoh if (error) { 273 1.29 msaitoh if (!(flags & DETACH_QUIET)) 274 1.1 jdolecek LP_PRINTF("%s(%s): unable to remove interrupt " 275 1.6 perry "callback.\n", __func__, 276 1.17 cegger device_xname(self)); 277 1.29 msaitoh if (!(flags & DETACH_FORCE)) 278 1.1 jdolecek return error; 279 1.1 jdolecek } 280 1.1 jdolecek error = ppbus_release_bus(ppbus, self, 0, 0); 281 1.29 msaitoh if (error) { 282 1.29 msaitoh if (!(flags & DETACH_QUIET)) 283 1.6 perry LP_PRINTF("%s(%s): error releasing bus %s.\n", 284 1.17 cegger __func__, device_xname(self), 285 1.17 cegger device_xname(ppbus)); 286 1.29 msaitoh if (!(flags & DETACH_FORCE)) 287 1.1 jdolecek return error; 288 1.1 jdolecek } 289 1.1 jdolecek } 290 1.1 jdolecek 291 1.29 msaitoh if (lp->sc_ifbuf) 292 1.1 jdolecek free(lp->sc_ifbuf, M_DEVBUF); 293 1.1 jdolecek 294 1.29 msaitoh if (--lp_count == 0) 295 1.1 jdolecek lpfreetables(); 296 1.1 jdolecek return error; 297 1.1 jdolecek } 298 1.1 jdolecek 299 1.1 jdolecek /* 300 1.1 jdolecek * Build the translation tables for the LPIP (BSD unix) protocol. 301 1.1 jdolecek * We don't want to calculate these nasties in our tight loop, so we 302 1.1 jdolecek * precalculate them when we initialize. 303 1.1 jdolecek */ 304 1.6 perry static void 305 1.29 msaitoh lpinittables(void) 306 1.1 jdolecek { 307 1.1 jdolecek int i; 308 1.1 jdolecek 309 1.1 jdolecek if (!txmith) 310 1.1 jdolecek txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK); 311 1.1 jdolecek 312 1.1 jdolecek if (!ctxmith) 313 1.1 jdolecek ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK); 314 1.1 jdolecek 315 1.29 msaitoh for (i = 0; i < LPIPTBLSIZE; i++) { 316 1.1 jdolecek ctxmith[i] = (i & 0xF0) >> 4; 317 1.1 jdolecek ctxmitl[i] = 0x10 | (i & 0x0F); 318 1.1 jdolecek ctrecvh[i] = (i & 0x78) << 1; 319 1.1 jdolecek ctrecvl[i] = (i & 0x78) >> 3; 320 1.1 jdolecek } 321 1.1 jdolecek 322 1.29 msaitoh for (i = 0; i < LPIPTBLSIZE; i++) { 323 1.1 jdolecek txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 324 1.1 jdolecek txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 325 1.1 jdolecek trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 326 1.1 jdolecek trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 327 1.1 jdolecek } 328 1.1 jdolecek } 329 1.1 jdolecek 330 1.1 jdolecek /* Free translation tables */ 331 1.6 perry static void 332 1.29 msaitoh lpfreetables(void) 333 1.1 jdolecek { 334 1.1 jdolecek if (txmith) 335 1.1 jdolecek free(txmith, M_DEVBUF); 336 1.1 jdolecek if (ctxmith) 337 1.1 jdolecek free(ctxmith, M_DEVBUF); 338 1.1 jdolecek txmith = ctxmith = NULL; 339 1.1 jdolecek } 340 1.1 jdolecek 341 1.6 perry 342 1.1 jdolecek /* Process an ioctl request. */ 343 1.1 jdolecek static int 344 1.22 dyoung lpioctl(struct ifnet *ifp, u_long cmd, void *data) 345 1.1 jdolecek { 346 1.21 cegger struct lp_softc * sc = ifp->if_softc; 347 1.21 cegger device_t dev = sc->ppbus_dev.sc_dev; 348 1.18 cegger device_t ppbus = device_parent(dev); 349 1.1 jdolecek struct ifaddr * ifa = (struct ifaddr *)data; 350 1.1 jdolecek struct ifreq * ifr = (struct ifreq *)data; 351 1.1 jdolecek u_char * ptr; 352 1.1 jdolecek int error, s; 353 1.1 jdolecek 354 1.1 jdolecek error = 0; 355 1.1 jdolecek s = splnet(); 356 1.1 jdolecek 357 1.29 msaitoh if (sc->sc_dev_ok) { 358 1.6 perry LP_PRINTF("%s(%s): device not properly attached!", __func__, 359 1.17 cegger device_xname(dev)); 360 1.1 jdolecek error = ENODEV; 361 1.1 jdolecek goto end; 362 1.1 jdolecek } 363 1.6 perry 364 1.1 jdolecek switch (cmd) { 365 1.1 jdolecek 366 1.1 jdolecek case SIOCSIFDSTADDR: 367 1.1 jdolecek if (ifa->ifa_addr->sa_family != AF_INET) 368 1.1 jdolecek error = EAFNOSUPPORT; 369 1.1 jdolecek break; 370 1.6 perry 371 1.22 dyoung case SIOCINITIFADDR: 372 1.1 jdolecek if (ifa->ifa_addr->sa_family != AF_INET) { 373 1.1 jdolecek error = EAFNOSUPPORT; 374 1.1 jdolecek break; 375 1.1 jdolecek } 376 1.1 jdolecek ifp->if_flags |= IFF_UP; 377 1.1 jdolecek /* FALLTHROUGH */ 378 1.1 jdolecek case SIOCSIFFLAGS: 379 1.32 mlelstv if (cmd == SIOCSIFFLAGS) { 380 1.32 mlelstv if ((error = ifioctl_common(ifp, cmd, data)) != 0) 381 1.32 mlelstv break; 382 1.32 mlelstv } 383 1.29 msaitoh if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) { 384 1.29 msaitoh if ((error = ppbus_request_bus(ppbus, dev, 0, 0))) 385 1.1 jdolecek break; 386 1.1 jdolecek error = ppbus_set_mode(ppbus, PPBUS_COMPATIBLE, 0); 387 1.29 msaitoh if (error) 388 1.1 jdolecek break; 389 1.6 perry 390 1.1 jdolecek error = ppbus_add_handler(ppbus, lp_intr, dev); 391 1.29 msaitoh if (error) { 392 1.1 jdolecek LP_PRINTF("%s(%s): unable to register interrupt" 393 1.6 perry " callback.\n", __func__, 394 1.17 cegger device_xname(dev)); 395 1.1 jdolecek ppbus_release_bus(ppbus, dev, 0, 0); 396 1.1 jdolecek break; 397 1.1 jdolecek } 398 1.1 jdolecek 399 1.1 jdolecek /* Allocate a buffer if necessary */ 400 1.29 msaitoh if (sc->sc_ifbuf == NULL) { 401 1.6 perry sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + 402 1.34 chs MLPIPHDRLEN, M_DEVBUF, M_WAITOK); 403 1.1 jdolecek } 404 1.1 jdolecek 405 1.1 jdolecek ppbus_wctr(ppbus, IRQENABLE); 406 1.1 jdolecek ifp->if_flags |= IFF_RUNNING; 407 1.1 jdolecek } 408 1.29 msaitoh if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) { 409 1.1 jdolecek ppbus_remove_handler(ppbus, lp_intr); 410 1.1 jdolecek error = ppbus_release_bus(ppbus, dev, 0, 0); 411 1.1 jdolecek ifp->if_flags &= ~IFF_RUNNING; 412 1.1 jdolecek } 413 1.1 jdolecek /* Go quiescent */ 414 1.1 jdolecek ppbus_wdtr(ppbus, 0); 415 1.1 jdolecek break; 416 1.1 jdolecek 417 1.1 jdolecek case SIOCSIFMTU: 418 1.29 msaitoh if (sc->sc_if.if_mtu == ifr->ifr_mtu) 419 1.1 jdolecek break; 420 1.1 jdolecek ptr = sc->sc_ifbuf; 421 1.34 chs sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF, 422 1.34 chs M_WAITOK); 423 1.29 msaitoh if (ptr) 424 1.1 jdolecek free(ptr,M_DEVBUF); 425 1.16 dyoung /*FALLTHROUGH*/ 426 1.1 jdolecek case SIOCGIFMTU: 427 1.19 cegger if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 428 1.16 dyoung error = 0; 429 1.1 jdolecek break; 430 1.1 jdolecek 431 1.1 jdolecek case SIOCADDMULTI: 432 1.1 jdolecek case SIOCDELMULTI: 433 1.1 jdolecek if (ifr == NULL) { 434 1.1 jdolecek error = EAFNOSUPPORT; /* XXX */ 435 1.1 jdolecek break; 436 1.1 jdolecek } 437 1.14 dyoung switch (ifreq_getaddr(cmd, ifr)->sa_family) { 438 1.1 jdolecek case AF_INET: 439 1.1 jdolecek break; 440 1.1 jdolecek default: 441 1.28 maxv splx(s); 442 1.1 jdolecek return EAFNOSUPPORT; 443 1.1 jdolecek } 444 1.1 jdolecek break; 445 1.1 jdolecek 446 1.1 jdolecek case SIOCGIFMEDIA: 447 1.1 jdolecek /* 448 1.1 jdolecek * No ifmedia support at this stage; maybe use it 449 1.1 jdolecek * in future for eg. protocol selection. 450 1.1 jdolecek */ 451 1.1 jdolecek default: 452 1.1 jdolecek LP_PRINTF("LP:ioctl(0x%lx)\n", cmd); 453 1.22 dyoung error = ifioctl_common(ifp, cmd, data); 454 1.1 jdolecek } 455 1.1 jdolecek 456 1.1 jdolecek end: 457 1.1 jdolecek splx(s); 458 1.6 perry return error; 459 1.1 jdolecek } 460 1.1 jdolecek 461 1.8 perry static inline int 462 1.29 msaitoh clpoutbyte(u_char byte, int spin, device_t ppbus) 463 1.1 jdolecek { 464 1.1 jdolecek int s = spin; 465 1.1 jdolecek ppbus_wdtr(ppbus, ctxmitl[byte]); 466 1.1 jdolecek while (ppbus_rstr(ppbus) & CLPIP_SHAKE) { 467 1.1 jdolecek if (--s == 0) { 468 1.1 jdolecek return 1; 469 1.1 jdolecek } 470 1.1 jdolecek } 471 1.1 jdolecek s = spin; 472 1.1 jdolecek ppbus_wdtr(ppbus, ctxmith[byte]); 473 1.1 jdolecek while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 474 1.1 jdolecek if (--s == 0) { 475 1.1 jdolecek return 1; 476 1.1 jdolecek } 477 1.1 jdolecek } 478 1.1 jdolecek return 0; 479 1.1 jdolecek } 480 1.1 jdolecek 481 1.8 perry static inline int 482 1.29 msaitoh clpinbyte(int spin, device_t ppbus) 483 1.1 jdolecek { 484 1.1 jdolecek u_char c, cl; 485 1.1 jdolecek int s = spin; 486 1.1 jdolecek 487 1.29 msaitoh while (ppbus_rstr(ppbus) & CLPIP_SHAKE) { 488 1.29 msaitoh if (!--s) { 489 1.1 jdolecek return -1; 490 1.1 jdolecek } 491 1.1 jdolecek } 492 1.1 jdolecek cl = ppbus_rstr(ppbus); 493 1.1 jdolecek ppbus_wdtr(ppbus, 0x10); 494 1.1 jdolecek 495 1.1 jdolecek s = spin; 496 1.29 msaitoh while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 497 1.29 msaitoh if (!--s) { 498 1.1 jdolecek return -1; 499 1.1 jdolecek } 500 1.1 jdolecek } 501 1.1 jdolecek c = ppbus_rstr(ppbus); 502 1.1 jdolecek ppbus_wdtr(ppbus, 0x00); 503 1.1 jdolecek 504 1.1 jdolecek return (ctrecvl[cl] | ctrecvh[c]); 505 1.1 jdolecek } 506 1.1 jdolecek 507 1.1 jdolecek static void 508 1.30 msaitoh lptap(struct ifnet *ifp, struct mbuf *m, u_int direction) 509 1.1 jdolecek { 510 1.1 jdolecek /* 511 1.1 jdolecek * Send a packet through bpf. We need to prepend the address family 512 1.1 jdolecek * as a four byte field. Cons up a dummy header to pacify bpf. This 513 1.1 jdolecek * is safe because bpf will only read from the mbuf (i.e., it won't 514 1.1 jdolecek * try to free it or keep a pointer to it). 515 1.1 jdolecek */ 516 1.1 jdolecek u_int32_t af = AF_INET; 517 1.1 jdolecek struct mbuf m0; 518 1.6 perry 519 1.31 msaitoh m0.m_type = MT_DATA; 520 1.1 jdolecek m0.m_next = m; 521 1.31 msaitoh m0.m_nextpkt = NULL; 522 1.31 msaitoh m0.m_owner = NULL; 523 1.1 jdolecek m0.m_len = sizeof(u_int32_t); 524 1.1 jdolecek m0.m_data = (char *)⁡ 525 1.31 msaitoh m0.m_flags = 0; 526 1.30 msaitoh bpf_mtap(ifp, &m0, direction); 527 1.1 jdolecek } 528 1.1 jdolecek 529 1.1 jdolecek /* Soft interrupt handler called by hardware interrupt handler */ 530 1.1 jdolecek static void 531 1.29 msaitoh lp_intr(void *arg) 532 1.1 jdolecek { 533 1.18 cegger device_t dev = (device_t)arg; 534 1.18 cegger device_t ppbus = device_parent(dev); 535 1.18 cegger struct lp_softc * sc = device_private(dev); 536 1.1 jdolecek struct ifnet * ifp = &sc->sc_if; 537 1.1 jdolecek struct mbuf *top; 538 1.1 jdolecek int len, s, j; 539 1.1 jdolecek u_char *bp; 540 1.1 jdolecek u_char c, cl; 541 1.1 jdolecek 542 1.1 jdolecek s = splnet(); 543 1.1 jdolecek 544 1.1 jdolecek /* Do nothing if device not properly attached */ 545 1.29 msaitoh if (sc->sc_dev_ok) { 546 1.6 perry LP_PRINTF("%s(%s): device not properly attached!", __func__, 547 1.17 cegger device_xname(dev)); 548 1.1 jdolecek goto done; 549 1.1 jdolecek } 550 1.1 jdolecek 551 1.1 jdolecek /* Do nothing if interface is not up */ 552 1.29 msaitoh if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 553 1.1 jdolecek goto done; 554 1.1 jdolecek 555 1.1 jdolecek /* If other side is no longer transmitting, do nothing */ 556 1.29 msaitoh if (!(ppbus_rstr(ppbus) & LPIP_SHAKE)) 557 1.1 jdolecek goto done; 558 1.1 jdolecek 559 1.1 jdolecek /* Disable interrupts until we finish */ 560 1.1 jdolecek ppbus_wctr(ppbus, ~IRQENABLE); 561 1.1 jdolecek 562 1.1 jdolecek top = NULL; 563 1.1 jdolecek bp = sc->sc_ifbuf; 564 1.1 jdolecek /* Linux/crynwyr protocol receiving */ 565 1.29 msaitoh if (ifp->if_flags & IFF_LINK0) { 566 1.1 jdolecek /* Ack. the request */ 567 1.1 jdolecek ppbus_wdtr(ppbus, 0x01); 568 1.1 jdolecek 569 1.1 jdolecek /* Get the packet length */ 570 1.1 jdolecek j = clpinbyte(LPMAXSPIN2, ppbus); 571 1.29 msaitoh if (j == -1) 572 1.1 jdolecek goto err; 573 1.1 jdolecek len = j; 574 1.1 jdolecek j = clpinbyte(LPMAXSPIN2, ppbus); 575 1.29 msaitoh if (j == -1) 576 1.1 jdolecek goto err; 577 1.1 jdolecek len = len + (j << 8); 578 1.29 msaitoh if (len > ifp->if_mtu + MLPIPHDRLEN) 579 1.1 jdolecek goto err; 580 1.1 jdolecek 581 1.29 msaitoh while (len--) { 582 1.1 jdolecek j = clpinbyte(LPMAXSPIN2, ppbus); 583 1.1 jdolecek if (j == -1) { 584 1.1 jdolecek goto err; 585 1.1 jdolecek } 586 1.1 jdolecek *bp++ = j; 587 1.1 jdolecek } 588 1.1 jdolecek /* Get and ignore checksum */ 589 1.1 jdolecek j = clpinbyte(LPMAXSPIN2, ppbus); 590 1.29 msaitoh if (j == -1) { 591 1.1 jdolecek goto err; 592 1.1 jdolecek } 593 1.1 jdolecek 594 1.1 jdolecek /* Return to idle state */ 595 1.1 jdolecek ppbus_wdtr(ppbus, 0); 596 1.1 jdolecek len = bp - sc->sc_ifbuf; 597 1.1 jdolecek if (len <= CLPIPHDRLEN) 598 1.1 jdolecek goto err; 599 1.1 jdolecek len -= CLPIPHDRLEN; 600 1.33 maxv top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, ifp); 601 1.1 jdolecek } 602 1.1 jdolecek /* FreeBSD protocol receiving */ 603 1.1 jdolecek else { 604 1.1 jdolecek len = ifp->if_mtu + LPIPHDRLEN; 605 1.29 msaitoh while (len--) { 606 1.1 jdolecek cl = ppbus_rstr(ppbus); 607 1.1 jdolecek ppbus_wdtr(ppbus, 0x08); 608 1.1 jdolecek 609 1.1 jdolecek j = LPMAXSPIN2; 610 1.29 msaitoh while ((ppbus_rstr(ppbus) & LPIP_SHAKE)) { 611 1.29 msaitoh if (!--j) 612 1.29 msaitoh goto err; 613 1.1 jdolecek } 614 1.1 jdolecek 615 1.1 jdolecek c = ppbus_rstr(ppbus); 616 1.1 jdolecek ppbus_wdtr(ppbus, 0); 617 1.1 jdolecek 618 1.1 jdolecek *bp++= trecvh[cl] | trecvl[c]; 619 1.1 jdolecek 620 1.1 jdolecek j = LPMAXSPIN2; 621 1.29 msaitoh while (!((cl = ppbus_rstr(ppbus)) & LPIP_SHAKE)) { 622 1.29 msaitoh if (cl != c && 623 1.6 perry (((cl = ppbus_rstr(ppbus)) ^ 0xb8) & 624 1.1 jdolecek 0xf8) == (c & 0xf8)) 625 1.1 jdolecek goto end; 626 1.29 msaitoh if (!--j) 627 1.29 msaitoh goto err; 628 1.1 jdolecek } 629 1.1 jdolecek } 630 1.1 jdolecek 631 1.1 jdolecek end: 632 1.1 jdolecek len = bp - sc->sc_ifbuf; 633 1.29 msaitoh if (len <= LPIPHDRLEN) 634 1.1 jdolecek goto err; 635 1.1 jdolecek len -= LPIPHDRLEN; 636 1.33 maxv top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, ifp); 637 1.1 jdolecek } 638 1.1 jdolecek 639 1.25 rmind if (top == NULL) { 640 1.36 jdolecek if_statinc(ifp, if_iqdrops); 641 1.1 jdolecek goto err; 642 1.1 jdolecek } 643 1.25 rmind if (ifp->if_bpf) { 644 1.30 msaitoh lptap(ifp, top, BPF_D_IN); 645 1.25 rmind } 646 1.25 rmind if (__predict_false(!pktq_enqueue(ip_pktq, top, 0))) { 647 1.36 jdolecek if_statinc(ifp, if_iqdrops); 648 1.25 rmind m_freem(top); 649 1.25 rmind goto err; 650 1.25 rmind } 651 1.36 jdolecek if_statinc(ifp, if_ipackets); 652 1.36 jdolecek if_statadd(ifp, if_ibytes, len); 653 1.1 jdolecek sc->sc_iferrs = 0; 654 1.1 jdolecek 655 1.1 jdolecek goto done; 656 1.1 jdolecek 657 1.1 jdolecek err: 658 1.1 jdolecek /* Return to idle state */ 659 1.1 jdolecek ppbus_wdtr(ppbus, 0); 660 1.35 skrll if_statinc(ifp, if_ierrors); 661 1.1 jdolecek sc->sc_iferrs++; 662 1.1 jdolecek LP_PRINTF("R"); 663 1.6 perry /* Disable interface if there are too many errors */ 664 1.29 msaitoh if (sc->sc_iferrs > LPMAXERRS) { 665 1.17 cegger aprint_error_dev(dev, "Too many consecutive errors, going off-line.\n"); 666 1.1 jdolecek ppbus_wctr(ppbus, ~IRQENABLE); 667 1.1 jdolecek if_down(ifp); 668 1.1 jdolecek sc->sc_iferrs = 0; 669 1.1 jdolecek } 670 1.1 jdolecek 671 1.1 jdolecek done: 672 1.1 jdolecek /* Re-enable interrupts */ 673 1.1 jdolecek ppbus_wctr(ppbus, IRQENABLE); 674 1.1 jdolecek /* If interface is not active, send some packets */ 675 1.29 msaitoh if ((ifp->if_flags & IFF_OACTIVE) == 0) 676 1.1 jdolecek lpstart(ifp); 677 1.1 jdolecek splx(s); 678 1.1 jdolecek return; 679 1.1 jdolecek } 680 1.1 jdolecek 681 1.8 perry static inline int 682 1.18 cegger lpoutbyte(u_char byte, int spin, device_t ppbus) 683 1.1 jdolecek { 684 1.1 jdolecek int s = spin; 685 1.1 jdolecek ppbus_wdtr(ppbus, txmith[byte]); 686 1.29 msaitoh while (!(ppbus_rstr(ppbus) & LPIP_SHAKE)) { 687 1.29 msaitoh if (--s == 0) 688 1.1 jdolecek return 1; 689 1.1 jdolecek } 690 1.1 jdolecek s = spin; 691 1.1 jdolecek ppbus_wdtr(ppbus, txmitl[byte]); 692 1.29 msaitoh while (ppbus_rstr(ppbus) & LPIP_SHAKE) { 693 1.29 msaitoh if (--s == 0) 694 1.1 jdolecek return 1; 695 1.1 jdolecek } 696 1.1 jdolecek return 0; 697 1.1 jdolecek } 698 1.1 jdolecek 699 1.1 jdolecek /* Queue a packet for delivery */ 700 1.1 jdolecek static int 701 1.13 drochner lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 702 1.29 msaitoh const struct rtentry *rt) 703 1.1 jdolecek { 704 1.21 cegger struct lp_softc * sc = ifp->if_softc; 705 1.21 cegger device_t dev = sc->ppbus_dev.sc_dev; 706 1.18 cegger device_t ppbus = device_parent(dev); 707 1.1 jdolecek int err; 708 1.1 jdolecek int s; 709 1.1 jdolecek 710 1.1 jdolecek s = splnet(); 711 1.1 jdolecek 712 1.29 msaitoh if (sc->sc_dev_ok) { 713 1.6 perry LP_PRINTF("%s(%s): device not properly attached!", __func__, 714 1.17 cegger device_xname(dev)); 715 1.1 jdolecek err = ENODEV; 716 1.1 jdolecek goto endoutput; 717 1.1 jdolecek } 718 1.6 perry 719 1.29 msaitoh if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 720 1.1 jdolecek err = ENETDOWN; 721 1.1 jdolecek goto endoutput; 722 1.1 jdolecek } 723 1.6 perry 724 1.1 jdolecek /* Only support INET */ 725 1.29 msaitoh if (dst->sa_family != AF_INET) { 726 1.1 jdolecek LP_PRINTF("%s: af%d not supported\n", ifp->if_xname, 727 1.1 jdolecek dst->sa_family); 728 1.36 jdolecek if_statinc(ifp, if_noproto); 729 1.1 jdolecek err = EAFNOSUPPORT; 730 1.1 jdolecek goto endoutput; 731 1.1 jdolecek } 732 1.6 perry 733 1.26 knakahar IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 734 1.27 christos IFQ_ENQUEUE(&ifp->if_snd, m, err); 735 1.29 msaitoh if (err == 0) { 736 1.29 msaitoh if ((ifp->if_flags & IFF_OACTIVE) == 0) 737 1.1 jdolecek lpstart(ifp); 738 1.29 msaitoh } else { 739 1.35 skrll if_statinc(ifp, if_oerrors); 740 1.1 jdolecek sc->sc_iferrs++; 741 1.1 jdolecek LP_PRINTF("Q"); 742 1.1 jdolecek 743 1.6 perry /* Disable interface if there are too many errors */ 744 1.29 msaitoh if (sc->sc_iferrs > LPMAXERRS) { 745 1.17 cegger aprint_error_dev(dev, "Too many errors, going off-line.\n"); 746 1.1 jdolecek ppbus_wctr(ppbus, ~IRQENABLE); 747 1.1 jdolecek if_down(ifp); 748 1.1 jdolecek sc->sc_iferrs = 0; 749 1.1 jdolecek } 750 1.1 jdolecek } 751 1.1 jdolecek 752 1.1 jdolecek endoutput: 753 1.29 msaitoh if ((err != 0) && (err != ENOBUFS)) 754 1.1 jdolecek m_freem(m); 755 1.1 jdolecek splx(s); 756 1.1 jdolecek return err; 757 1.1 jdolecek } 758 1.1 jdolecek 759 1.1 jdolecek /* Send routine: send packets over PLIP cable. Call at splnet(). */ 760 1.1 jdolecek void 761 1.6 perry lpstart(struct ifnet * ifp) 762 1.1 jdolecek { 763 1.1 jdolecek struct lp_softc * lp = ifp->if_softc; 764 1.21 cegger device_t dev = lp->ppbus_dev.sc_dev; 765 1.18 cegger device_t ppbus = device_parent(dev); 766 1.1 jdolecek struct mbuf * mm; 767 1.1 jdolecek struct mbuf * m; 768 1.1 jdolecek u_char * cp; 769 1.1 jdolecek int err, i, len, spin, count; 770 1.1 jdolecek u_char str, chksum; 771 1.1 jdolecek 772 1.29 msaitoh if (lp->sc_dev_ok) { 773 1.6 perry LP_PRINTF("%s(%s): device not properly attached!", __func__, 774 1.17 cegger device_xname(dev)); 775 1.1 jdolecek return; 776 1.1 jdolecek } 777 1.6 perry 778 1.29 msaitoh if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 779 1.1 jdolecek return; 780 1.1 jdolecek } 781 1.1 jdolecek 782 1.1 jdolecek ifp->if_flags |= IFF_OACTIVE; 783 1.1 jdolecek 784 1.1 jdolecek /* Go quiescent */ 785 1.1 jdolecek ppbus_wdtr(ppbus, 0); 786 1.1 jdolecek 787 1.1 jdolecek /* Output loop */ 788 1.29 msaitoh for (;;) { 789 1.1 jdolecek /* Check if there are packets to send */ 790 1.29 msaitoh if (IFQ_IS_EMPTY(&ifp->if_snd)) { 791 1.1 jdolecek goto final; 792 1.1 jdolecek } 793 1.1 jdolecek /* Try to send a packet, dequeue it later if successful */ 794 1.1 jdolecek IFQ_POLL(&ifp->if_snd, m); 795 1.29 msaitoh if (m == NULL) 796 1.1 jdolecek goto final; 797 1.1 jdolecek 798 1.1 jdolecek str = ppbus_rstr(ppbus); 799 1.1 jdolecek /* Wait until other side is not transmitting */ 800 1.29 msaitoh if ((str & LPIP_SHAKE) || 801 1.1 jdolecek ((ifp->if_flags & IFF_LINK0) && !(str & CLPIP_SHAKE))) { 802 1.1 jdolecek LP_PRINTF("&"); 803 1.29 msaitoh if (++lp->sc_xmit_rtry > LPMAXRTRY) { 804 1.17 cegger aprint_error_dev(dev, "Too many retries while channel " 805 1.17 cegger "busy, going off-line.\n"); 806 1.1 jdolecek ppbus_wctr(ppbus, ~IRQENABLE); 807 1.1 jdolecek if_down(ifp); 808 1.1 jdolecek lp->sc_xmit_rtry = 0; 809 1.1 jdolecek } 810 1.1 jdolecek goto final; 811 1.1 jdolecek } 812 1.1 jdolecek lp->sc_xmit_rtry = 0; 813 1.1 jdolecek 814 1.1 jdolecek /* Disable interrupt generation */ 815 1.1 jdolecek ppbus_wctr(ppbus, ~IRQENABLE); 816 1.6 perry 817 1.1 jdolecek err = 1; 818 1.1 jdolecek 819 1.1 jdolecek /* Output packet for Linux/crynwyr compatible protocol */ 820 1.29 msaitoh if (ifp->if_flags & IFF_LINK0) { 821 1.1 jdolecek /* Calculate packet length */ 822 1.1 jdolecek count = 14; /* Ethernet header len */ 823 1.29 msaitoh for (mm = m; mm; mm = mm->m_next) { 824 1.1 jdolecek count += mm->m_len; 825 1.1 jdolecek } 826 1.1 jdolecek 827 1.1 jdolecek /* Alert other end to pending packet */ 828 1.1 jdolecek spin = LPMAXSPIN1; 829 1.1 jdolecek ppbus_wdtr(ppbus, 0x08); 830 1.29 msaitoh while ((ppbus_rstr(ppbus) & 0x08) == 0) { 831 1.1 jdolecek if (--spin == 0) { 832 1.1 jdolecek goto nend; 833 1.1 jdolecek } 834 1.1 jdolecek } 835 1.1 jdolecek 836 1.29 msaitoh if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 837 1.1 jdolecek goto nend; 838 1.29 msaitoh if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 839 1.1 jdolecek goto nend; 840 1.1 jdolecek 841 1.1 jdolecek /* Send dummy ethernet header */ 842 1.1 jdolecek chksum = 0; 843 1.29 msaitoh for (i = 0; i < 12; i++) { 844 1.29 msaitoh if (clpoutbyte(i, LPMAXSPIN1, ppbus)) 845 1.1 jdolecek goto nend; 846 1.1 jdolecek chksum += i; 847 1.1 jdolecek } 848 1.1 jdolecek 849 1.29 msaitoh if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 850 1.1 jdolecek goto nend; 851 1.29 msaitoh if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 852 1.1 jdolecek goto nend; 853 1.1 jdolecek chksum += 0x08 + 0x00; /* Add into checksum */ 854 1.1 jdolecek 855 1.1 jdolecek mm = m; 856 1.1 jdolecek do { 857 1.1 jdolecek cp = mtod(mm, u_char *); 858 1.1 jdolecek len = mm->m_len; 859 1.29 msaitoh while (len--) { 860 1.29 msaitoh if (clpoutbyte(*cp, LPMAXSPIN2, ppbus)) 861 1.1 jdolecek goto nend; 862 1.1 jdolecek chksum += *cp++; 863 1.1 jdolecek } 864 1.1 jdolecek } while ((mm = mm->m_next)); 865 1.1 jdolecek 866 1.1 jdolecek /* Send checksum */ 867 1.29 msaitoh if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 868 1.1 jdolecek goto nend; 869 1.1 jdolecek 870 1.1 jdolecek /* No errors */ 871 1.1 jdolecek err = 0; 872 1.1 jdolecek /* Go quiescent */ 873 1.1 jdolecek ppbus_wdtr(ppbus, 0); 874 1.1 jdolecek } 875 1.1 jdolecek /* Output packet for FreeBSD compatible protocol */ 876 1.1 jdolecek else { 877 1.1 jdolecek /* We need a sensible value if we abort */ 878 1.1 jdolecek cp = NULL; 879 1.1 jdolecek 880 1.29 msaitoh if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 881 1.1 jdolecek goto end; 882 1.29 msaitoh if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 883 1.1 jdolecek goto end; 884 1.1 jdolecek 885 1.1 jdolecek mm = m; 886 1.1 jdolecek do { 887 1.1 jdolecek cp = mtod(mm,u_char *); 888 1.1 jdolecek len = mm->m_len; 889 1.29 msaitoh while (len--) 890 1.29 msaitoh if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 891 1.1 jdolecek goto end; 892 1.1 jdolecek } while ((mm = mm->m_next)); 893 1.1 jdolecek 894 1.1 jdolecek /* no errors were encountered */ 895 1.1 jdolecek err = 0; 896 1.1 jdolecek 897 1.1 jdolecek end: 898 1.29 msaitoh if (cp) 899 1.1 jdolecek ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17); 900 1.1 jdolecek else 901 1.1 jdolecek ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17); 902 1.1 jdolecek } 903 1.2 jdolecek 904 1.2 jdolecek nend: 905 1.1 jdolecek /* Re-enable interrupt generation */ 906 1.1 jdolecek ppbus_wctr(ppbus, IRQENABLE); 907 1.1 jdolecek 908 1.29 msaitoh if (err) { 909 1.1 jdolecek /* Go quiescent */ 910 1.1 jdolecek ppbus_wdtr(ppbus, 0); 911 1.6 perry 912 1.35 skrll if_statinc(ifp, if_oerrors); 913 1.1 jdolecek lp->sc_iferrs++; 914 1.1 jdolecek LP_PRINTF("X"); 915 1.1 jdolecek 916 1.6 perry /* Disable interface if there are too many errors */ 917 1.29 msaitoh if (lp->sc_iferrs > LPMAXERRS) { 918 1.17 cegger aprint_error_dev(dev, "Too many errors, going off-line.\n"); 919 1.1 jdolecek ppbus_wctr(ppbus, ~IRQENABLE); 920 1.1 jdolecek if_down(ifp); 921 1.1 jdolecek lp->sc_iferrs = 0; 922 1.1 jdolecek goto final; 923 1.1 jdolecek } 924 1.29 msaitoh } else { 925 1.1 jdolecek /* Dequeue packet on success */ 926 1.1 jdolecek IFQ_DEQUEUE(&ifp->if_snd, m); 927 1.30 msaitoh if(ifp->if_bpf) 928 1.30 msaitoh lptap(ifp, m, BPF_D_OUT); 929 1.35 skrll if_statinc(ifp, if_opackets); 930 1.35 skrll if_statadd(ifp, if_obytes, m->m_pkthdr.len); 931 1.1 jdolecek m_freem(m); 932 1.1 jdolecek } 933 1.1 jdolecek } 934 1.1 jdolecek 935 1.1 jdolecek final: 936 1.1 jdolecek ifp->if_flags &= ~IFF_OACTIVE; 937 1.1 jdolecek return; 938 1.1 jdolecek } 939