Annotation of src/sys/arch/pc532/dev/lpt.c, Revision 1.41
1.41 ! chs 1: /* $NetBSD: lpt.c,v 1.40 2004/01/23 04:12:39 simonb Exp $ */
1.1 phil 2:
3: /*
4: * Copyright (c) 1994 Matthias Pfaller.
1.3 phil 5: * Copyright (c) 1994 Poul-Henning Kamp
1.27 mycroft 6: * Copyright (c) 1993, 1994 Charles M. Hannum.
1.1 phil 7: * Copyright (c) 1990 William F. Jolitz, TeleMuse
8: * All rights reserved.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
1.40 simonb 20: * This software is a component of "386BSD" developed by
1.1 phil 21: * William F. Jolitz, TeleMuse.
22: * 4. Neither the name of the developer nor the name "386BSD"
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
1.29 pk 26: * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: */
38:
39: /*
1.40 simonb 40: * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
41: * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
42: * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
43: * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
1.1 phil 44: * NOT MAKE USE OF THIS WORK.
45: *
46: * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
1.40 simonb 47: * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
48: * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
49: * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
50: * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
51: * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
52: * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
1.1 phil 53: * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
54: */
55:
56: /*
57: * Device Driver for Matthias's parallel printer port.
1.3 phil 58: * This driver is based on the i386 lpt driver and
59: * some IP code from Poul-Henning Kamp.
1.1 phil 60: */
1.39 lukem 61:
62: #include <sys/cdefs.h>
1.41 ! chs 63: __KERNEL_RCSID(0, "$NetBSD: lpt.c,v 1.40 2004/01/23 04:12:39 simonb Exp $");
1.39 lukem 64:
1.26 jonathan 65: #include "opt_inet.h"
1.1 phil 66:
67: #include <sys/param.h>
68: #include <sys/systm.h>
1.31 thorpej 69: #include <sys/callout.h>
1.1 phil 70: #include <sys/proc.h>
71: #include <sys/user.h>
72: #include <sys/buf.h>
73: #include <sys/kernel.h>
74: #include <sys/ioctl.h>
75: #include <sys/uio.h>
76: #include <sys/device.h>
77: #include <sys/syslog.h>
78: #include <sys/malloc.h>
1.35 gehenna 79: #include <sys/conf.h>
1.18 matthias 80:
81: #include <machine/autoconf.h>
1.6 phil 82:
1.1 phil 83: #if defined(INET) && defined(PLIP)
1.13 matthias 84: #include "bpfilter.h"
1.1 phil 85: #include <sys/mbuf.h>
86: #include <sys/socket.h>
1.19 is 87:
1.1 phil 88: #include <net/if.h>
1.13 matthias 89: #include <net/if_dl.h>
1.1 phil 90: #include <net/if_types.h>
1.19 is 91: #include <net/if_ether.h>
92:
1.1 phil 93: #include <netinet/in.h>
94: #include <netinet/in_systm.h>
95: #include <netinet/in_var.h>
96: #include <netinet/ip.h>
1.19 is 97: #include <netinet/if_inarp.h>
1.13 matthias 98: #if NBPFILTER > 0
99: #include <sys/time.h>
100: #include <net/bpf.h>
1.1 phil 101: #endif
1.13 matthias 102: #endif
103:
104: #include "lpt.h"
105: #include "lptreg.h"
1.1 phil 106:
1.3 phil 107: #define LPT_INVERT (LPC_NBUSY|LPC_NERROR|LPC_NACK|LPC_ONLINE)
108: #define LPT_MASK (LPC_NBUSY|LPC_NERROR|LPC_NACK|LPC_NOPAPER|LPC_ONLINE)
109:
1.1 phil 110: #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
111: #define STEP hz/4
112:
113: #define LPTPRI (PZERO+8)
114: #define LPT_BSIZE 1024
115:
116: #if defined(INET) && defined(PLIP)
1.3 phil 117: #ifndef PLIPMTU /* MTU for the plip# interfaces */
118: #if defined(COMPAT_PLIP10)
1.7 jtc 119: #define PLIPMTU 1600 /* Linux 1.0.x */
120: #elif defined(COMPAT_PLIP11)
121: #define PLIPMTU (ETHERMTU - ifp->if_hdrlen) /* Linux 1.1.x */
1.3 phil 122: #else
1.7 jtc 123: #define PLIPMTU ETHERMTU /* Linux 1.3.x */
1.3 phil 124: #endif
1.1 phil 125: #endif
126:
1.3 phil 127: #ifndef PLIPMXSPIN1 /* DELAY factor for the plip# interfaces */
1.23 matthias 128: #define PLIPMXSPIN1 50000 /* Spinning for remote intr to happen */
1.1 phil 129: #endif
130:
1.3 phil 131: #ifndef PLIPMXSPIN2 /* DELAY factor for the plip# interfaces */
1.23 matthias 132: #define PLIPMXSPIN2 50000 /* Spinning for remote handshake to happen */
1.1 phil 133: #endif
134:
135: #ifndef PLIPMXERRS /* Max errors before !RUNNING */
1.4 phil 136: #define PLIPMXERRS 20
1.1 phil 137: #endif
138: #ifndef PLIPMXRETRY
139: #define PLIPMXRETRY 20 /* Max number of retransmits */
140: #endif
141: #ifndef PLIPRETRY
142: #define PLIPRETRY hz/50 /* Time between retransmits */
143: #endif
144: #endif
145:
146: struct lpt_softc {
147: struct device sc_dev;
148: size_t sc_count;
149: u_char *sc_inbuf;
150: u_char *sc_cp;
151: volatile struct i8255 *sc_i8255;
152: int sc_irq;
153: u_char sc_state;
154: #define LPT_OPEN 0x01 /* device is open */
155: #define LPT_INIT 0x02 /* waiting to initialize for open */
156:
1.6 phil 157: u_char sc_status;
1.1 phil 158: u_char sc_flags;
159: #define LPT_AUTOLF 0x20 /* automatic LF on CR */
160: #define LPT_NOPRIME 0x40 /* don't prime on open */
161:
1.31 thorpej 162: struct callout sc_out_ch;
163:
1.1 phil 164: #if defined(INET) && defined(PLIP)
1.19 is 165: struct ethercom sc_ethercom;
1.31 thorpej 166: struct callout sc_plipout_ch;
167: struct callout sc_pliprx_ch;
1.1 phil 168: u_char *sc_ifbuf;
1.4 phil 169: int sc_ifierrs; /* consecutive input errors */
170: int sc_ifoerrs; /* consecutive output errors */
1.6 phil 171: int sc_ifsoftint; /* i/o software interrupt */
172: volatile int sc_pending; /* interrputs pending */
173: #define PLIP_IPENDING 1
174: #define PLIP_OPENDING 2
175:
1.3 phil 176: #if defined(COMPAT_PLIP10)
1.1 phil 177: u_char sc_adrcksum;
178: #endif
1.3 phil 179: #endif
1.1 phil 180: };
181:
1.3 phil 182: #define LPTUNIT(s) (minor(s) & 0x1f)
183: #define LPTFLAGS(s) (minor(s) & 0xe0)
1.20 matthias 184: #define LPTSOFTC(n) ((struct lpt_softc *) lpt_cd.cd_devs[n])
1.13 matthias 185:
1.17 matthias 186: static int lptmatch __P((struct device *, struct cfdata *, void *aux));
1.13 matthias 187: static void lptattach __P((struct device *, struct device *, void *));
1.16 matthias 188: static void lptintr __P((void *));
1.13 matthias 189: static int notready __P((u_char, struct lpt_softc *));
1.16 matthias 190: static void lptout __P((void *));
1.13 matthias 191: static int pushbytes __P((struct lpt_softc *));
1.1 phil 192:
193: #if defined(INET) && defined(PLIP)
194: /* Functions for the plip# interface */
1.23 matthias 195: static void plipattach __P((struct lpt_softc *,int));
196: static void plipinput __P((struct lpt_softc *));
197: static int plipioctl __P((struct ifnet *, u_long, caddr_t));
198: static void plipoutput __P((void *));
199: #ifndef __OPTIMIZE__
200: static
201: #endif
202: int plipreceive __P((volatile struct i8255 *, u_char *, int));
203: static void pliprxenable __P((void *));
204: static void plipsoftint __P((void *));
205: static void plipstart __P((struct ifnet *));
206: #ifndef __OPTIMIZE__
207: static
208: #endif
209: int pliptransmit __P((volatile struct i8255 *, u_char *, int));
1.1 phil 210: #endif
211:
1.37 thorpej 212: CFATTACH_DECL(lpt, sizeof(struct lpt_softc),
213: lptmatch, lptattach, NULL, NULL);
1.8 thorpej 214:
1.25 thorpej 215: extern struct cfdriver lpt_cd;
1.35 gehenna 216:
217: dev_type_open(lptopen);
218: dev_type_close(lptclose);
219: dev_type_write(lptwrite);
220: dev_type_ioctl(lptioctl);
221:
222: const struct cdevsw lpt_cdevsw = {
223: lptopen, lptclose, noread, lptwrite, lptioctl,
1.38 jdolecek 224: nostop, notty, nopoll, nommap, nokqfilter,
1.35 gehenna 225: };
1.1 phil 226:
1.13 matthias 227: static int
228: lptmatch(parent, cf, aux)
229: struct device *parent;
1.17 matthias 230: struct cfdata *cf;
231: void *aux;
1.1 phil 232: {
1.18 matthias 233: struct confargs *ca = aux;
1.1 phil 234: volatile struct i8255 *i8255 =
1.41 ! chs 235: (volatile struct i8255 *)cf->cf_addr;
1.1 phil 236:
1.41 ! chs 237: if (cf->cf_addr == MAINBUSCF_ADDR_DEFAULT)
! 238: return 0;
! 239: if (cf->cf_irq == MAINBUSCF_IRQ_DEFAULT)
! 240: return 0;
1.1 phil 241:
242: i8255->port_control = LPT_PROBE_MODE;
243:
244: i8255->port_control = LPT_PROBE_CLR;
1.3 phil 245: if ((i8255->port_c & LPT_PROBE_MASK) != 0)
1.1 phil 246: return 0;
1.40 simonb 247:
1.1 phil 248: i8255->port_control = LPT_PROBE_SET;
1.3 phil 249: if ((i8255->port_c & LPT_PROBE_MASK) == 0)
1.1 phil 250: return 0;
251:
252: i8255->port_control = LPT_PROBE_CLR;
1.3 phil 253: if ((i8255->port_c & LPT_PROBE_MASK) != 0)
1.1 phil 254: return 0;
255:
256: i8255->port_control = LPT_MODE;
1.3 phil 257: i8255->port_a = LPA_ACTIVE | LPA_NPRIME;
1.18 matthias 258:
259: ca->ca_addr = (int)i8255;
260:
1.1 phil 261: return 1;
262: }
263:
1.13 matthias 264: static void
265: lptattach(parent, self, aux)
266: struct device *parent, *self;
267: void *aux;
1.1 phil 268: {
1.18 matthias 269: struct confargs *ca = aux;
1.1 phil 270: struct lpt_softc *sc = (struct lpt_softc *) self;
1.18 matthias 271: volatile struct i8255 *i8255;
1.1 phil 272:
1.18 matthias 273: printf("\n");
1.1 phil 274:
1.18 matthias 275: sc->sc_irq = ca->ca_irq;
276: i8255 = (volatile struct i8255 *)ca->ca_addr;
1.1 phil 277: i8255->port_control = LPT_MODE;
1.3 phil 278: i8255->port_a = LPA_ACTIVE | LPA_NPRIME;
1.1 phil 279: i8255->port_control = LPT_IRQDISABLE;
280:
281: sc->sc_state = 0;
282: sc->sc_i8255 = i8255;
283:
1.31 thorpej 284: callout_init(&sc->sc_out_ch);
285:
1.6 phil 286: #if defined(INET) && defined(PLIP)
1.1 phil 287: plipattach(sc, self->dv_unit);
1.6 phil 288: #endif
1.5 phil 289: intr_establish(sc->sc_irq, lptintr, sc, sc->sc_dev.dv_xname,
1.23 matthias 290: IPL_ZERO, IPL_ZERO, LOW_LEVEL);
1.1 phil 291: }
292:
293: /*
294: * Reset the printer, then wait until it's selected and not busy.
295: */
296: int
1.13 matthias 297: lptopen(dev, flag, mode, p)
298: dev_t dev;
299: int flag;
300: int mode;
301: struct proc *p;
1.1 phil 302: {
1.20 matthias 303: struct lpt_softc *sc;
304: volatile struct i8255 *i8255;
1.1 phil 305: u_char flags = LPTFLAGS(dev);
306: int error;
307: int spin;
308:
1.20 matthias 309: if (LPTUNIT(dev) >= lpt_cd.cd_ndevs)
310: return ENXIO;
311:
312: sc = LPTSOFTC(LPTUNIT(dev));
313: if (!sc)
1.1 phil 314: return ENXIO;
315:
1.6 phil 316: if (sc->sc_state)
1.1 phil 317: return EBUSY;
318:
1.20 matthias 319: i8255 = sc->sc_i8255;
1.6 phil 320: #if defined(INET) && defined(PLIP)
1.19 is 321: if (sc->sc_ethercom.ec_if.if_flags & IFF_UP)
1.6 phil 322: return EBUSY;
323: #endif
324:
1.1 phil 325: sc->sc_state = LPT_INIT;
326: sc->sc_flags = flags;
327:
328: if ((flags & LPT_NOPRIME) == 0) {
329: /* assert INIT for 100 usec to start up printer */
1.3 phil 330: i8255->port_a &= ~LPA_NPRIME;
1.1 phil 331: DELAY(100);
332: }
333:
334: if (flags & LPT_AUTOLF)
1.3 phil 335: i8255->port_a |= LPA_ALF | LPA_SELECT | LPA_NPRIME;
1.1 phil 336: else
1.3 phil 337: i8255->port_a = (i8255->port_a & ~LPA_ALF)
338: | LPA_SELECT | LPA_NPRIME;
1.1 phil 339:
340: /* wait till ready (printer running diagnostics) */
1.3 phil 341: for (spin = 0; notready(i8255->port_c, sc); spin += STEP) {
1.1 phil 342: if (spin >= TIMEOUT) {
343: sc->sc_state = 0;
344: return EBUSY;
345: }
346:
347: /* wait 1/4 second, give up if we get a signal */
1.20 matthias 348: error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP);
349: if (error != EWOULDBLOCK) {
1.1 phil 350: sc->sc_state = 0;
351: return error;
352: }
353: }
354:
355: sc->sc_inbuf = malloc(LPT_BSIZE, M_DEVBUF, M_WAITOK);
356: sc->sc_status =
357: sc->sc_count = 0;
358: sc->sc_state = LPT_OPEN;
359:
360: return 0;
361: }
362:
1.13 matthias 363: static int
364: notready(status, sc)
365: u_char status;
366: struct lpt_softc *sc;
1.1 phil 367: {
368: status ^= LPT_INVERT;
369:
370: if (status != sc->sc_status) {
371: if (status & LPC_NOPAPER)
372: log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
1.3 phil 373: if (status & LPC_ONLINE)
1.1 phil 374: log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
1.3 phil 375: if (status & LPC_NERROR)
1.1 phil 376: log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
1.3 phil 377: if (status & LPC_NACK)
378: log(LOG_NOTICE, "%s: NACK low\n", sc->sc_dev.dv_xname);
379: if (status & LPC_NBUSY)
380: log(LOG_NOTICE, "%s: NBUSY low\n", sc->sc_dev.dv_xname);
1.1 phil 381: sc->sc_status = status;
382: }
383: return status & LPT_MASK;
384: }
385:
1.13 matthias 386: static void
387: lptout(arg)
388: void *arg;
1.1 phil 389: {
1.16 matthias 390: struct lpt_softc *sc = arg;
1.3 phil 391: if (sc->sc_count > 0)
1.1 phil 392: sc->sc_i8255->port_control = LPT_IRQENABLE;
393: }
394:
395: /*
396: * Close the device, and free the local line buffer.
397: */
1.13 matthias 398: int
399: lptclose(dev, flag, mode, p)
400: dev_t dev;
401: int flag;
402: int mode;
403: struct proc *p;
1.1 phil 404: {
1.20 matthias 405: struct lpt_softc *sc = LPTSOFTC(LPTUNIT(dev));
1.1 phil 406:
407: if (sc->sc_count)
408: (void) pushbytes(sc);
409:
410: sc->sc_i8255->port_control = LPT_IRQDISABLE;
411: sc->sc_state = 0;
412: free(sc->sc_inbuf, M_DEVBUF);
413:
414: return 0;
415: }
416:
1.13 matthias 417: static int
418: pushbytes(sc)
419: struct lpt_softc *sc;
1.1 phil 420: {
421: volatile struct i8255 *i8255 = sc->sc_i8255;
422: int error;
423:
424: while (sc->sc_count > 0) {
425: i8255->port_control = LPT_IRQENABLE;
1.20 matthias 426: error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptwrite", 0);
1.40 simonb 427: if (error != 0)
1.1 phil 428: return error;
429: }
430: return 0;
431: }
432:
1.40 simonb 433: /*
1.3 phil 434: * Copy a line from user space to a local buffer, then call pushbytes to
435: * get the chars moved to the output queue.
1.1 phil 436: */
1.13 matthias 437: int
438: lptwrite(dev, uio, flags)
439: dev_t dev;
440: struct uio *uio;
441: int flags;
1.1 phil 442: {
1.20 matthias 443: struct lpt_softc *sc = LPTSOFTC(LPTUNIT(dev));
1.1 phil 444: size_t n;
445: int error = 0;
446:
447: if (sc->sc_count) return EBUSY;
1.20 matthias 448: while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) {
1.1 phil 449: uiomove(sc->sc_cp = sc->sc_inbuf, n, uio);
450: sc->sc_count = n;
451: error = pushbytes(sc);
452: if (error) {
453: /*
454: * Return accurate residual if interrupted or timed
455: * out.
456: */
457: uio->uio_resid += sc->sc_count;
458: sc->sc_count = 0;
459: return error;
460: }
461: }
462: return 0;
463: }
464:
465: /*
466: * Handle printer interrupts which occur when the printer is ready to accept
467: * another char.
468: */
1.13 matthias 469: static void
1.16 matthias 470: lptintr(arg)
471: void *arg;
1.1 phil 472: {
1.16 matthias 473: struct lpt_softc *sc = arg;
1.1 phil 474: volatile struct i8255 *i8255 = sc->sc_i8255;
475:
476: #if defined(INET) && defined(PLIP)
1.19 is 477: if (sc->sc_ethercom.ec_if.if_flags & IFF_UP) {
1.6 phil 478: i8255->port_a &= ~LPA_ACKENABLE;
479: sc->sc_pending |= PLIP_IPENDING;
480: softintr(sc->sc_ifsoftint);
1.3 phil 481: return;
1.1 phil 482: }
483: #endif
484:
485: if ((sc->sc_state & LPT_OPEN) == 0) {
486: i8255->port_control = LPT_IRQDISABLE;
1.3 phil 487: return;
1.1 phil 488: }
489:
490: if (sc->sc_count) {
491: /* is printer online and ready for output? */
1.3 phil 492: if (notready(i8255->port_c, sc)) {
1.1 phil 493: i8255->port_control = LPT_IRQDISABLE;
1.31 thorpej 494: callout_reset(&sc->sc_out_ch, STEP, lptout, sc);
1.3 phil 495: return;
1.1 phil 496: }
497: /* send char */
1.3 phil 498: i8255->port_a &= ~LPA_ACTIVE;
499: i8255->port_b = *sc->sc_cp++;
1.1 phil 500: i8255->port_a |= LPA_ACTIVE;
501: sc->sc_count--;
502: }
503:
504: if (sc->sc_count == 0) {
505: /* none, wake up the top half to get more */
506: i8255->port_control = LPT_IRQDISABLE;
507: wakeup((caddr_t)sc);
508: }
509: }
510:
511: int
1.13 matthias 512: lptioctl(dev, cmd, data, flag, p)
513: dev_t dev;
514: u_long cmd;
515: caddr_t data;
516: int flag;
517: struct proc *p;
1.1 phil 518: {
519: int error = 0;
520:
521: switch (cmd) {
522: default:
523: error = EINVAL;
524: }
525:
526: return error;
527: }
528:
529: #if defined(INET) && defined(PLIP)
530:
531: static void
1.13 matthias 532: plipattach(sc, unit)
533: struct lpt_softc *sc;
534: int unit;
1.1 phil 535: {
1.19 is 536: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.20 matthias 537: u_int8_t myaddr[ETHER_ADDR_LEN];
1.1 phil 538:
1.31 thorpej 539: callout_init(&sc->sc_plipout_ch);
540: callout_init(&sc->sc_pliprx_ch);
541:
1.1 phil 542: sc->sc_ifbuf = NULL;
1.15 christos 543: sprintf(ifp->if_xname, "plip%d", unit);
1.28 matthias 544: memset(myaddr, 0, sizeof(myaddr));
1.9 thorpej 545: ifp->if_softc = sc;
1.3 phil 546: ifp->if_start = plipstart;
547: ifp->if_ioctl = plipioctl;
548: ifp->if_watchdog = 0;
1.13 matthias 549: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
1.3 phil 550:
1.13 matthias 551: if_attach(ifp);
1.20 matthias 552: ether_ifattach(ifp, myaddr);
1.1 phil 553: ifp->if_mtu = PLIPMTU;
1.13 matthias 554:
1.6 phil 555: sc->sc_ifsoftint = intr_establish(SOFTINT, plipsoftint, sc,
1.17 matthias 556: sc->sc_dev.dv_xname, IPL_NET, IPL_ZERO, 0);
1.1 phil 557: }
558:
559: /*
560: * Process an ioctl request.
561: */
562: static int
1.13 matthias 563: plipioctl(ifp, cmd, data)
564: struct ifnet *ifp;
565: u_long cmd;
566: caddr_t data;
1.1 phil 567: {
1.6 phil 568: struct proc *p = curproc;
1.9 thorpej 569: struct lpt_softc *sc = (struct lpt_softc *)(ifp->if_softc);
1.1 phil 570: volatile struct i8255 *i8255 = sc->sc_i8255;
571: struct ifaddr *ifa = (struct ifaddr *)data;
1.40 simonb 572: struct ifreq *ifr = (struct ifreq *)data;
1.13 matthias 573: struct sockaddr_dl *sdl;
1.1 phil 574: int error = 0;
575:
576: switch (cmd) {
577: case SIOCSIFFLAGS:
578: if (((ifp->if_flags & IFF_UP) == 0) &&
579: (ifp->if_flags & IFF_RUNNING)) {
580: ifp->if_flags &= ~IFF_RUNNING;
581: sc->sc_i8255->port_control = LPT_MODE;
1.3 phil 582: i8255->port_a = LPA_ACTIVE | LPA_NPRIME;
1.1 phil 583: if (sc->sc_ifbuf)
584: free(sc->sc_ifbuf, M_DEVBUF);
585: sc->sc_ifbuf = NULL;
586: }
587: if (((ifp->if_flags & IFF_UP)) &&
588: ((ifp->if_flags & IFF_RUNNING) == 0)) {
1.3 phil 589: if (sc->sc_state) {
590: error = EBUSY;
591: break;
592: }
1.1 phil 593: if (!sc->sc_ifbuf)
594: sc->sc_ifbuf =
1.3 phil 595: malloc(ifp->if_mtu + ifp->if_hdrlen,
596: M_DEVBUF, M_WAITOK);
1.1 phil 597: ifp->if_flags |= IFF_RUNNING;
598: sc->sc_i8255->port_control = LPT_IRQDISABLE;
599: sc->sc_i8255->port_b = 0;
600: sc->sc_i8255->port_a |= LPA_ACKENABLE;
601: }
602: break;
603:
604: case SIOCSIFADDR:
1.19 is 605: sdl = ifp->if_sadl;
1.1 phil 606: if (ifa->ifa_addr->sa_family == AF_INET) {
607: if (!sc->sc_ifbuf)
608: sc->sc_ifbuf =
1.3 phil 609: malloc(PLIPMTU + ifp->if_hdrlen,
610: M_DEVBUF, M_WAITOK);
1.19 is 611: LLADDR(sdl)[0] = 0xfc;
612: LLADDR(sdl)[1] = 0xfc;
1.28 matthias 613: memcpy((caddr_t)&LLADDR(sdl)[2],
614: (caddr_t)&IA_SIN(ifa)->sin_addr, 4);
1.3 phil 615: #if defined(COMPAT_PLIP10)
1.1 phil 616: if (ifp->if_flags & IFF_LINK0) {
617: int i;
1.19 is 618: LLADDR(sdl)[0] = 0xfd;
619: LLADDR(sdl)[1] = 0xfd;
1.1 phil 620: for (i = sc->sc_adrcksum = 0; i < 5; i++)
1.19 is 621: sc->sc_adrcksum += LLADDR(sdl)[i];
1.1 phil 622: sc->sc_adrcksum *= 2;
623: }
1.3 phil 624: #endif
1.13 matthias 625: ifp->if_flags |= IFF_RUNNING | IFF_UP;
1.1 phil 626: sc->sc_i8255->port_control = LPT_IRQDISABLE;
627: sc->sc_i8255->port_b = 0;
628: sc->sc_i8255->port_a |= LPA_ACKENABLE;
1.19 is 629: arp_ifinit(ifp, ifa);
1.1 phil 630: } else
631: error = EAFNOSUPPORT;
632: break;
633:
1.3 phil 634: case SIOCAIFADDR:
635: case SIOCDIFADDR:
1.1 phil 636: case SIOCSIFDSTADDR:
637: if (ifa->ifa_addr->sa_family != AF_INET)
638: error = EAFNOSUPPORT;
639: break;
640:
641: case SIOCSIFMTU:
642: if ((error = suser(p->p_ucred, &p->p_acflag)))
1.3 phil 643: return(error);
1.11 cgd 644: if (ifp->if_mtu != ifr->ifr_mtu) {
645: ifp->if_mtu = ifr->ifr_mtu;
1.1 phil 646: if (sc->sc_ifbuf) {
647: free(sc->sc_ifbuf, M_DEVBUF);
648: sc->sc_ifbuf =
1.3 phil 649: malloc(ifp->if_mtu + ifp->if_hdrlen,
650: M_DEVBUF, M_WAITOK);
1.1 phil 651: }
652: }
653: break;
654:
655: default:
656: error = EINVAL;
657: }
658: return (error);
659: }
660:
1.6 phil 661: static void
1.16 matthias 662: plipsoftint(arg)
663: void *arg;
1.6 phil 664: {
1.16 matthias 665: struct lpt_softc *sc = arg;
1.6 phil 666: int pending = sc->sc_pending;
667:
668: while (sc->sc_pending & PLIP_IPENDING) {
669: pending |= sc->sc_pending;
670: sc->sc_pending = 0;
671: plipinput(sc);
672: }
673:
674: if (pending & PLIP_OPENDING)
675: plipoutput(sc);
676: }
677:
1.13 matthias 678: #ifdef __OPTIMIZE__
1.23 matthias 679: int plipreceive __P((volatile struct i8255 *, u_char *, int))
680: __asm("plipreceive");
1.41 ! chs 681: __asm(" \
! 682: plipreceive: \
! 683: enter [r3,r4,r5,r6,r7],0 ; \
! 684: movqd 0,r0 ; \
! 685: movd 8(fp),r1 ; \
! 686: movd 12(fp),r2 ; \
! 687: movd 16(fp),r3 ; \
! 688: cmpqd 0,r3 ; \
! 689: beq 5f ; \
! 690: \
! 691: movqd 0,r7 ; \
! 692: movd 50000,r4 ; \
! 693: \
! 694: .align 2,0xa2 ; \
! 695: 0: movb 8,r5 ; \
! 696: 1: movb 2(r1),r6 ; \
! 697: andb r6,r5 ; \
! 698: cmpqb 0,r5 ; \
! 699: beq 2f ; \
! 700: acbd -1,r4,1b ; \
! 701: br 6f ; \
! 702: \
! 703: .align 2,0xa2 ; \
! 704: 2: movb 0x11,1(r1) ; \
! 705: lshb -4,r6 ; \
! 706: addd r7,r0 ; \
! 707: addqd 1,r2 ; \
! 708: \
! 709: movb 8,r5 ; \
! 710: 3: movb 2(r1),r7 ; \
! 711: bicb r7,r5 ; \
! 712: cmpqb 0,r5 ; \
! 713: beq 4f ; \
! 714: acbd -1,r4,3b ; \
! 715: br 6f ; \
! 716: \
! 717: .align 2,0xa2 ; \
! 718: 4: movqb 0x01,1(r1) ; \
! 719: andb 0xf0,r7 ; \
! 720: orb r6,r7 ; \
! 721: movb r7,-1(r2) ; \
! 722: acbd -1,r3,0b ; \
! 723: \
! 724: addd r7,r0 ; \
! 725: andd 0xff,r0 ; \
! 726: 5: exit [r3,r4,r5,r6,r7] ; \
! 727: ret 0 ; \
! 728: \
! 729: 6: movqd -1,r0 ; \
! 730: exit [r3,r4,r5,r6,r7] ; \
! 731: ret 0 \
1.13 matthias 732: ");
733: #else
1.1 phil 734: static int
1.13 matthias 735: plipreceive(i8255, buf, len)
736: volatile struct i8255 *i8255;
737: u_char *buf;
738: int len;
1.1 phil 739: {
740: int i;
741: u_char cksum = 0, c;
742:
743: while (len--) {
1.3 phil 744: i = PLIPMXSPIN2;
745: while ((i8255->port_c & LPC_NBUSY) != 0)
746: if (i-- < 0) return -1;
747: c = i8255->port_c >> 4;
1.1 phil 748: i8255->port_b = 0x11;
1.3 phil 749: while ((i8255->port_c & LPC_NBUSY) == 0)
750: if (i-- < 0) return -1;
751: c |= i8255->port_c & 0xf0;
1.1 phil 752: i8255->port_b = 0x01;
753: cksum += (*buf++ = c);
754: }
755: return(cksum);
756: }
1.13 matthias 757: #endif
1.1 phil 758:
759: static void
1.23 matthias 760: pliprxenable(arg)
761: void *arg;
762: {
763: struct lpt_softc *sc = arg;
764: volatile struct i8255 *i8255 = sc->sc_i8255;
765: i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE;
766: }
767:
768: static void
1.13 matthias 769: plipinput(sc)
770: struct lpt_softc *sc;
1.1 phil 771: {
1.19 is 772: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.1 phil 773: volatile struct i8255 *i8255 = sc->sc_i8255;
774: struct mbuf *m;
775: struct ether_header *eh;
776: u_char *p = sc->sc_ifbuf, minibuf[4];
1.20 matthias 777: int s, len, cksum;
1.1 phil 778:
1.6 phil 779: if (!(i8255->port_c & LPC_NACK)) {
780: i8255->port_a |= LPA_ACKENABLE;
781: ifp->if_collisions++;
782: return;
783: }
784: i8255->port_b = 0x01;
1.3 phil 785: i8255->port_a &= ~(LPA_ACKENABLE | LPA_ACTIVE);
1.1 phil 786:
1.23 matthias 787: if (sc->sc_ifierrs)
1.31 thorpej 788: callout_stop(&sc->sc_pliprx_ch);
1.23 matthias 789:
1.3 phil 790: #if defined(COMPAT_PLIP10)
1.1 phil 791: if (ifp->if_flags & IFF_LINK0) {
1.20 matthias 792: int c;
1.1 phil 793: if (plipreceive(i8255, minibuf, 3) < 0) goto err;
794: len = (minibuf[1] << 8) | minibuf[2];
1.3 phil 795: if (len > (ifp->if_mtu + ifp->if_hdrlen)) goto err;
1.1 phil 796:
797: switch (minibuf[0]) {
798: case 0xfc:
1.19 is 799: p[0] = p[ 6] = LLADDR(ifp->if_sadl)[0];
800: p[1] = p[ 7] = LLADDR(ifp->if_sadl)[1];
801: p[2] = p[ 8] = LLADDR(ifp->if_sadl)[2];
802: p[3] = p[ 9] = LLADDR(ifp->if_sadl)[3];
803: p[4] = p[10] = LLADDR(ifp->if_sadl)[4];
1.1 phil 804: p += 5;
805: if ((cksum = plipreceive(i8255, p, 1)) < 0) goto err;
806: p += 6;
807: if ((c = plipreceive(i8255, p, len - 11)) < 0) goto err;
808: cksum += c + sc->sc_adrcksum;
809: c = p[1]; p[1] = p[2]; p[2] = c;
810: cksum &= 0xff;
811: break;
812: case 0xfd:
813: if ((cksum = plipreceive(i8255, p, len)) < 0) goto err;
814: break;
815: default:
816: goto err;
817: }
1.3 phil 818: } else
819: #endif
820: {
1.1 phil 821: if (plipreceive(i8255, minibuf, 2) < 0) goto err;
822: len = (minibuf[1] << 8) | minibuf[0];
1.3 phil 823: if (len > (ifp->if_mtu + ifp->if_hdrlen)) {
1.13 matthias 824: log(LOG_NOTICE, "%s: packet (%x) > MTU\n", ifp->if_xname, len);
1.3 phil 825: goto err;
826: }
1.1 phil 827: if ((cksum = plipreceive(i8255, p, len)) < 0) goto err;
828: }
1.6 phil 829:
1.1 phil 830: if (plipreceive(i8255, minibuf, 1) < 0) goto err;
831: if (cksum != minibuf[0]) {
1.9 thorpej 832: log(LOG_NOTICE, "%s: checksum error\n", ifp->if_xname);
1.1 phil 833: goto err;
834: }
835: i8255->port_b = 0x00;
836:
1.34 thorpej 837: s = splnet();
1.20 matthias 838: if ((m = m_devget(sc->sc_ifbuf, len, 0, ifp, NULL)) != NULL) {
1.1 phil 839: /* We assume that the header fit entirely in one mbuf. */
840: eh = mtod(m, struct ether_header *);
1.13 matthias 841: #if NBPFILTER > 0
842: /*
843: * Check if there's a BPF listener on this interface.
844: * If so, hand off the raw packet to bpf.
845: */
846: if (ifp->if_bpf) {
847: bpf_mtap(ifp->if_bpf, m);
848: }
849: #endif
1.30 thorpej 850: (*ifp->if_input)(ifp, m);
1.1 phil 851: }
1.3 phil 852: splx(s);
1.4 phil 853: sc->sc_ifierrs = 0;
1.1 phil 854: ifp->if_ipackets++;
1.3 phil 855: i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE;
1.1 phil 856: return;
857:
858: err:
859: i8255->port_b = 0x00;
860:
1.4 phil 861: if (sc->sc_ifierrs < PLIPMXERRS) {
862: i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE;
863: } else {
1.23 matthias 864: /*
865: * We are not able to send or receive anything for now,
1.1 phil 866: * so stop wasting our time and leave the interrupt
867: * disabled.
868: */
1.4 phil 869: if (sc->sc_ifierrs == PLIPMXERRS)
1.9 thorpej 870: log(LOG_NOTICE, "%s: rx hard error\n", ifp->if_xname);
1.3 phil 871: i8255->port_a |= LPA_ACTIVE;
1.23 matthias 872: /* But we will retry from time to time. */
1.31 thorpej 873: callout_reset(&sc->sc_pliprx_ch, PLIPRETRY * 10,
874: pliprxenable, sc);
1.4 phil 875: }
876: ifp->if_ierrors++;
877: sc->sc_ifierrs++;
1.1 phil 878: return;
879: }
880:
1.13 matthias 881: #ifdef __OPTIMIZE__
1.23 matthias 882: int pliptransmit __P((volatile struct i8255 *, u_char *, int))
883: __asm("pliptransmit");
1.41 ! chs 884: __asm(" \
! 885: pliptransmit: \
! 886: enter [r3,r4,r5,r6,r7],0 ; \
! 887: movqd 0,r0 ; \
! 888: movd 8(fp),r1 ; \
! 889: movd 12(fp),r2 ; \
! 890: movd 16(fp),r3 ; \
! 891: cmpqd 0,r3 ; \
! 892: beq 5f ; \
! 893: \
! 894: movqd 0,r7 ; \
! 895: movd 50000,r4 ; \
! 896: \
! 897: .align 2,0xa2 ; \
! 898: 0: movb 8,r5 ; \
! 899: 1: movb 2(r1),r6 ; \
! 900: bicb r6,r5 ; \
! 901: cmpqb 0,r5 ; \
! 902: beq 2f ; \
! 903: acbd -1,r4,1b ; \
! 904: br 6f ; \
! 905: \
! 906: .align 2,0xa2 ; \
! 907: 2: movb 0(r2),r7 ; \
! 908: movb 0x0f,r5 ; \
! 909: andb r7,r5 ; \
! 910: addqd 1,r2 ; \
! 911: movb r5,1(r1) ; \
! 912: orb 0x10,r5 ; \
! 913: movb r5,1(r1) ; \
! 914: \
! 915: movb 8,r5 ; \
! 916: 3: movb 2(r1),r6 ; \
! 917: andb r6,r5 ; \
! 918: cmpqb 0,r5 ; \
! 919: beq 4f ; \
! 920: acbd -1,r4,3b ; \
! 921: br 6f ; \
! 922: \
! 923: .align 2,0xa2 ; \
! 924: 4: addd r7,r0 ; \
! 925: lshb -4,r7 ; \
! 926: movb 0x10,r5 ; \
! 927: orb r7,r5 ; \
! 928: movb r5,1(r1) ; \
! 929: movb r7,1(r1) ; \
! 930: acbd -1,r3,0b ; \
! 931: \
! 932: andd 0xff,r0 ; \
! 933: 5: exit [r3,r4,r5,r6,r7] ; \
! 934: ret 0 ; \
! 935: \
! 936: 6: movqd -1,r0 ; \
! 937: exit [r3,r4,r5,r6,r7] ; \
! 938: ret 0 \
1.13 matthias 939: ");
940: #else
1.1 phil 941: static int
1.33 matthias 942: pliptransmit(i8255, buf, len)
1.13 matthias 943: volatile struct i8255 *i8255;
944: u_char *buf;
945: int len;
1.1 phil 946: {
947: int i;
948: u_char cksum = 0, c;
949:
950: while (len--) {
1.3 phil 951: i = PLIPMXSPIN2;
1.1 phil 952: cksum += (c = *buf++);
1.3 phil 953: while ((i8255->port_c & LPC_NBUSY) == 0)
954: if (i-- < 0) return -1;
1.1 phil 955: i8255->port_b = c & 0x0f;
956: i8255->port_b = c & 0x0f | 0x10;
957: c >>= 4;
1.3 phil 958: while ((i8255->port_c & LPC_NBUSY) != 0)
959: if (i-- < 0) return -1;
960: i8255->port_b = c | 0x10;
961: i8255->port_b = c;
1.1 phil 962: }
963: return(cksum);
964: }
1.13 matthias 965: #endif
1.1 phil 966:
967: /*
968: * Setup output on interface.
969: */
1.3 phil 970: static void
1.13 matthias 971: plipstart(ifp)
972: struct ifnet *ifp;
1.1 phil 973: {
1.9 thorpej 974: struct lpt_softc *sc = (struct lpt_softc *)(ifp->if_softc);
1.6 phil 975: sc->sc_pending |= PLIP_OPENDING;
976: softintr(sc->sc_ifsoftint);
977: }
978:
979: static void
1.16 matthias 980: plipoutput(arg)
981: void *arg;
1.6 phil 982: {
1.16 matthias 983: struct lpt_softc *sc = arg;
1.19 is 984: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.1 phil 985: volatile struct i8255 *i8255 = sc->sc_i8255;
986: struct mbuf *m0, *m;
1.3 phil 987: u_char minibuf[4], cksum;
1.1 phil 988: int len, i, s;
989:
1.3 phil 990: if (ifp->if_flags & IFF_OACTIVE)
1.1 phil 991: return;
992: ifp->if_flags |= IFF_OACTIVE;
993:
1.4 phil 994: if (sc->sc_ifoerrs)
1.31 thorpej 995: callout_stop(&sc->sc_plipout_ch);
1.1 phil 996:
997: for (;;) {
1.34 thorpej 998: s = splnet();
1.1 phil 999: IF_DEQUEUE(&ifp->if_snd, m0);
1.3 phil 1000: splx(s);
1.1 phil 1001: if (!m0)
1002: break;
1003:
1.13 matthias 1004: #if NBPFILTER > 0
1005: if (ifp->if_bpf)
1006: bpf_mtap(ifp->if_bpf, m0);
1007: #endif
1008:
1009: len = m0->m_pkthdr.len;
1010:
1.3 phil 1011: #if defined(COMPAT_PLIP10)
1.1 phil 1012: if (ifp->if_flags & IFF_LINK0) {
1013: minibuf[0] = 3;
1014: minibuf[1] = 0xfd;
1015: minibuf[2] = len >> 8;
1016: minibuf[3] = len;
1.3 phil 1017: } else
1018: #endif
1019: {
1.1 phil 1020: minibuf[0] = 2;
1021: minibuf[1] = len;
1022: minibuf[2] = len >> 8;
1023: }
1024:
1025: /* Trigger remote interrupt */
1.6 phil 1026: i = PLIPMXSPIN1;
1027: do {
1028: if (sc->sc_pending & PLIP_IPENDING) {
1029: i8255->port_b = 0x00;
1030: sc->sc_pending = 0;
1031: plipinput(sc);
1032: i = PLIPMXSPIN1;
1033: } else if (i-- < 0)
1.1 phil 1034: goto retry;
1.6 phil 1035: /* Retrigger remote interrupt */
1036: i8255->port_b = 0x08;
1037: } while ((i8255->port_c & LPC_NERROR) == 0);
1038: i8255->port_a &= ~(LPA_ACKENABLE | LPA_ACTIVE);
1.1 phil 1039:
1040: if (pliptransmit(i8255, minibuf + 1, minibuf[0]) < 0) goto retry;
1041: for (cksum = 0, m = m0; m; m = m->m_next) {
1042: i = pliptransmit(i8255, mtod(m, u_char *), m->m_len);
1043: if (i < 0) goto retry;
1044: cksum += i;
1045: }
1046: if (pliptransmit(i8255, &cksum, 1) < 0) goto retry;
1.3 phil 1047: i = PLIPMXSPIN2;
1048: while ((i8255->port_c & LPC_NBUSY) == 0)
1049: if (i-- < 0) goto retry;
1.1 phil 1050: i8255->port_b = 0x00;
1.3 phil 1051:
1052: ifp->if_opackets++;
1053: ifp->if_obytes += len + 4;
1.4 phil 1054: sc->sc_ifoerrs = 0;
1.1 phil 1055: m_freem(m0);
1056: i8255->port_a |= LPA_ACKENABLE;
1057: }
1.3 phil 1058: i8255->port_a |= LPA_ACTIVE;
1.1 phil 1059: ifp->if_flags &= ~IFF_OACTIVE;
1.3 phil 1060: return;
1.1 phil 1061:
1062: retry:
1063: if (i8255->port_c & LPC_NACK)
1064: ifp->if_collisions++;
1065: else
1066: ifp->if_oerrors++;
1.6 phil 1067:
1068: ifp->if_flags &= ~IFF_OACTIVE;
1069: i8255->port_b = 0x00;
1070:
1.1 phil 1071: if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == (IFF_RUNNING | IFF_UP)
1.4 phil 1072: && sc->sc_ifoerrs < PLIPMXRETRY) {
1.34 thorpej 1073: s = splnet();
1.1 phil 1074: IF_PREPEND(&ifp->if_snd, m0);
1.3 phil 1075: splx(s);
1.31 thorpej 1076: callout_reset(&sc->sc_plipout_ch, PLIPRETRY, plipoutput, sc);
1.1 phil 1077: } else {
1.4 phil 1078: if (sc->sc_ifoerrs == PLIPMXRETRY) {
1.9 thorpej 1079: log(LOG_NOTICE, "%s: tx hard error\n", ifp->if_xname);
1.3 phil 1080: }
1.1 phil 1081: m_freem(m0);
1082: }
1.23 matthias 1083: i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE;
1.4 phil 1084: sc->sc_ifoerrs++;
1.1 phil 1085: }
1086:
1087: #endif
CVSweb <webmaster@jp.NetBSD.org>