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