1 /* $OpenBSD: siotty.c,v 1.25 2021/01/09 02:34:21 aoyama Exp $ */
2 /* $NetBSD: siotty.c,v 1.9 2002/03/17 19:40:43 atatat Exp $ */
3
4 /*-
5 * Copyright (c) 2000 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Tohru Nishimura.
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/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/conf.h>
37 #include <sys/ioctl.h>
38 #include <sys/malloc.h>
39 #include <sys/proc.h>
40 #include <sys/tty.h>
41 #include <sys/uio.h>
42 #include <sys/fcntl.h>
43 #include <dev/cons.h>
44
45 #include <machine/board.h>
46 #include <machine/cpu.h>
47
48 #include <luna88k/dev/sioreg.h>
49 #include <luna88k/dev/siovar.h>
50
51 #define TIOCM_BREAK 01000 /* non standard use */
52
53 static const u_int8_t ch0_regs[6] = {
54 WR0_RSTINT, /* reset E/S interrupt */
55 WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
56 0, /* */
57 WR3_RX8BIT | WR3_RXENBL, /* Rx */
58 WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
59 WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
60 };
61
62 static const struct speedtab siospeedtab[] = {
63 { 2400, WR4_BAUD24, },
64 { 4800, WR4_BAUD48, },
65 { 9600, WR4_BAUD96, },
66 { -1, 0, },
67 };
68
69 struct siotty_softc {
70 struct device sc_dev;
71 struct tty *sc_tty;
72 struct sioreg *sc_ctl;
73 u_int sc_flags;
74 u_int8_t sc_wr[6];
75 void *sc_si; /* software interrupt handler */
76 u_int sc_hwflags;
77 #define SIOTTY_HW_CONSOLE 0x0001
78
79 u_int8_t *sc_rbuf;
80 u_int8_t *sc_rbufend;
81 u_int8_t * volatile sc_rbget;
82 u_int8_t * volatile sc_rbput;
83 volatile u_int sc_rbavail;
84
85 u_int8_t *sc_tba;
86 u_int sc_tbc;
87
88 bool sc_rx_ready;
89 bool sc_tx_busy;
90 bool sc_tx_done;
91 };
92
93 #define SIOTTY_RING_SIZE 2048
94 u_int siotty_rbuf_size = SIOTTY_RING_SIZE;
95
96 cdev_decl(sio);
97 void siostart(struct tty *);
98 int sioparam(struct tty *, struct termios *);
99 void siottyintr(void *);
100 void siottysoft(void *);
101 void siotty_rxsoft(struct siotty_softc *, struct tty *);
102 void siotty_txsoft(struct siotty_softc *, struct tty *);
103 int siomctl(struct siotty_softc *, int, int);
104
105 int siotty_match(struct device *, void *, void *);
106 void siotty_attach(struct device *, struct device *, void *);
107
108 const struct cfattach siotty_ca = {
109 sizeof(struct siotty_softc), siotty_match, siotty_attach
110 };
111
112 struct cfdriver siotty_cd = {
113 NULL, "siotty", DV_TTY
114 };
115
116 int
siotty_match(struct device * parent,void * cf,void * aux)117 siotty_match(struct device *parent, void *cf, void *aux)
118 {
119 struct sio_attach_args *args = aux;
120
121 if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
122 return 0;
123 return 1;
124 }
125
126 void
siotty_attach(struct device * parent,struct device * self,void * aux)127 siotty_attach(struct device *parent, struct device *self, void *aux)
128 {
129 struct sio_softc *siosc = (void *)parent;
130 struct siotty_softc *sc = (void *)self;
131 struct sio_attach_args *args = aux;
132 int channel;
133 struct tty *tp;
134
135 channel = args->channel;
136 sc->sc_ctl = &siosc->sc_ctl[channel];
137 memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
138 siosc->sc_intrhand[channel].ih_func = siottyintr;
139 siosc->sc_intrhand[channel].ih_arg = sc;
140 if (args->hwflags == 1)
141 sc->sc_hwflags |= SIOTTY_HW_CONSOLE;
142
143 if (sc->sc_hwflags & SIOTTY_HW_CONSOLE) {
144 printf(" (console)");
145 sc->sc_flags = TIOCFLAG_SOFTCAR;
146 } else {
147 setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
148 setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
149 setsioreg(sc->sc_ctl, WR2B, 0);
150 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
151 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
152 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
153 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
154 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
155 }
156 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
157
158 printf("\n");
159
160 sc->sc_rbuf = malloc(siotty_rbuf_size * 2, M_DEVBUF, M_NOWAIT);
161 if (sc->sc_rbuf == NULL) {
162 printf("%s: unable to allocate ring buffer\n",
163 (sc->sc_dev).dv_xname);
164 return;
165 }
166 sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2);
167 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
168 sc->sc_rbavail = siotty_rbuf_size;
169
170 tp = ttymalloc(0);
171 tp->t_oproc = siostart;
172 tp->t_param = sioparam;
173 tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
174 if (sc->sc_hwflags & SIOTTY_HW_CONSOLE)
175 tp->t_dev = cn_tab->cn_dev;
176 sc->sc_tty = tp;
177
178 sc->sc_si = softintr_establish(IPL_SOFTTTY, siottysoft, sc);
179 }
180
181 /*-------------------- low level routine --------------------*/
182
183 void
siottyintr(void * arg)184 siottyintr(void *arg)
185 {
186 struct siotty_softc *sc;
187 struct sioreg *sio;
188 u_int8_t *put, *end;
189 u_int8_t c;
190 u_int16_t rr;
191 int cc;
192
193 sc = arg;
194 end = sc->sc_rbufend;
195 put = sc->sc_rbput;
196 cc = sc->sc_rbavail;
197
198 sio = sc->sc_ctl;
199 rr = getsiocsr(sio);
200 if (rr & RR_RXRDY) {
201 do {
202 if (cc > 0) {
203 c = sio->sio_data;
204 put[0] = c;
205 put[1] = rr & 0xff;
206 put += 2;
207 if (put >= end)
208 put = sc->sc_rbuf;
209 cc--;
210 }
211 if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY))
212 sio->sio_cmd = WR0_ERRRST;
213
214 sc->sc_rbput = put;
215 sc->sc_rbavail = cc;
216 sc->sc_rx_ready = true;
217 } while ((rr = getsiocsr(sio)) & RR_RXRDY);
218 }
219 if (rr & RR_TXRDY) {
220 sio->sio_cmd = WR0_RSTPEND;
221 if (sc->sc_tbc > 0) {
222 sio->sio_data = *sc->sc_tba;
223 sc->sc_tba++;
224 sc->sc_tbc--;
225 } else {
226 if (sc->sc_tx_busy) {
227 sc->sc_tx_busy = false;
228 sc->sc_tx_done = true;
229 }
230 }
231 }
232 softintr_schedule(sc->sc_si);
233 }
234
235 void
siottysoft(void * arg)236 siottysoft(void *arg)
237 {
238 struct siotty_softc *sc;
239 struct tty *tp;
240
241 sc = arg;
242 tp = sc->sc_tty;
243
244 if (sc->sc_rx_ready) {
245 sc->sc_rx_ready = false;
246 siotty_rxsoft(sc, tp);
247 }
248 if (sc->sc_tx_done) {
249 sc->sc_tx_done = false;
250 siotty_txsoft(sc, tp);
251 }
252 }
253
254 void
siotty_rxsoft(struct siotty_softc * sc,struct tty * tp)255 siotty_rxsoft(struct siotty_softc *sc, struct tty *tp)
256 {
257 uint8_t *get, *end;
258 u_int cc, scc;
259 unsigned int code;
260 uint8_t stat;
261 int s;
262
263 end = sc->sc_rbufend;
264 get = sc->sc_rbget;
265 scc = cc = siotty_rbuf_size - sc->sc_rbavail;
266
267 if (cc == siotty_rbuf_size) {
268 printf("%s: rx buffer overflow\n", (sc->sc_dev).dv_xname);
269 }
270
271 while (cc > 0) {
272 code = get[0];
273 stat = get[1];
274 if ((stat & RR_FRAMING) != 0)
275 code |= TTY_FE;
276 else if ((stat & RR_PARITY) != 0)
277 code |= TTY_PE;
278
279 (*linesw[tp->t_line].l_rint)(code, tp);
280 get += 2;
281 if (get >= end)
282 get = sc->sc_rbuf;
283 cc--;
284 }
285
286 if (cc != scc) {
287 s = spltty();
288 sc->sc_rbget = get;
289 sc->sc_rbavail += scc - cc;
290 splx(s);
291 }
292 }
293
294 void
siotty_txsoft(struct siotty_softc * sc,struct tty * tp)295 siotty_txsoft(struct siotty_softc *sc, struct tty *tp)
296 {
297
298 tp->t_state &= ~TS_BUSY;
299 if ((tp->t_state & TS_FLUSH) != 0)
300 tp->t_state &= ~TS_FLUSH;
301 else
302 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
303 (*linesw[tp->t_line].l_start)(tp);
304 }
305
306 void
siostart(struct tty * tp)307 siostart(struct tty *tp)
308 {
309 struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
310 int s;
311 u_int8_t *tba;
312 int tbc;
313
314 s = spltty();
315 if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP))
316 goto out;
317 ttwakeupwr(tp);
318 if (tp->t_outq.c_cc == 0)
319 goto out;
320
321 tp->t_state |= TS_BUSY;
322
323 tba = tp->t_outq.c_cf;
324 tbc = ndqb(&tp->t_outq, 0);
325
326 sc->sc_tba = tba;
327 sc->sc_tbc = tbc;
328 sc->sc_tx_busy = true;
329
330 sc->sc_ctl->sio_data = *sc->sc_tba;
331 sc->sc_tba++;
332 sc->sc_tbc--;
333 out:
334 splx(s);
335 }
336
337 int
siostop(struct tty * tp,int flag)338 siostop(struct tty *tp, int flag)
339 {
340 int s;
341
342 s = spltty();
343 if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
344 /*
345 * Device is transmitting; must stop it.
346 */
347 tp->t_state |= TS_FLUSH;
348 }
349 splx(s);
350 return (0);
351 }
352
353 int
sioparam(struct tty * tp,struct termios * t)354 sioparam(struct tty *tp, struct termios *t)
355 {
356 struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
357 int wr4, s;
358
359 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
360 return EINVAL;
361 wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
362 if (wr4 < 0)
363 return EINVAL;
364
365 if (sc->sc_flags & TIOCFLAG_SOFTCAR) {
366 t->c_cflag |= CLOCAL;
367 t->c_cflag &= ~HUPCL;
368 }
369 if (sc->sc_flags & TIOCFLAG_CLOCAL)
370 t->c_cflag |= CLOCAL;
371
372 /*
373 * If there were no changes, don't do anything. This avoids dropping
374 * input and improves performance when all we did was frob things like
375 * VMIN and VTIME.
376 */
377 if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
378 return 0;
379
380 tp->t_ispeed = t->c_ispeed;
381 tp->t_ospeed = t->c_ospeed;
382 tp->t_cflag = t->c_cflag;
383
384 sc->sc_wr[WR3] &= 0x3f;
385 sc->sc_wr[WR5] &= 0x9f;
386 switch (tp->t_cflag & CSIZE) {
387 case CS7:
388 sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
389 break;
390 case CS8:
391 sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
392 break;
393 }
394 if (tp->t_cflag & PARENB) {
395 wr4 |= WR4_PARENAB;
396 if ((tp->t_cflag & PARODD) == 0)
397 wr4 |= WR4_EPARITY;
398 }
399 wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
400 sc->sc_wr[WR4] = wr4;
401
402 s = spltty();
403 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
404 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
405 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
406 splx(s);
407
408 return 0;
409 }
410
411 int
siomctl(struct siotty_softc * sc,int control,int op)412 siomctl(struct siotty_softc *sc, int control, int op)
413 {
414 int val, s, wr5, rr;
415
416 val = 0;
417 if (control & TIOCM_BREAK)
418 val |= WR5_BREAK;
419 if (control & TIOCM_DTR)
420 val |= WR5_DTR;
421 if (control & TIOCM_RTS)
422 val |= WR5_RTS;
423 s = spltty();
424 wr5 = sc->sc_wr[WR5];
425 switch (op) {
426 case DMSET:
427 wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
428 /* FALLTHROUGH */
429 case DMBIS:
430 wr5 |= val;
431 break;
432 case DMBIC:
433 wr5 &= ~val;
434 break;
435 case DMGET:
436 val = 0;
437 rr = getsiocsr(sc->sc_ctl);
438 if (wr5 & WR5_DTR)
439 val |= TIOCM_DTR;
440 if (wr5 & WR5_RTS)
441 val |= TIOCM_RTS;
442 if (rr & RR_CTS)
443 val |= TIOCM_CTS;
444 if (rr & RR_DCD)
445 val |= TIOCM_CD;
446 goto done;
447 }
448 sc->sc_wr[WR5] = wr5;
449 setsioreg(sc->sc_ctl, WR5, wr5);
450 val = 0;
451 done:
452 splx(s);
453 return val;
454 }
455
456 /*-------------------- cdevsw[] interface --------------------*/
457
458 int
sioopen(dev_t dev,int flag,int mode,struct proc * p)459 sioopen(dev_t dev, int flag, int mode, struct proc *p)
460 {
461 struct siotty_softc *sc;
462 struct tty *tp;
463 int s;
464
465 if ((sc = siotty_cd.cd_devs[minor(dev)]) == NULL)
466 return ENXIO;
467
468 tp = sc->sc_tty;
469
470 if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE)
471 && suser(p) != 0)
472 return EBUSY;
473
474 if ((tp->t_state & TS_ISOPEN) == 0) {
475 struct termios t;
476
477 tp->t_dev = dev;
478 t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
479 t.c_cflag = TTYDEF_CFLAG;
480 tp->t_ospeed = 0; /* force register update */
481 (void)sioparam(tp, &t);
482 tp->t_iflag = TTYDEF_IFLAG;
483 tp->t_oflag = TTYDEF_OFLAG;
484 tp->t_lflag = TTYDEF_LFLAG;
485 ttychars(tp);
486 ttsetwater(tp);
487 /* raise RTS and DTR here; but, DTR lead is not wired */
488 /* then check DCD condition; but, DCD lead is not wired */
489 #if 0
490 if ((sc->sc_flags & TIOCFLAG_SOFTCAR)
491 || (tp->t_cflag & MDMBUF)
492 || (getsiocsr(sc->sc_ctl) & RR_DCD))
493 tp->t_state |= TS_CARR_ON;
494 else
495 tp->t_state &= ~TS_CARR_ON;
496 #else
497 tp->t_state |= TS_CARR_ON; /* assume detected all the time */
498 #endif
499 s = spltty();
500 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
501 sc->sc_rbavail = siotty_rbuf_size;
502 splx(s);
503 }
504
505 return (*linesw[tp->t_line].l_open)(dev, tp, p);
506 }
507
508 int
sioclose(dev_t dev,int flag,int mode,struct proc * p)509 sioclose(dev_t dev, int flag, int mode, struct proc *p)
510 {
511 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
512 struct tty *tp = sc->sc_tty;
513 int s;
514
515 (*linesw[tp->t_line].l_close)(tp, flag, p);
516
517 s = spltty();
518 siomctl(sc, TIOCM_BREAK, DMBIC);
519 #if 0 /* because unable to feed DTR signal */
520 if ((tp->t_cflag & HUPCL)
521 || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
522 siomctl(sc, TIOCM_DTR, DMBIC);
523 /* Yield CPU time to others for 1 second, then ... */
524 siomctl(sc, TIOCM_DTR, DMBIS);
525 }
526 #endif
527 splx(s);
528 return ttyclose(tp);
529 }
530
531 int
sioread(dev_t dev,struct uio * uio,int flag)532 sioread(dev_t dev, struct uio *uio, int flag)
533 {
534 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
535 struct tty *tp = sc->sc_tty;
536
537 return (*linesw[tp->t_line].l_read)(tp, uio, flag);
538 }
539
540 int
siowrite(dev_t dev,struct uio * uio,int flag)541 siowrite(dev_t dev, struct uio *uio, int flag)
542 {
543 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
544 struct tty *tp = sc->sc_tty;
545
546 return (*linesw[tp->t_line].l_write)(tp, uio, flag);
547 }
548
549 int
sioioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)550 sioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
551 {
552 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
553 struct tty *tp = sc->sc_tty;
554 int error;
555
556 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
557 if (error >= 0)
558 return error;
559
560 error = ttioctl(tp, cmd, data, flag, p);
561 if (error >= 0)
562 return error;
563
564 /* the last resort for TIOC ioctl traversing */
565 switch (cmd) {
566 case TIOCSBRK: /* Set the hardware into BREAK condition */
567 siomctl(sc, TIOCM_BREAK, DMBIS);
568 break;
569 case TIOCCBRK: /* Clear the hardware BREAK condition */
570 siomctl(sc, TIOCM_BREAK, DMBIC);
571 break;
572 case TIOCSDTR: /* Assert DTR signal */
573 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
574 break;
575 case TIOCCDTR: /* Clear DTR signal */
576 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
577 break;
578 case TIOCMSET: /* Set modem state replacing current one */
579 siomctl(sc, *(int *)data, DMSET);
580 break;
581 case TIOCMGET: /* Return current modem state */
582 *(int *)data = siomctl(sc, 0, DMGET);
583 break;
584 case TIOCMBIS: /* Set individual bits of modem state */
585 siomctl(sc, *(int *)data, DMBIS);
586 break;
587 case TIOCMBIC: /* Clear individual bits of modem state */
588 siomctl(sc, *(int *)data, DMBIC);
589 break;
590 case TIOCSFLAGS: /* Instruct how serial port behaves */
591 error = suser(p);
592 if (error != 0)
593 return EPERM;
594 sc->sc_flags = *(int *)data;
595 break;
596 case TIOCGFLAGS: /* Return current serial port state */
597 *(int *)data = sc->sc_flags;
598 break;
599 default:
600 return ENOTTY;
601 }
602 return 0;
603 }
604
605 /* ARSGUSED */
606 struct tty *
siotty(dev_t dev)607 siotty(dev_t dev)
608 {
609 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
610
611 return sc->sc_tty;
612 }
613
614 /*-------------------- miscellaneous routines --------------------*/
615
616 /* EXPORT */ void
setsioreg(struct sioreg * sio,int regno,int val)617 setsioreg(struct sioreg *sio, int regno, int val)
618 {
619 if (regno != 0)
620 sio->sio_cmd = regno; /* DELAY(); */
621 sio->sio_cmd = val; /* DELAY(); */
622 }
623
624 /* EXPORT */ int
getsiocsr(struct sioreg * sio)625 getsiocsr(struct sioreg *sio)
626 {
627 int val;
628
629 val = sio->sio_stat << 8; /* DELAY(); */
630 sio->sio_cmd = 1; /* DELAY(); */
631 val |= sio->sio_stat; /* DELAY(); */
632 return val;
633 }
634
635 /*--------------------- console interface ----------------------*/
636
637 void syscnattach(int);
638 int syscngetc(dev_t);
639 void syscnputc(dev_t, int);
640
641 struct consdev syscons = {
642 NULL,
643 NULL,
644 syscngetc,
645 syscnputc,
646 nullcnpollc,
647 NULL,
648 NODEV,
649 CN_HIGHPRI,
650 };
651
652 /* EXPORT */ void
syscnattach(int channel)653 syscnattach(int channel)
654 {
655 /*
656 * Channel A is immediately initialized with 9600N1 right after cold
657 * boot/reset/poweron. ROM monitor emits one line message on CH.A.
658 */
659 struct sioreg *sio;
660 sio = (struct sioreg *)OBIO_SIO + channel;
661
662 syscons.cn_dev = makedev(12, channel);
663 cn_tab = &syscons;
664
665 setsioreg(sio, WR0, WR0_CHANRST);
666 setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
667 setsioreg(sio, WR2B, 0);
668 setsioreg(sio, WR0, ch0_regs[WR0]);
669 setsioreg(sio, WR4, ch0_regs[WR4]);
670 setsioreg(sio, WR3, ch0_regs[WR3]);
671 setsioreg(sio, WR5, ch0_regs[WR5]);
672 setsioreg(sio, WR0, ch0_regs[WR0]);
673 }
674
675 /* EXPORT */ int
syscngetc(dev_t dev)676 syscngetc(dev_t dev)
677 {
678 struct sioreg *sio;
679 int s, c;
680
681 sio = (struct sioreg *)OBIO_SIO + ((int)dev & 0x1);
682 s = splhigh();
683 while ((getsiocsr(sio) & RR_RXRDY) == 0)
684 ;
685 c = sio->sio_data;
686 splx(s);
687
688 return c;
689 }
690
691 /* EXPORT */ void
syscnputc(dev_t dev,int c)692 syscnputc(dev_t dev, int c)
693 {
694 struct sioreg *sio;
695 int s;
696
697 sio = (struct sioreg *)OBIO_SIO + ((int)dev & 0x1);
698 s = splhigh();
699 while ((getsiocsr(sio) & RR_TXRDY) == 0)
700 ;
701 sio->sio_cmd = WR0_RSTPEND;
702 sio->sio_data = c;
703 splx(s);
704 }
705