dz_ebus.c revision 1.6 1 /* $NetBSD: dz_ebus.c,v 1.6 2013/11/10 18:27:15 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code was written by Alessandro Forin and Neil Pittman
8 * at Microsoft Research and contributed to The NetBSD Foundation
9 * by Microsoft Corporation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: dz_ebus.c,v 1.6 2013/11/10 18:27:15 christos Exp $");
35
36 #include "opt_ddb.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/callout.h>
41 #include <sys/ioctl.h>
42 #include <sys/tty.h>
43 #include <sys/proc.h>
44 #include <sys/buf.h>
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #include <sys/uio.h>
48 #include <sys/kernel.h>
49 #include <sys/syslog.h>
50 #include <sys/device.h>
51 #include <sys/kauth.h>
52
53 #include <machine/bus.h>
54 #include <machine/emipsreg.h>
55
56 #include <dev/cons.h>
57
58
59 #include <emips/ebus/ebusvar.h>
60 #include <emips/emips/cons.h>
61 #if 0
62 #include <emips/emips/machdep.h>
63 #endif
64
65 #include "ioconf.h" /* for dz_cd */
66
67 #define DZ_C2I(c) ((c) << 3) /* convert controller # to index */
68 #define DZ_I2C(c) ((c) >> 3) /* convert minor to controller # */
69 #define DZ_PORT(u) ((u) & 07) /* extract the port # */
70
71 struct dz_softc {
72 device_t sc_dev; /* Autoconf blaha */
73 struct evcnt sc_rintrcnt; /* recevive interrupt counts */
74 struct evcnt sc_tintrcnt; /* transmit interrupt counts */
75 struct _Usart *sc_dr; /* reg pointers */
76 bus_space_tag_t sc_iot;
77 bus_space_handle_t sc_ioh;
78 int sc_consline; /* console line, or -1 */
79 int sc_rxint; /* Receive interrupt count XXX */
80 u_char sc_brk; /* Break asserted on some lines */
81 u_char sc_dsr; /* DSR set bits if no mdm ctrl */
82 struct dz_linestate {
83 struct dz_softc *dz_sc; /* backpointer to softc */
84 int dz_line; /* channel number */
85 struct tty *dz_tty; /* what we work on */
86 } sc_dz;
87 };
88
89 void dzrint(struct dz_softc *, uint32_t);
90 void dzxint(struct dz_softc *, uint32_t);
91
92 #ifndef TIOCM_BRK
93 #define TIOCM_BRK 0100000 /* no equivalent */
94
95 static void dzstart(struct tty *);
96 static int dzparam(struct tty *, struct termios *);
97 static unsigned dzmctl(struct dz_softc *sc, int line,
98 int bits, /* one of the TIOCM_xx */
99 int how); /* one of the DMSET/BIS.. */
100
101 #include <dev/dec/dzkbdvar.h>
102 #endif
103
104 dev_type_open(dzopen);
105 dev_type_close(dzclose);
106 dev_type_read(dzread);
107 dev_type_write(dzwrite);
108 dev_type_ioctl(dzioctl);
109 dev_type_stop(dzstop);
110 dev_type_tty(dztty);
111 dev_type_poll(dzpoll);
112
113 const struct cdevsw dz_cdevsw = {
114 dzopen, dzclose, dzread, dzwrite, dzioctl,
115 dzstop, dztty, dzpoll, nommap, ttykqfilter, D_TTY
116 };
117
118 int
119 dzopen(dev_t dev, int flag, int mode, struct lwp *l)
120 {
121 struct tty *tp;
122 int unit, line;
123 struct dz_softc *sc;
124 int s, error = 0;
125
126 unit = DZ_I2C(minor(dev));
127 sc = device_lookup_private(&dz_cd, unit);
128 if (sc == NULL)
129 return ENXIO;
130
131 line = DZ_PORT(minor(dev));
132 if (line > 0) /* FIXME for more than one line */
133 return ENXIO;
134
135 tp = sc->sc_dz.dz_tty;
136 if (tp == NULL)
137 return ENODEV;
138 tp->t_oproc = dzstart;
139 tp->t_param = dzparam;
140 tp->t_dev = dev;
141
142 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
143 return (EBUSY);
144
145 if ((tp->t_state & TS_ISOPEN) == 0) {
146 ttychars(tp);
147 if (tp->t_ispeed == 0) {
148 tp->t_iflag = TTYDEF_IFLAG;
149 tp->t_oflag = TTYDEF_OFLAG;
150 tp->t_cflag = TTYDEF_CFLAG;
151 tp->t_lflag = TTYDEF_LFLAG;
152 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
153 }
154 (void)dzparam(tp, &tp->t_termios);
155 ttsetwater(tp);
156 }
157 /* we have no modem control but..*/
158 if (dzmctl(sc, line, TIOCM_DTR, DMBIS) & TIOCM_CD)
159 tp->t_state |= TS_CARR_ON;
160 s = spltty();
161 while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
162 !(tp->t_state & TS_CARR_ON)) {
163 tp->t_wopen++;
164 error = ttysleep(tp, &tp->t_rawcv, true, 0);
165 tp->t_wopen--;
166 if (error)
167 break;
168 }
169 (void)splx(s);
170 if (error)
171 return error;
172 return (*tp->t_linesw->l_open)(dev, tp);
173 }
174
175 int
176 dzclose(dev_t dev, int flag, int mode, struct lwp *l)
177 {
178 struct dz_softc *sc;
179 struct tty *tp;
180 int unit, line;
181
182 unit = DZ_I2C(minor(dev));
183 sc = device_lookup_private(&dz_cd, unit);
184 line = DZ_PORT(minor(dev));
185
186 tp = sc->sc_dz.dz_tty;
187
188 (*tp->t_linesw->l_close)(tp, flag);
189
190 /* Make sure a BREAK state is not left enabled. */
191 (void)dzmctl(sc, line, TIOCM_BRK, DMBIC);
192
193 /* Do a hangup if so required. */
194 if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN))
195 (void)dzmctl(sc, line, 0, DMSET);
196
197 return ttyclose(tp);
198 }
199
200 int
201 dzread(dev_t dev, struct uio *uio, int flag)
202 {
203 struct tty *tp;
204 struct dz_softc *sc;
205
206 sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
207
208 tp = sc->sc_dz.dz_tty;
209 return (*tp->t_linesw->l_read)(tp, uio, flag);
210 }
211
212 int
213 dzwrite(dev_t dev, struct uio *uio, int flag)
214 {
215 struct tty *tp;
216 struct dz_softc *sc;
217
218 sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
219
220 tp = sc->sc_dz.dz_tty;
221 return (*tp->t_linesw->l_write)(tp, uio, flag);
222 }
223
224 /*ARGSUSED*/
225 int
226 dzioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
227 {
228 struct dz_softc *sc;
229 struct tty *tp;
230 int unit, line;
231 int error;
232
233 unit = DZ_I2C(minor(dev));
234 line = 0;
235 sc = device_lookup_private(&dz_cd, unit);
236 tp = sc->sc_dz.dz_tty;
237
238 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
239 if (error >= 0)
240 return error;
241
242 error = ttioctl(tp, cmd, data, flag, l);
243 if (error >= 0)
244 return error;
245
246 switch (cmd) {
247
248 case TIOCSBRK:
249 (void)dzmctl(sc, line, TIOCM_BRK, DMBIS);
250 break;
251
252 case TIOCCBRK:
253 (void)dzmctl(sc, line, TIOCM_BRK, DMBIC);
254 break;
255
256 case TIOCSDTR:
257 (void)dzmctl(sc, line, TIOCM_DTR, DMBIS);
258 break;
259
260 case TIOCCDTR:
261 (void)dzmctl(sc, line, TIOCM_DTR, DMBIC);
262 break;
263
264 case TIOCMSET:
265 (void)dzmctl(sc, line, *(int *)data, DMSET);
266 break;
267
268 case TIOCMBIS:
269 (void)dzmctl(sc, line, *(int *)data, DMBIS);
270 break;
271
272 case TIOCMBIC:
273 (void)dzmctl(sc, line, *(int *)data, DMBIC);
274 break;
275
276 case TIOCMGET:
277 *(int *)data = dzmctl(sc, line, 0, DMGET) & ~TIOCM_BRK;
278 break;
279
280 default:
281 return EPASSTHROUGH;
282 }
283 return 0;
284 }
285
286 /*ARGSUSED*/
287 void
288 dzstop(struct tty *tp, int flag)
289 {
290
291 if (tp->t_state & TS_BUSY)
292 if (!(tp->t_state & TS_TTSTOP))
293 tp->t_state |= TS_FLUSH;
294 }
295
296 struct tty *
297 dztty(dev_t dev)
298 {
299 struct dz_softc *sc;
300 struct tty *tp;
301
302 sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
303 tp = sc->sc_dz.dz_tty;
304
305 return tp;
306 }
307
308 int
309 dzpoll(dev_t dev, int events, struct lwp *l)
310 {
311 struct dz_softc *sc;
312 struct tty *tp;
313
314 sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
315
316 tp = sc->sc_dz.dz_tty;
317 return (*tp->t_linesw->l_poll)(tp, events, l);
318 }
319
320 void
321 dzstart(struct tty *tp)
322 {
323 struct dz_softc *sc;
324 struct clist *cl;
325 int unit, s;
326
327 unit = DZ_I2C(minor(tp->t_dev));
328 sc = device_lookup_private(&dz_cd, unit);
329
330 s = spltty();
331 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) {
332 splx(s);
333 return;
334 }
335 cl = &tp->t_outq;
336 ttypull(tp);
337 if (cl->c_cc == 0) {
338 splx(s);
339 return;
340 }
341
342 tp->t_state |= TS_BUSY;
343
344 /* was idle, get it started */
345 dzxint(sc,USI_TXRDY);
346 splx(s);
347 }
348
349 static int rclk = 25000000; /* BUGBUGBUGBUG */
350
351 static int
352 dzdivisor(int baudrate)
353 {
354 int act_baud, divisor, error;
355
356 if (baudrate <= 0)
357 return 0;
358
359 divisor = (rclk / 8) / (baudrate);
360 divisor = (divisor / 2) + (divisor & 1);
361
362 if (divisor <= 0)
363 return -1;
364 act_baud = rclk / (divisor * 16);
365
366 /* 10 times error in percent: */
367 error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1;
368
369 /* 3.0% maximum error tolerance: */
370 if (error < -30 || error > 30)
371 return -1;
372
373 return divisor;
374 }
375
376 static int
377 dzparam(struct tty *tp, struct termios *t)
378 {
379 struct dz_softc *sc;
380 int cflag = t->c_cflag;
381 int unit, line;
382 int speed;
383 unsigned lpr;
384 int s;
385 struct _Usart *dzr;
386
387 unit = DZ_I2C(minor(tp->t_dev));
388 line = DZ_PORT(minor(tp->t_dev));
389 sc = device_lookup_private(&dz_cd, unit);
390
391 /* check requested parameters */
392 if (t->c_ispeed != t->c_ospeed)
393 return EINVAL;
394 speed = dzdivisor(t->c_ispeed);
395 if (speed < 0)
396 return EINVAL;
397
398 tp->t_ispeed = t->c_ispeed;
399 tp->t_ospeed = t->c_ospeed;
400 tp->t_cflag = cflag;
401
402 {
403 /* XXX */
404 static int didit = 0;
405 if (!didit && t->c_ispeed != 38400)
406 printf("dzparam: c_ispeed %d ignored, keeping 38400\n",
407 t->c_ispeed);
408 didit = 1;
409 }
410 speed = dzdivisor(38400);
411
412 if (speed == 0) {
413 (void)dzmctl(sc, line, 0, DMSET); /* hang up line */
414 return 0;
415 }
416
417 switch (cflag & CSIZE) {
418 case CS5:
419 lpr = USC_BPC_5;
420 break;
421 case CS6:
422 lpr = USC_BPC_6;
423 break;
424 case CS7:
425 lpr = USC_BPC_7;
426 break;
427 default:
428 lpr = USC_BPC_8;
429 break;
430 }
431 if (cflag & CSTOPB)
432 lpr |= USC_2STOP;
433
434 if (cflag & PARENB) {
435 if (cflag & PARODD)
436 lpr |= USC_ODD;
437 else
438 lpr |= USC_EVEN;
439 } else
440 lpr |= USC_NONE;
441
442 s = spltty();
443
444 dzr = sc->sc_dr;
445
446 dzr->Baud = speed;
447 dzr->Control = USC_CLKDIV_4 | USC_TXEN | USC_RXEN | lpr;
448 #define USI_INTRS (USI_RXRDY|USI_RXBRK|USI_OVRE|USI_FRAME|USI_PARE)
449 dzr->IntrEnable = USI_INTRS;
450
451 (void)splx(s);
452 return 0;
453 }
454
455 static unsigned
456 dzmctl(struct dz_softc *sc, int line, int bits, int how)
457 {
458 unsigned int mbits;
459 int s;
460 struct _Usart *dzr;
461
462 mbits = 0;
463
464 s = spltty();
465
466 dzr = sc->sc_dr;
467
468 /* we have no modem control bits (CD,RI,DTR,DSR,..) */
469 mbits |= TIOCM_CD;
470 mbits |= TIOCM_DTR;
471
472 if (dzr->ChannelStatus & USI_RXBRK)
473 mbits |= TIOCM_BRK;
474
475 switch (how) {
476 case DMSET:
477 mbits = bits;
478 break;
479
480 case DMBIS:
481 mbits |= bits;
482 break;
483
484 case DMBIC:
485 mbits &= ~bits;
486 break;
487
488 case DMGET:
489 (void)splx(s);
490 return mbits;
491 }
492
493 /* BUGBUG work in progress */
494 if (mbits & TIOCM_BRK) {
495 sc->sc_brk |= (1 << line);
496 dzr->Control |= USC_STTBRK;
497 } else {
498 sc->sc_brk &= ~(1 << line);
499 dzr->Control |= USC_STPBRK;
500 }
501
502 (void)splx(s);
503 return mbits;
504 }
505
506
507 #if defined(DDB)
508 int dz_ddb = 0;
509 #endif
510
511 /* Receiver Interrupt */
512
513 void
514 dzrint(struct dz_softc *sc, uint32_t csr)
515 {
516 struct tty *tp;
517 int cc;
518 struct _Usart *dzr;
519
520 sc->sc_rxint++;
521 dzr = sc->sc_dr;
522
523 cc = dzr->RxData;
524 tp = sc->sc_dz.dz_tty;
525
526 /* clear errors before we print or bail out */
527 if (csr & (USI_OVRE|USI_FRAME|USI_PARE))
528 dzr->Control = USC_RSTSTA;
529
530 if (!(tp->t_state & TS_ISOPEN)) {
531 wakeup(&tp->t_rawq);
532 return;
533 }
534
535 if (csr & USI_OVRE) {
536 log(LOG_WARNING, "%s: silo overflow, line %d\n",
537 device_xname(sc->sc_dev), 0);
538 }
539
540 if (csr & USI_FRAME)
541 cc |= TTY_FE;
542 if (csr & USI_PARE)
543 cc |= TTY_PE;
544
545 #if defined(DDB)
546 /* ^P drops into DDB */
547 if (dz_ddb && (cc == 0x10))
548 Debugger();
549 #endif
550 (*tp->t_linesw->l_rint)(cc, tp);
551 }
552
553 /* Transmitter Interrupt */
554
555 void
556 dzxint(struct dz_softc *sc, uint32_t csr)
557 {
558 struct tty *tp;
559 struct clist *cl;
560 int ch;
561 struct _Usart *dzr;
562
563 dzr = sc->sc_dr;
564
565 tp = sc->sc_dz.dz_tty;
566 cl = &tp->t_outq;
567 tp->t_state &= ~TS_BUSY;
568
569 /* Just send out a char if we have one */
570 if (cl->c_cc) {
571 tp->t_state |= TS_BUSY;
572 ch = getc(cl);
573 dzr->TxData = ch;
574 dzr->IntrEnable = USI_TXRDY;
575 return;
576 }
577
578 /* Nothing to send; turn off intr */
579 dzr->IntrDisable = USI_TXRDY;
580
581 if (tp->t_state & TS_FLUSH)
582 tp->t_state &= ~TS_FLUSH;
583 else
584 ndflush(&tp->t_outq, cl->c_cc);
585
586 (*tp->t_linesw->l_start)(tp);
587 }
588
589 /*
590 * Machdep part of the driver
591 */
592 int dz_ebus_match(device_t, cfdata_t, void *);
593 void dz_ebus_attach(device_t, device_t, void *);
594 int dz_ebus_intr(void *, void *);
595
596 void dz_ebus_cnsetup(paddr_t);
597 void dz_ebus_cninit(struct consdev *);
598 int dz_ebus_cngetc(dev_t);
599 void dz_ebus_cnputc(dev_t, int);
600 void dz_ebus_cnpollc(dev_t, int);
601
602 static int dz_ebus_getmajor(void);
603
604 CFATTACH_DECL_NEW(dz_ebus, sizeof(struct dz_softc),
605 dz_ebus_match, dz_ebus_attach, NULL, NULL);
606
607 struct consdev dz_ebus_consdev = {
608 NULL, dz_ebus_cninit, dz_ebus_cngetc, dz_ebus_cnputc,
609 dz_ebus_cnpollc, NULL, NULL, NULL, NODEV, CN_NORMAL,
610 };
611
612 /*
613 * Points to the console regs. Special mapping until VM is turned on.
614 */
615 struct _Usart *dzcn;
616
617 int
618 dz_ebus_match(device_t parent, cfdata_t cf, void *aux)
619 {
620 struct ebus_attach_args *iba;
621 struct _Usart *us;
622
623 iba = aux;
624
625 if (strcmp(iba->ia_name, "dz") != 0)
626 return 0;
627
628 us = (struct _Usart *)iba->ia_vaddr;
629 if ((us == NULL) ||
630 (us->Tag != PMTTAG_USART))
631 return 0;
632
633 return 1;
634 }
635
636 void
637 dz_ebus_attach(device_t parent, device_t self, void *aux)
638 {
639 struct ebus_attach_args *iba;
640 struct dz_softc *sc;
641
642 sc = device_private(self);
643 iba = aux;
644
645 sc->sc_dev = self;
646 sc->sc_dr = (struct _Usart *)iba->ia_vaddr;
647 #if DEBUG
648 printf(" virt=%p ", (void *)sc->sc_dr);
649 #endif
650
651 printf(": neilsart 1 line");
652 ebus_intr_establish(parent, (void *)iba->ia_cookie, IPL_TTY,
653 dz_ebus_intr, sc);
654
655 sc->sc_rxint = sc->sc_brk = 0;
656 sc->sc_consline = 0;
657
658 /* Initialize our softc structure. Should be done in open? */
659
660 sc->sc_dz.dz_sc = sc;
661 sc->sc_dz.dz_line = 0;
662 sc->sc_dz.dz_tty = tty_alloc();
663
664 evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, NULL,
665 device_xname(self), "rintr");
666 evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, NULL,
667 device_xname(self), "tintr");
668
669 /* Initialize hw regs */
670 #if 0
671 DZ_WRITE_WORD(dr_csr, DZ_CSR_MSE | DZ_CSR_RXIE | DZ_CSR_TXIE);
672 DZ_WRITE_BYTE(dr_dtr, 0);
673 DZ_WRITE_BYTE(dr_break, 0);
674 #endif
675
676 /* Switch the console to virtual mode */
677 dzcn = sc->sc_dr;
678 /* And test it */
679 printf("\n");
680 }
681
682 static int
683 dz_ebus_getmajor(void)
684 {
685 extern const struct cdevsw dz_cdevsw;
686 static int cache = -1;
687
688 if (cache != -1)
689 return cache;
690
691 return cache = cdevsw_lookup_major(&dz_cdevsw);
692 }
693
694 int
695 dz_ebus_intr(void *cookie, void *f)
696 {
697 struct dz_softc *sc;
698 struct _Usart *dzr;
699 uint32_t csr;
700
701 sc = cookie;
702 dzr = sc->sc_dr;
703
704 #define USI_INTERRUPTS (USI_INTRS|USI_TXRDY)
705
706 for (; ((csr = (dzr->ChannelStatus & dzr->IntrMask)) &
707 USI_INTERRUPTS) != 0;) {
708 if ((csr & USI_INTRS) != 0)
709 dzrint(sc, csr);
710 if ((csr & USI_TXRDY) != 0)
711 dzxint(sc, csr);
712 }
713
714 return 0;
715 }
716
717 void
718 dz_ebus_cnsetup(paddr_t addr)
719 {
720
721 dzcn = (struct _Usart *)addr;
722
723 #if 0
724 /*
725 * Initialize enough to xmit/recv via polling.
726 * Bootloader might or might not have done it.
727 */
728 dzcn->Control =
729 USC_RXEN |
730 USC_TXEN |
731 USC_BPC_8 |
732 USC_NONE |
733 USC_1STOP |
734 USC_CLKDIV_4;
735 dzcn->Baud = 0x29; /* 38400 */
736 #endif
737
738 /*
739 * Point the console at us
740 */
741 cn_tab = &dz_ebus_consdev;
742 cn_tab->cn_pri = CN_NORMAL;/*CN_REMOTE?*/
743 cn_tab->cn_dev = makedev(dz_ebus_getmajor(), 0);
744 }
745
746 void
747 dz_ebus_cninit(struct consdev *cn)
748 {
749 }
750
751 int
752 dz_ebus_cngetc(dev_t dev)
753 {
754 int c, s;
755
756 c = 0;
757 s = spltty();
758
759 while ((dzcn->ChannelStatus & USI_RXRDY) == 0)
760 DELAY(10);
761 c = dzcn->RxData;
762
763 splx(s);
764 if (c == 13) /* map cr->ln */
765 c = 10;
766 return c;
767 }
768
769 int dzflipped = 0;
770 void
771 dz_ebus_cnputc(dev_t dev, int ch)
772 {
773 int timeout, s;
774
775 /* Don't hang the machine! */
776 timeout = 1 << 15;
777
778 s = spltty();
779
780 #if 1
781 /* Keep wired to hunt for a bug */
782 if (dzcn && (dzcn != (struct _Usart *)0xfff90000)) {
783 dzcn = (struct _Usart *)0xfff90000;
784 dzflipped++;
785 }
786 #endif
787
788 /* Wait until ready */
789 while ((dzcn->ChannelStatus & USI_TXRDY) == 0)
790 if (--timeout < 0)
791 break;
792
793 /* Put the character */
794 dzcn->TxData = ch;
795
796 splx(s);
797 }
798
799 /*
800 * Called before/after going into poll mode
801 */
802 void
803 dz_ebus_cnpollc(dev_t dev, int on)
804 {
805 }
806