1 /**	$MirOS: src/sys/dev/ic/lpt.c,v 1.3 2005/07/04 01:39:08 tg Exp $	*/
2 /*	$OpenBSD: lpt.c,v 1.5 2002/03/14 01:26:54 millert Exp $ */
3 /*	$NetBSD: lpt.c,v 1.42 1996/10/21 22:41:14 thorpej Exp $	*/
4 
5 /*
6  * Copyright (c) 2003, 2005 Thorsten Glaser <tg@MirBSD.org>
7  * Copyright (c) 1994 Matthias Pfaller.
8  * Copyright (c) 1994 Poul-Henning Kamp.
9  * Copyright (c) 1993, 1994 Charles Hannum.
10  * Copyright (c) 1990 William F. Jolitz, TeleMuse
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This software is a component of "386BSD" developed by
24  *	William F. Jolitz, TeleMuse.
25  * 4. Neither the name of the developer nor the name "386BSD"
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
30  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
31  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
32  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
33  * NOT MAKE USE OF THIS WORK.
34  *
35  * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
36  * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
37  * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
38  * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
39  * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
40  * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
41  * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
42  * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
45  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
48  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  */
56 
57 /*
58  * Device Driver for AT parallel printer port
59  */
60 
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/proc.h>
64 #include <sys/user.h>
65 #include <sys/buf.h>
66 #include <sys/kernel.h>
67 #include <sys/ioctl.h>
68 #include <sys/uio.h>
69 #include <sys/device.h>
70 #include <sys/conf.h>
71 #include <sys/syslog.h>
72 
73 #include <machine/bus.h>
74 #include <machine/intr.h>
75 
76 #if defined(INET) && defined(PLIP)
77 #include "bpfilter.h"
78 #include <sys/mbuf.h>
79 #include <sys/socket.h>
80 
81 #include <net/if.h>
82 #include <net/if_dl.h>
83 #include <net/if_types.h>
84 #ifdef	__NetBSD__
85 #include <net/if_ether.h>
86 #endif
87 #include <net/netisr.h>
88 
89 #include <netinet/in.h>
90 #include <netinet/in_systm.h>
91 #include <netinet/in_var.h>
92 #include <netinet/ip.h>
93 #ifdef	__NetBSD__
94 #include <netinet/if_inarp.h>
95 #else
96 #include <netinet/if_ether.h>
97 #endif
98 #if NBPFILTER > 0
99 #include <sys/time.h>
100 #include <net/bpf.h>
101 #endif
102 #endif
103 
104 #include <dev/ic/lptreg.h>
105 #include <dev/ic/lptvar.h>
106 
107 #include "lpt.h"
108 
109 #define	TIMEOUT		hz*16	/* wait up to 16 seconds for a ready */
110 #define	STEP		hz/4
111 
112 #define	LPTPRI		(PZERO+8)
113 #define	LPT_BSIZE	1024
114 
115 #if !defined(DEBUG) || !defined(notdef)
116 #define LPRINTF(a)
117 #else
118 #define LPRINTF(a)	if (lptdebug) printf a
119 int lptdebug = 1;
120 #endif
121 
122 #if defined(INET) && defined(PLIP)
123 
124 #define PLIPMTU		ETHERMTU
125 
126 #ifndef PLIPMXSPIN1		/* DELAY factor for the plip# interfaces */
127 #define	PLIPMXSPIN1	50000	/* Spinning for remote intr to happen */
128 #endif
129 
130 #ifndef PLIPMXSPIN2		/* DELAY factor for the plip# interfaces */
131 #define	PLIPMXSPIN2	50000	/* Spinning for remote handshake to happen */
132 #endif
133 
134 #ifndef PLIPMXERRS		/* Max errors before !RUNNING */
135 #define	PLIPMXERRS	50
136 #endif
137 #ifndef PLIPMXRETRY
138 #define PLIPMXRETRY	20	/* Max number of retransmits */
139 #endif
140 #ifndef PLIPRETRY
141 #define PLIPRETRY	hz/50	/* Time between retransmits */
142 #endif
143 
144 #define STABILIZE(iot, ioh, io) ({ \
145 		int v1, v2; \
146 		v2 = bus_space_read_1(iot, ioh, io); \
147 		do { \
148 			v1 = v2; \
149 			v2 = bus_space_read_1(iot, ioh, io); \
150 		} while (v1 != v2); \
151 		v2; \
152 	})
153 #endif
154 
155 #if defined(INET) && defined(PLIP)
156 /* Functions for the plip# interface */
157 static void	plipattach(struct lpt_softc *);
158 static void	plipinput(struct lpt_softc *);
159 static int	plipioctl(struct ifnet *, u_long, caddr_t);
160 static void	plipoutput(void *);
161 static int	plipreceive(struct lpt_softc *, u_char *, int);
162 static void	pliprxenable(void *);
163 void		plipsoftint(void);
164 static void	plipstart(struct ifnet *);
165 static int	pliptransmit(struct lpt_softc *, u_char *, int);
166 #endif
167 
168 /* XXX does not belong here */
169 cdev_decl(lpt);
170 
171 struct cfdriver lpt_cd = {
172 	NULL, "lpt", DV_TTY
173 };
174 
175 #define	LPTUNIT(s)	(minor(s) & 0x1f)
176 #define	LPTFLAGS(s)	(minor(s) & 0xe0)
177 
178 #define	LPS_INVERT	(LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK)
179 #define	LPS_MASK	(LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER)
180 #define	NOT_READY() \
181     ((bus_space_read_1(iot, ioh, lpt_status) ^ LPS_INVERT) & LPS_MASK)
182 #define	NOT_READY_ERR() \
183     lpt_not_ready(bus_space_read_1(iot, ioh, lpt_status), sc)
184 
185 int	lpt_not_ready(u_int8_t, struct lpt_softc *);
186 void	lptwakeup(void *arg);
187 int	lptpushbytes(struct lpt_softc *);
188 
189 /*
190  * Internal routine to lptprobe to do port tests of one byte value.
191  */
192 int
lpt_port_test(iot,ioh,base,off,data,mask)193 lpt_port_test(iot, ioh, base, off, data, mask)
194 	bus_space_tag_t iot;
195 	bus_space_handle_t ioh;
196 	bus_addr_t base;
197 	bus_size_t off;
198 	u_int8_t data, mask;
199 {
200 	int timeout;
201 	u_int8_t temp;
202 
203 	data &= mask;
204 	bus_space_write_1(iot, ioh, off, data);
205 	timeout = 1000;
206 	do {
207 		delay(10);
208 		temp = bus_space_read_1(iot, ioh, off) & mask;
209 	} while (temp != data && --timeout);
210 	LPRINTF(("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n", base + off,
211 	    data, temp, timeout));
212 	return (temp == data);
213 }
214 
215 void
lpt_attach_common(sc)216 lpt_attach_common(sc)
217 	struct lpt_softc *sc;
218 {
219 	printf("\n");
220 
221 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, lpt_control, LPC_NINIT);
222 
223 #if defined(INET) && defined(PLIP)
224 	plipattach(sc);
225 #endif
226 
227 	timeout_set(&sc->sc_wakeup_tmo, lptwakeup, sc);
228 }
229 
230 /*
231  * Reset the printer, then wait until it's selected and not busy.
232  */
233 int
lptopen(dev,flag,mode,p)234 lptopen(dev, flag, mode, p)
235 	dev_t dev;
236 	int flag;
237 	int mode;
238 	struct proc *p;
239 {
240 	int unit = LPTUNIT(dev);
241 	u_int8_t flags = LPTFLAGS(dev);
242 	struct lpt_softc *sc;
243 	bus_space_tag_t iot;
244 	bus_space_handle_t ioh;
245 	u_int8_t control;
246 	int error;
247 	int spin;
248 
249 	if (unit >= lpt_cd.cd_ndevs)
250 		return ENXIO;
251 	sc = lpt_cd.cd_devs[unit];
252 	if (!sc)
253 		return ENXIO;
254 
255 	sc->sc_flags = (sc->sc_flags & LPT_POLLED) | flags;
256 	if ((sc->sc_flags & (LPT_POLLED|LPT_NOINTR)) == LPT_POLLED)
257 		return ENXIO;
258 
259 #ifdef DIAGNOSTIC
260 	if (sc->sc_state)
261 		printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname,
262 		    sc->sc_state);
263 #endif
264 
265 	if (sc->sc_state)
266 		return EBUSY;
267 
268 #if defined(INET) && defined(PLIP)
269 #ifdef	__NetBSD__
270 	if (sc->sc_ethercom.ec_if.if_flags & IFF_UP)
271 #else
272 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP)
273 #endif
274 	    return EBUSY;
275 #endif
276 
277 	sc->sc_state = LPT_INIT;
278 	LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags));
279 	iot = sc->sc_iot;
280 	ioh = sc->sc_ioh;
281 
282 	if ((flags & LPT_NOPRIME) == 0) {
283 		/* assert INIT for 100 usec to start up printer */
284 		bus_space_write_1(iot, ioh, lpt_control, LPC_SELECT);
285 		delay(100);
286 	}
287 
288 	control = LPC_SELECT | LPC_NINIT;
289 	bus_space_write_1(iot, ioh, lpt_control, control);
290 
291 	/* wait till ready (printer running diagnostics) */
292 	for (spin = 0; NOT_READY_ERR(); spin += STEP) {
293 		if (spin >= TIMEOUT) {
294 			sc->sc_state = 0;
295 			return EBUSY;
296 		}
297 
298 		/* wait 1/4 second, give up if we get a signal */
299 		error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP);
300 		if (error != EWOULDBLOCK) {
301 			sc->sc_state = 0;
302 			return error;
303 		}
304 	}
305 
306 	if ((flags & LPT_NOINTR) == 0)
307 		control |= LPC_IENABLE;
308 	if (flags & LPT_AUTOLF)
309 		control |= LPC_AUTOLF;
310 	sc->sc_control = control;
311 	bus_space_write_1(iot, ioh, lpt_control, control);
312 
313 	sc->sc_inbuf = geteblk(LPT_BSIZE);
314 	sc->sc_count = 0;
315 	sc->sc_state = LPT_OPEN;
316 
317 	if ((sc->sc_flags & LPT_NOINTR) == 0)
318 		lptwakeup(sc);
319 
320 	LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname));
321 	return 0;
322 }
323 
324 int
lpt_not_ready(status,sc)325 lpt_not_ready(status, sc)
326 	u_int8_t status;
327 	struct lpt_softc *sc;
328 {
329 	u_int8_t new;
330 
331 	status = (status ^ LPS_INVERT) & LPS_MASK;
332 	new = status & ~sc->sc_laststatus;
333 	sc->sc_laststatus = status;
334 
335 	if (new & LPS_SELECT)
336 		log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
337 	else if (new & LPS_NOPAPER)
338 		log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
339 	else if (new & LPS_NERR)
340 		log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
341 
342 	return status;
343 }
344 
345 void
lptwakeup(arg)346 lptwakeup(arg)
347 	void *arg;
348 {
349 	struct lpt_softc *sc = arg;
350 	int s;
351 
352 	s = spltty();
353 	lptintr(sc);
354 	splx(s);
355 
356 	timeout_add(&sc->sc_wakeup_tmo, STEP);
357 }
358 
359 /*
360  * Close the device, and free the local line buffer.
361  */
362 int
lptclose(dev,flag,mode,p)363 lptclose(dev, flag, mode, p)
364 	dev_t dev;
365 	int flag;
366 	int mode;
367 	struct proc *p;
368 {
369 	int unit = LPTUNIT(dev);
370 	struct lpt_softc *sc = lpt_cd.cd_devs[unit];
371 	bus_space_tag_t iot = sc->sc_iot;
372 	bus_space_handle_t ioh = sc->sc_ioh;
373 
374 	if (sc->sc_count)
375 		(void) lptpushbytes(sc);
376 
377 	if ((sc->sc_flags & LPT_NOINTR) == 0)
378 		timeout_del(&sc->sc_wakeup_tmo);
379 
380 	bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
381 	sc->sc_state = 0;
382 	bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
383 	brelse(sc->sc_inbuf);
384 
385 	LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname));
386 	return 0;
387 }
388 
389 int
lptpushbytes(sc)390 lptpushbytes(sc)
391 	struct lpt_softc *sc;
392 {
393 	bus_space_tag_t iot = sc->sc_iot;
394 	bus_space_handle_t ioh = sc->sc_ioh;
395 	int error;
396 
397 	if (sc->sc_flags & LPT_NOINTR) {
398 		int spin, tic;
399 		u_int8_t control = sc->sc_control;
400 
401 		while (sc->sc_count > 0) {
402 			spin = 0;
403 			while (NOT_READY()) {
404 				if (++spin < sc->sc_spinmax)
405 					continue;
406 				tic = 0;
407 				/* adapt busy-wait algorithm */
408 				sc->sc_spinmax++;
409 				while (NOT_READY_ERR()) {
410 					/* exponential backoff */
411 					tic = tic + tic + 1;
412 					if (tic > TIMEOUT)
413 						tic = TIMEOUT;
414 					error = tsleep((caddr_t)sc,
415 					    LPTPRI | PCATCH, "lptpsh", tic);
416 					if (error != EWOULDBLOCK)
417 						return error;
418 				}
419 				break;
420 			}
421 
422 			bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++);
423 			bus_space_write_1(iot, ioh, lpt_control,
424 			    control | LPC_STROBE);
425 			sc->sc_count--;
426 			bus_space_write_1(iot, ioh, lpt_control, control);
427 
428 			/* adapt busy-wait algorithm */
429 			if (spin*2 + 16 < sc->sc_spinmax)
430 				sc->sc_spinmax--;
431 		}
432 	} else {
433 		int s;
434 
435 		while (sc->sc_count > 0) {
436 			/* if the printer is ready for a char, give it one */
437 			if ((sc->sc_state & LPT_OBUSY) == 0) {
438 				LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname,
439 				    sc->sc_count));
440 				s = spltty();
441 				(void) lptintr(sc);
442 				splx(s);
443 			}
444 			error = tsleep((caddr_t)sc, LPTPRI | PCATCH,
445 			    "lptwrite2", 0);
446 			if (error)
447 				return error;
448 		}
449 	}
450 	return 0;
451 }
452 
453 /*
454  * Copy a line from user space to a local buffer, then call putc to get the
455  * chars moved to the output queue.
456  */
457 int
lptwrite(dev,uio,flags)458 lptwrite(dev, uio, flags)
459 	dev_t dev;
460 	struct uio *uio;
461 	int flags;
462 {
463 	struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)];
464 	size_t n;
465 	int error = 0;
466 
467 	while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) {
468 		uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
469 		sc->sc_count = n;
470 		error = lptpushbytes(sc);
471 		if (error) {
472 			/*
473 			 * Return accurate residual if interrupted or timed
474 			 * out.
475 			 */
476 			uio->uio_resid += sc->sc_count;
477 			sc->sc_count = 0;
478 			return error;
479 		}
480 	}
481 	return 0;
482 }
483 
484 /*
485  * Handle printer interrupts which occur when the printer is ready to accept
486  * another char.
487  */
488 int
lptintr(arg)489 lptintr(arg)
490 	void *arg;
491 {
492 	struct lpt_softc *sc = arg;
493 	bus_space_tag_t iot = sc->sc_iot;
494 	bus_space_handle_t ioh = sc->sc_ioh;
495 
496 	if (((sc->sc_state & LPT_OPEN) == 0 && sc->sc_count == 0) ||
497 	    (sc->sc_flags & LPT_NOINTR))
498 		return 0;
499 
500 #if defined(INET) && defined(PLIP)
501 #ifdef	__NetBSD__
502 	if (sc->sc_ethercom.ec_if.if_flags & IFF_UP) {
503 #else
504 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) {
505 #endif
506 		if ((sc->sc_control & LPC_IENABLE) == 0)
507 			return 0;	/* dispose spurious interrupt */
508 
509 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control &= ~LPC_IENABLE);
510 		sc->sc_pending |= PLIP_IPENDING;
511 		/*softintr(sc->sc_ifsoftint);*/
512 		schednetisr(NETISR_PLIP);
513 		return 0;
514 	}
515 #endif
516 	/* is printer online and ready for output */
517 	if (NOT_READY() && NOT_READY_ERR())
518 		return -1;
519 
520 	if (sc->sc_count) {
521 		u_int8_t control = sc->sc_control;
522 		/* send char */
523 		bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++);
524 		delay (50);
525 		bus_space_write_1(iot, ioh, lpt_control, control | LPC_STROBE);
526 		sc->sc_count--;
527 		bus_space_write_1(iot, ioh, lpt_control, control);
528 		sc->sc_state |= LPT_OBUSY;
529 	} else
530 		sc->sc_state &= ~LPT_OBUSY;
531 
532 	if (sc->sc_count == 0) {
533 		/* none, wake up the top half to get more */
534 		wakeup((caddr_t)sc);
535 	}
536 
537 	return 1;
538 }
539 
540 int
lptioctl(dev,cmd,data,flag,p)541 lptioctl(dev, cmd, data, flag, p)
542 	dev_t dev;
543 	u_long cmd;
544 	caddr_t data;
545 	int flag;
546 	struct proc *p;
547 {
548 	int error = 0;
549 
550 	switch (cmd) {
551 	default:
552 		error = ENODEV;
553 	}
554 
555 	return error;
556 }
557 
558 #if defined(INET) && defined(PLIP)
559 static void
plipattach(struct lpt_softc * sc)560 plipattach(struct lpt_softc *sc)
561 {
562 #ifdef	__NetBSD__
563 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
564 #else
565 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
566 #endif
567 	u_int8_t myaddr[ETHER_ADDR_LEN];
568 
569 	sc->sc_ifbuf = NULL;
570 	snprintf(ifp->if_xname, sizeof ifp->if_xname,
571 	    "plip%d", sc->sc_dev.dv_unit);
572 	bzero(myaddr, sizeof(myaddr));
573 	ifp->if_softc = sc;
574 	ifp->if_start = plipstart;
575 	ifp->if_ioctl = plipioctl;
576 	ifp->if_watchdog = 0;
577 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
578 	bzero(&sc->sc_pliptimeout, sizeof(struct timeout));
579 
580 	if_attach(ifp);
581 	ether_ifattach(ifp);
582 	ifp->if_mtu = PLIPMTU;
583 
584 #if NBPFILTER > 0
585 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
586 #endif
587 	/*
588 	 * We hope to get Charle's MI softint establish RSN - the
589 	 * current hack involves patching icu.s and hardcoding
590 	 * the softinterupts in a complete unrelated peace
591 	 * of code....
592 	sc->sc_ifsoftint = isa_intr_establish(SOFTINT, 0, ISA_IPL_NET,
593 				plipsoftint, sc);
594 	 */
595 }
596 
597 /*
598  * Process an ioctl request.
599  */
600 static int
plipioctl(struct ifnet * ifp,u_long cmd,caddr_t data)601 plipioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
602 {
603 	struct proc *p = curproc;
604 	struct lpt_softc *sc = (struct lpt_softc *) ifp->if_softc;
605 	u_char control = sc->sc_control;
606 	struct ifaddr *ifa = (struct ifaddr *)data;
607 	struct ifreq *ifr = (struct ifreq *)data;
608 	bus_space_tag_t iot = sc->sc_iot;
609 	bus_space_handle_t ioh = sc->sc_ioh;
610 	struct sockaddr_dl *sdl;
611 	int error = 0;
612 
613 	switch (cmd) {
614 	case SIOCSIFFLAGS:
615 		if (((ifp->if_flags & IFF_UP) == 0) &&
616 		    (ifp->if_flags & IFF_RUNNING)) {
617 		        ifp->if_flags &= ~IFF_RUNNING;
618 			control = LPC_SELECT | LPC_NINIT;
619 			bus_space_write_1(iot, ioh, lpt_control, control);
620 
621 			if (sc->sc_ifbuf)
622 				free(sc->sc_ifbuf, M_DEVBUF);
623 			sc->sc_ifbuf = NULL;
624 		}
625 		if (((ifp->if_flags & IFF_UP)) &&
626 		    ((ifp->if_flags & IFF_RUNNING) == 0)) {
627 			if (sc->sc_state) {
628 				error = EBUSY;
629 				break;
630 			}
631 			if (sc->sc_ih == 0) {
632 				error = EINVAL;
633 				break;
634 			}
635 			if (!sc->sc_ifbuf)
636 				sc->sc_ifbuf =
637 					malloc(ifp->if_mtu + ifp->if_hdrlen,
638 					       M_DEVBUF, M_WAITOK);
639 		        ifp->if_flags |= IFF_RUNNING;
640 			bus_space_write_1(iot, ioh, lpt_control, control & ~LPC_IENABLE);
641 			bus_space_write_1(iot, ioh, lpt_data, 0);
642 			bus_space_write_1(iot, ioh, lpt_control, control |= LPC_IENABLE);
643 		}
644 		break;
645 
646 	case SIOCSIFADDR:
647 		sdl = ifp->if_sadl;
648 		if (ifa->ifa_addr->sa_family == AF_INET) {
649 			if (!sc->sc_ifbuf)
650 				sc->sc_ifbuf =
651 					malloc(PLIPMTU + ifp->if_hdrlen,
652 					       M_DEVBUF, M_WAITOK);
653 			LLADDR(sdl)[0] = 0xfc;
654 			LLADDR(sdl)[1] = 0xfc;
655 			bcopy((caddr_t)&IA_SIN(ifa)->sin_addr,
656 			      (caddr_t)&LLADDR(sdl)[2], 4);
657 			ifp->if_flags |= IFF_RUNNING | IFF_UP;
658 			bus_space_write_1(iot, ioh, lpt_control, control & ~LPC_IENABLE);
659 			bus_space_write_1(iot, ioh, lpt_data, 0);
660 			bus_space_write_1(iot, ioh, lpt_control, control |= LPC_IENABLE);
661 			arp_ifinit(&sc->sc_arpcom, ifa);
662 		} else
663 			error = EAFNOSUPPORT;
664 		break;
665 
666 	case SIOCAIFADDR:
667 	case SIOCDIFADDR:
668 	case SIOCSIFDSTADDR:
669 		if (ifa->ifa_addr->sa_family != AF_INET)
670 			error = EAFNOSUPPORT;
671 		break;
672 
673 	case SIOCSIFMTU:
674         	if ((error = suser(p, 0)))
675             		return(error);
676 		if (ifp->if_mtu != ifr->ifr_metric) {
677 		        ifp->if_mtu = ifr->ifr_metric;
678 			if (sc->sc_ifbuf) {
679 				free(sc->sc_ifbuf, M_DEVBUF);
680 				sc->sc_ifbuf =
681 					malloc(ifp->if_mtu + ifp->if_hdrlen,
682 					       M_DEVBUF, M_WAITOK);
683 			}
684 		}
685 		break;
686 
687 	default:
688 		error = EINVAL;
689 	}
690 	sc->sc_control = control;
691 	return (error);
692 }
693 
694 void
plipsoftint(void)695 plipsoftint(void)
696 {
697 	/* while the MI softint framework isn't there, we check
698 	   check all lpt devices */
699 	struct device *dev;
700 
701 	for (dev = alldevs.tqh_first; dev; dev = dev->dv_list.tqe_next) {
702 		if (dev->dv_cfdata->cf_driver == &lpt_cd) {
703 			int pending;
704 			struct lpt_softc *sc = (struct lpt_softc*)dev;
705 
706 			pending = sc->sc_pending;
707 			while (sc->sc_pending & PLIP_IPENDING) {
708 				pending |= sc->sc_pending;
709 				sc->sc_pending = 0;
710 				plipinput(sc);
711 			}
712 
713 			if (pending & PLIP_OPENDING)
714 				plipoutput(sc);
715 		}
716 	}
717 }
718 
719 static int
plipreceive(struct lpt_softc * sc,u_char * buf,int len)720 plipreceive(struct lpt_softc *sc, u_char *buf, int len)
721 {
722 	bus_space_tag_t iot = sc->sc_iot;
723 	bus_space_handle_t ioh = sc->sc_ioh;
724 	int i;
725 	u_char cksum = 0, cl, ch;
726 
727 	while (len--) {
728 		i = PLIPMXSPIN2;
729 		while (((cl = STABILIZE(iot, ioh, lpt_status)) & LPS_NBSY) != 0)
730 			if (i-- < 0) return -1;
731 		cl = (cl >> 3) & 0x0f;
732 		bus_space_write_1(iot, ioh, lpt_data, 0x11);
733 		while (((ch = STABILIZE(iot, ioh, lpt_status)) & LPS_NBSY) == 0)
734 			if (i-- < 0) return -1;
735 		cl |= (ch << 1) & 0xf0;
736 		bus_space_write_1(iot, ioh, lpt_data, 0x01);
737 		cksum += (*buf++ = cl);
738 	}
739 	return(cksum);
740 }
741 
742 static void
pliprxenable(void * arg)743 pliprxenable(void *arg)
744 {
745 	struct lpt_softc *sc = arg;
746 	bus_space_tag_t iot = sc->sc_iot;
747 	bus_space_handle_t ioh = sc->sc_ioh;
748 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
749 }
750 
751 static void
plipinput(struct lpt_softc * sc)752 plipinput(struct lpt_softc *sc)
753 {
754 #ifdef	__NetBSD__
755 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
756 #else
757 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
758 #endif
759 	bus_space_tag_t iot = sc->sc_iot;
760 	bus_space_handle_t ioh = sc->sc_ioh;
761 	struct mbuf *m;
762 	struct ether_header *eh;
763 	u_char *p = sc->sc_ifbuf, minibuf[4];
764 	int s, len, cksum;
765 
766 	if (((ifp->if_flags & IFF_LINK2) == 0) &&
767 	    (!(STABILIZE(iot, ioh, lpt_status) & LPS_NACK))) {
768 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
769 		ifp->if_collisions++;
770 		return;
771 	}
772 
773 	bus_space_write_1(iot, ioh, lpt_data, 0x01);
774 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control &= ~LPC_IENABLE);
775 
776 	if (sc->sc_ifierrs)
777 		timeout_del(&sc->sc_pliptimeout);
778 
779 	if (plipreceive(sc, minibuf, 2) < 0) goto err;
780 	len = (minibuf[1] << 8) | minibuf[0];
781 	if (len > (ifp->if_mtu + ifp->if_hdrlen)) {
782 		log(LOG_NOTICE, "%s: packet > MTU\n", ifp->if_xname);
783 		goto err;
784 	}
785 	if ((cksum = plipreceive(sc, p, len)) < 0) goto err;
786 
787 	if (plipreceive(sc, minibuf, 1) < 0) goto err;
788 	if (cksum != minibuf[0]) {
789 		log(LOG_NOTICE, "%s: checksum error\n", ifp->if_xname);
790 		goto err;
791 	}
792 	bus_space_write_1(iot, ioh, lpt_data, 0x00);
793 
794 	s = splimp();
795 	if ((m = m_devget(sc->sc_ifbuf, len, 0, ifp, NULL)) != NULL) {
796 		/* We assume that the header fit entirely in one mbuf. */
797 		eh = mtod(m, struct ether_header *);
798 #if NBPFILTER > 0
799 		/*
800 		 * Check if there's a BPF listener on this interface.
801 		 * If so, hand off the raw packet to bpf.
802 		 */
803 		if (ifp->if_bpf) {
804 			bpf_mtap(ifp->if_bpf, m);
805 		}
806 #endif
807 		/* We assume the header fit entirely in one mbuf. */
808 		m_adj(m, sizeof(struct ether_header));
809 		ether_input_mbuf(ifp, m);
810 	}
811 	splx(s);
812 	sc->sc_ifierrs = 0;
813 	ifp->if_ipackets++;
814 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
815 	return;
816 
817 err:
818 	bus_space_write_1(iot, ioh, lpt_data, 0x00);
819 
820 	if (sc->sc_ifierrs < PLIPMXERRS) {
821 		if (sc->sc_ifierrs > 4 && (STABILIZE(iot, ioh, lpt_status) & LPS_NBSY)) {
822 			/* Avoid interrupt nesting ... */
823 			sc->sc_ifierrs = PLIPMXERRS - 1;
824 		}
825 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
826 	} else {
827 		/* We are not able to send or receive anything for now,
828 		 * so stop wasting our time and leave the interrupt
829 		 * disabled.
830 		 */
831 		if (sc->sc_ifierrs == PLIPMXERRS)
832 			log(LOG_NOTICE, "%s: rx hard error\n", ifp->if_xname);
833 		/* But we will retry from time to time. */
834 		timeout_set(&sc->sc_pliptimeout, pliprxenable, sc);
835 		timeout_add(&sc->sc_pliptimeout, PLIPRETRY * 10);
836 	}
837 	ifp->if_ierrors++;
838 	sc->sc_ifierrs++;
839 	return;
840 }
841 
842 static int
pliptransmit(struct lpt_softc * sc,u_char * buf,int len)843 pliptransmit(struct lpt_softc *sc, u_char *buf, int len)
844 {
845 	bus_space_tag_t iot = sc->sc_iot;
846 	bus_space_handle_t ioh = sc->sc_ioh;
847 	int i;
848 	u_char cksum = 0, c;
849 
850 	while (len--) {
851 		i = PLIPMXSPIN2;
852 		cksum += (c = *buf++);
853 		while ((STABILIZE(iot, ioh, lpt_status) & LPS_NBSY) == 0)
854 			if (i-- < 0) return -1;
855 		bus_space_write_1(iot, ioh, lpt_data, c & 0x0f);
856 		bus_space_write_1(iot, ioh, lpt_data, (c & 0x0f) | 0x10);
857 		c >>= 4;
858 		while ((STABILIZE(iot, ioh, lpt_status) & LPS_NBSY) != 0)
859 			if (i-- < 0) return -1;
860 		bus_space_write_1(iot, ioh, lpt_data, c | 0x10);
861 		bus_space_write_1(iot, ioh, lpt_data, c);
862 	}
863 	return(cksum);
864 }
865 
866 /*
867  * Setup output on interface.
868  */
869 static void
plipstart(struct ifnet * ifp)870 plipstart(struct ifnet *ifp)
871 {
872 	struct lpt_softc *sc = (struct lpt_softc *) ifp->if_softc;
873 	sc->sc_pending |= PLIP_OPENDING;
874 	/*softintr(sc->sc_ifsoftint);*/
875 	schednetisr(NETISR_PLIP);
876 }
877 
878 static void
plipoutput(void * arg)879 plipoutput(void *arg)
880 {
881 	struct lpt_softc *sc = arg;
882 #ifdef	__NetBSD__
883 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
884 #else
885 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
886 #endif
887 	bus_space_tag_t iot = sc->sc_iot;
888 	bus_space_handle_t ioh = sc->sc_ioh;
889 	struct mbuf *m0, *m;
890 	u_char minibuf[4], cksum;
891 	int len, i, s;
892 
893 	if (ifp->if_flags & IFF_OACTIVE)
894 		return;
895 	ifp->if_flags |= IFF_OACTIVE;
896 
897 	if (sc->sc_ifoerrs)
898 		timeout_del(&sc->sc_pliptimeout);
899 
900 	for (;;) {
901 		s = splnet();
902 		IF_DEQUEUE(&ifp->if_snd, m0);
903 		splx(s);
904 		if (!m0)
905 			break;
906 
907 #if NBPFILTER > 0
908 		if (ifp->if_bpf)
909 			bpf_mtap(ifp->if_bpf, m0);
910 #endif
911 
912 		len = m0->m_pkthdr.len;
913 		minibuf[0] = 2;
914 		minibuf[1] = len;
915 		minibuf[2] = len >> 8;
916 
917 		/* Trigger remote interrupt */
918 		i = PLIPMXSPIN1;
919 		do {
920 			if (sc->sc_pending & PLIP_IPENDING) {
921 				bus_space_write_1(iot, ioh, lpt_data, 0x00);
922 				sc->sc_pending = 0;
923 				plipinput(sc);
924 				i = PLIPMXSPIN1;
925 			} else if (i-- < 0)
926 				goto retry;
927 			/* Retrigger remote interrupt */
928 			bus_space_write_1(iot, ioh, lpt_data, 0x08);
929 		} while ((STABILIZE(iot, ioh, lpt_status) & LPS_NERR) == 0);
930 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control &= ~LPC_IENABLE);
931 		if (pliptransmit(sc, minibuf + 1, minibuf[0]) < 0) goto retry;
932 		for (cksum = 0, m = m0; m; m = m->m_next) {
933 			i = pliptransmit(sc, mtod(m, u_char *), m->m_len);
934 			if (i < 0) goto retry;
935 			cksum += i;
936 		}
937 		if (pliptransmit(sc, &cksum, 1) < 0) goto retry;
938 		i = PLIPMXSPIN2;
939 		while ((STABILIZE(iot, ioh, lpt_status) & LPS_NBSY) == 0)
940 			if (i-- < 0) goto retry;
941 		sc->sc_pending = 0;
942 		bus_space_write_1(iot, ioh, lpt_data, 0x00);
943 
944 		ifp->if_opackets++;
945 		ifp->if_obytes += len + 4;
946 		sc->sc_ifoerrs = 0;
947 		m_freem(m0);
948 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
949 	}
950 	ifp->if_flags &= ~IFF_OACTIVE;
951 	return;
952 
953 retry:
954 	if (STABILIZE(iot, ioh, lpt_status) & LPS_NACK)
955 		ifp->if_collisions++;
956 	else
957 		ifp->if_oerrors++;
958 
959 	ifp->if_flags &= ~IFF_OACTIVE;
960 	bus_space_write_1(iot, ioh, lpt_data, 0x00);
961 
962 	if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == (IFF_RUNNING | IFF_UP)
963 	    && sc->sc_ifoerrs < PLIPMXRETRY) {
964 		s = splnet();
965 		IF_PREPEND(&ifp->if_snd, m0);
966 		splx(s);
967 		timeout_set(&sc->sc_pliptimeout, plipoutput, sc);
968 		timeout_add(&sc->sc_pliptimeout, PLIPRETRY);
969 	} else {
970 		/* we are not able to send this... give up for now */
971 		if (sc->sc_ifoerrs == PLIPMXRETRY) {
972 			log(LOG_NOTICE, "%s: tx hard error\n", ifp->if_xname);
973 		}
974 		m_freem(m0);
975 	}
976 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
977 	sc->sc_ifoerrs++;
978 }
979 #endif	/* PLIP and INET */
980