siotty.c revision 1.51 1 /* $NetBSD: siotty.c,v 1.51 2021/09/25 15:18:38 tsutsui Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
33
34 __KERNEL_RCSID(0, "$NetBSD: siotty.c,v 1.51 2021/09/25 15:18:38 tsutsui Exp $");
35
36 #include "opt_ddb.h"
37 #include "siotty.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/conf.h>
43 #include <sys/ioctl.h>
44 #include <sys/proc.h>
45 #include <sys/tty.h>
46 #include <sys/uio.h>
47 #include <sys/callout.h>
48 #include <sys/fcntl.h>
49 #include <dev/cons.h>
50 #include <sys/kauth.h>
51 #include <sys/kmem.h>
52
53 #include <machine/board.h>
54 #include <machine/cpu.h>
55
56 #include <luna68k/dev/sioreg.h>
57 #include <luna68k/dev/siovar.h>
58
59 #include "ioconf.h"
60
61 #define TIOCM_BREAK 01000 /* non standard use */
62
63 static const uint8_t ch0_regs[6] = {
64 WR0_RSTINT, /* reset E/S interrupt */
65 WR1_RXALLS | WR1_TXENBL | WR1_ESENBL, /* Rx per char, Tx, E/S */
66 0, /* */
67 WR3_RX8BIT | WR3_RXENBL, /* Rx */
68 WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
69 WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
70 };
71
72 static const struct speedtab siospeedtab[] = {
73 { 2400, WR4_BAUD24, },
74 { 4800, WR4_BAUD48, },
75 { 9600, WR4_BAUD96, },
76 { -1, 0, },
77 };
78
79 struct siotty_softc {
80 device_t sc_dev;
81 struct tty *sc_tty;
82 struct sioreg *sc_ctl;
83 u_int sc_flags;
84 uint8_t sc_wr[6];
85 void *sc_si; /* software interrupt handler */
86 u_int sc_hwflags;
87 #define SIOTTY_HW_CONSOLE 0x0001
88
89 uint8_t *sc_rbuf;
90 uint8_t *sc_rbufend;
91 uint8_t * volatile sc_rbget;
92 uint8_t * volatile sc_rbput;
93 volatile u_int sc_rbavail;
94
95 uint8_t *sc_tba;
96 u_int sc_tbc;
97
98 bool sc_rx_ready;
99 bool sc_tx_busy;
100 bool sc_tx_done;
101 };
102
103 #define SIOTTY_RING_SIZE 2048
104 u_int siotty_rbuf_size = SIOTTY_RING_SIZE;
105
106 static struct cnm_state siotty_cnm_state;
107
108 static void siostart(struct tty *);
109 static int sioparam(struct tty *, struct termios *);
110 static void siottyintr(void *);
111 static void siottysoft(void *);
112 static void siotty_rxsoft(struct siotty_softc *, struct tty *);
113 static void siotty_txsoft(struct siotty_softc *, struct tty *);
114 static int siomctl(struct siotty_softc *, int, int);
115
116 static int siotty_match(device_t, cfdata_t, void *);
117 static void siotty_attach(device_t, device_t, void *);
118
119 CFATTACH_DECL_NEW(siotty, sizeof(struct siotty_softc),
120 siotty_match, siotty_attach, NULL, NULL);
121
122 static dev_type_open(sioopen);
123 static dev_type_close(sioclose);
124 static dev_type_read(sioread);
125 static dev_type_write(siowrite);
126 static dev_type_ioctl(sioioctl);
127 static dev_type_stop(siostop);
128 static dev_type_tty(siotty);
129 static dev_type_poll(siopoll);
130
131 static dev_type_cninit(siottycninit);
132 static dev_type_cngetc(siottycngetc);
133 static dev_type_cnputc(siottycnputc);
134
135 const struct cdevsw siotty_cdevsw = {
136 .d_open = sioopen,
137 .d_close = sioclose,
138 .d_read = sioread,
139 .d_write = siowrite,
140 .d_ioctl = sioioctl,
141 .d_stop = siostop,
142 .d_tty = siotty,
143 .d_poll = siopoll,
144 .d_mmap = nommap,
145 .d_kqfilter = ttykqfilter,
146 .d_discard = nodiscard,
147 .d_flag = D_TTY
148 };
149
150 static int
151 siotty_match(device_t parent, cfdata_t cf, void *aux)
152 {
153 struct sio_attach_args *args = aux;
154
155 if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
156 return 0;
157 return 1;
158 }
159
160 static void
161 siotty_attach(device_t parent, device_t self, void *aux)
162 {
163 struct sio_softc *siosc = device_private(parent);
164 struct siotty_softc *sc = device_private(self);
165 struct sio_attach_args *args = aux;
166 int channel;
167 struct tty *tp;
168
169 sc->sc_dev = self;
170 channel = args->channel;
171 sc->sc_ctl = &siosc->sc_ctl[channel];
172 memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
173 siosc->sc_intrhand[channel].ih_func = siottyintr;
174 siosc->sc_intrhand[channel].ih_arg = sc;
175 if (args->hwflags == 1)
176 sc->sc_hwflags |= SIOTTY_HW_CONSOLE;
177
178 if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0) {
179 aprint_normal(" (console)");
180 sc->sc_flags = TIOCFLAG_SOFTCAR;
181 } else {
182 setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
183 setsioreg(&siosc->sc_ctl[0], WR2A, WR2A_VEC86 | WR2A_INTR_1);
184 setsioreg(&siosc->sc_ctl[1], WR2B, 0);
185 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
186 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
187 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
188 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
189 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
190 }
191 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
192
193 aprint_normal("\n");
194
195 sc->sc_rbuf = kmem_alloc(siotty_rbuf_size * 2, KM_SLEEP);
196 sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2);
197 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
198 sc->sc_rbavail = siotty_rbuf_size;
199
200 tp = tty_alloc();
201 tp->t_oproc = siostart;
202 tp->t_param = sioparam;
203 tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
204 if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0)
205 tp->t_dev = cn_tab->cn_dev;
206 sc->sc_tty = tp;
207
208 tty_attach(tp);
209
210 sc->sc_si = softint_establish(SOFTINT_SERIAL, siottysoft, sc);
211 }
212
213 /*-------------------- low level routine --------------------*/
214
215 static void
216 siottyintr(void *arg)
217 {
218 struct siotty_softc *sc;
219 struct sioreg *sio;
220 uint8_t *put, *end;
221 uint8_t c;
222 uint16_t rr;
223 int cc;
224
225 sc = arg;
226 end = sc->sc_rbufend;
227 put = sc->sc_rbput;
228 cc = sc->sc_rbavail;
229
230 sio = sc->sc_ctl;
231 rr = getsiocsr(sio);
232 if ((rr & RR_BREAK) != 0) {
233 cn_check_magic(sc->sc_tty->t_dev, CNC_BREAK, siotty_cnm_state);
234 }
235 /* XXX should handle RR_DCD and RR_CTS */
236 sio->sio_cmd = WR0_RSTINT;
237
238 if ((rr & RR_RXRDY) != 0) {
239 do {
240 if (cc > 0) {
241 c = sio->sio_data;
242 cn_check_magic(sc->sc_tty->t_dev, c,
243 siotty_cnm_state);
244 put[0] = c;
245 put[1] = rr & 0xff;
246 put += 2;
247 if (put >= end)
248 put = sc->sc_rbuf;
249 cc--;
250 }
251 if ((rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) != 0)
252 sio->sio_cmd = WR0_ERRRST;
253
254 sc->sc_rbput = put;
255 sc->sc_rbavail = cc;
256 sc->sc_rx_ready = true;
257 } while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0);
258 }
259 if ((rr & RR_TXRDY) != 0) {
260 sio->sio_cmd = WR0_RSTPEND;
261 if (sc->sc_tbc > 0) {
262 sio->sio_data = *sc->sc_tba;
263 sc->sc_tba++;
264 sc->sc_tbc--;
265 } else {
266 if (sc->sc_tx_busy) {
267 sc->sc_tx_busy = false;
268 sc->sc_tx_done = true;
269 }
270 }
271 }
272 softint_schedule(sc->sc_si);
273 }
274
275 static void
276 siottysoft(void *arg)
277 {
278 struct siotty_softc *sc;
279 struct tty *tp;
280
281 sc = arg;
282 tp = sc->sc_tty;
283
284 if (sc->sc_rx_ready) {
285 sc->sc_rx_ready = false;
286 siotty_rxsoft(sc, tp);
287 }
288 if (sc->sc_tx_done) {
289 sc->sc_tx_done = false;
290 siotty_txsoft(sc, tp);
291 }
292 }
293
294 static void
295 siotty_rxsoft(struct siotty_softc *sc, struct tty *tp)
296 {
297 uint8_t *get, *end;
298 u_int cc, scc;
299 unsigned int code;
300 uint8_t stat;
301 int s;
302
303 end = sc->sc_rbufend;
304 get = sc->sc_rbget;
305 scc = cc = siotty_rbuf_size - sc->sc_rbavail;
306
307 if (cc == siotty_rbuf_size) {
308 printf("%s: rx buffer overflow\n", device_xname(sc->sc_dev));
309 }
310
311 while (cc > 0) {
312 code = get[0];
313 stat = get[1];
314 if ((stat & RR_FRAMING) != 0)
315 code |= TTY_FE;
316 else if ((stat & RR_PARITY) != 0)
317 code |= TTY_PE;
318
319 (*tp->t_linesw->l_rint)(code, tp);
320 get += 2;
321 if (get >= end)
322 get = sc->sc_rbuf;
323 cc--;
324 }
325
326 if (cc != scc) {
327 s = splserial();
328 sc->sc_rbget = get;
329 sc->sc_rbavail += scc - cc;
330 splx(s);
331 }
332 }
333
334 static void
335 siotty_txsoft(struct siotty_softc *sc, struct tty *tp)
336 {
337
338 tp->t_state &= ~TS_BUSY;
339 if ((tp->t_state & TS_FLUSH) != 0)
340 tp->t_state &= ~TS_FLUSH;
341 else
342 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
343 (*tp->t_linesw->l_start)(tp);
344 }
345
346 static void
347 siostart(struct tty *tp)
348 {
349 struct siotty_softc *sc;
350 int s;
351 uint8_t *tba;
352 int tbc;
353
354 sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
355 s = splserial();
356 if ((tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP)) != 0)
357 goto out;
358 if (!ttypull(tp))
359 goto out;
360 tp->t_state |= TS_BUSY;
361
362 tba = tp->t_outq.c_cf;
363 tbc = ndqb(&tp->t_outq, 0);
364
365 sc->sc_tba = tba;
366 sc->sc_tbc = tbc;
367 sc->sc_tx_busy = true;
368
369 sc->sc_ctl->sio_data = *sc->sc_tba;
370 sc->sc_tba++;
371 sc->sc_tbc--;
372 out:
373 splx(s);
374 }
375
376 static void
377 siostop(struct tty *tp, int flag)
378 {
379 int s;
380
381 s = splserial();
382 if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
383 /*
384 * Device is transmitting; must stop it.
385 */
386 tp->t_state |= TS_FLUSH;
387 }
388 splx(s);
389 }
390
391 static int
392 sioparam(struct tty *tp, struct termios *t)
393 {
394 struct siotty_softc *sc;
395 int wr4, s;
396
397 sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
398 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
399 return EINVAL;
400 wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
401 if (wr4 < 0)
402 return EINVAL;
403
404 if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0) {
405 t->c_cflag |= CLOCAL;
406 t->c_cflag &= ~HUPCL;
407 }
408 if ((sc->sc_flags & TIOCFLAG_CLOCAL) != 0)
409 t->c_cflag |= CLOCAL;
410
411 /*
412 * If there were no changes, don't do anything. This avoids dropping
413 * input and improves performance when all we did was frob things like
414 * VMIN and VTIME.
415 */
416 if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
417 return 0;
418
419 tp->t_ispeed = t->c_ispeed;
420 tp->t_ospeed = t->c_ospeed;
421 tp->t_cflag = t->c_cflag;
422
423 sc->sc_wr[WR3] &= ~WR3_RX8BIT;
424 sc->sc_wr[WR5] &= ~WR5_TX8BIT;
425 switch (tp->t_cflag & CSIZE) {
426 case CS7:
427 sc->sc_wr[WR3] |= WR3_RX7BIT;
428 sc->sc_wr[WR5] |= WR5_TX7BIT;
429 break;
430 case CS8:
431 sc->sc_wr[WR3] |= WR3_RX8BIT;
432 sc->sc_wr[WR5] |= WR5_TX8BIT;
433 break;
434 }
435 if ((tp->t_cflag & PARENB) != 0) {
436 wr4 |= WR4_PARENAB;
437 if ((tp->t_cflag & PARODD) == 0)
438 wr4 |= WR4_EPARITY;
439 }
440 wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
441 sc->sc_wr[WR4] = wr4;
442
443 s = splserial();
444 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
445 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
446 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
447 splx(s);
448
449 return 0;
450 }
451
452 static int
453 siomctl(struct siotty_softc *sc, int control, int op)
454 {
455 int val, s;
456 uint8_t wr5;
457 uint16_t rr;
458
459 val = 0;
460 if ((control & TIOCM_BREAK) != 0)
461 val |= WR5_BREAK;
462 if ((control & TIOCM_DTR) != 0)
463 val |= WR5_DTR;
464 if ((control & TIOCM_RTS) != 0)
465 val |= WR5_RTS;
466 s = splserial();
467 wr5 = sc->sc_wr[WR5];
468 switch (op) {
469 case DMSET:
470 wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
471 /* FALLTHRU */
472 case DMBIS:
473 wr5 |= val;
474 break;
475 case DMBIC:
476 wr5 &= ~val;
477 break;
478 case DMGET:
479 val = 0;
480 rr = getsiocsr(sc->sc_ctl);
481 if ((wr5 & WR5_DTR) != 0)
482 val |= TIOCM_DTR;
483 if ((wr5 & WR5_RTS) != 0)
484 val |= TIOCM_RTS;
485 if ((rr & RR_CTS) != 0)
486 val |= TIOCM_CTS;
487 if ((rr & RR_DCD) != 0)
488 val |= TIOCM_CD;
489 goto done;
490 }
491 sc->sc_wr[WR5] = wr5;
492 setsioreg(sc->sc_ctl, WR5, wr5);
493 val = 0;
494 done:
495 splx(s);
496 return val;
497 }
498
499 /*-------------------- cdevsw[] interface --------------------*/
500
501 static int
502 sioopen(dev_t dev, int flag, int mode, struct lwp *l)
503 {
504 struct siotty_softc *sc;
505 struct tty *tp;
506 int error;
507 int s;
508
509 sc = device_lookup_private(&siotty_cd, minor(dev));
510 if (sc == NULL)
511 return ENXIO;
512
513 tp = sc->sc_tty;
514
515 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
516 return EBUSY;
517
518 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
519 struct termios t;
520
521 tp->t_dev = dev;
522 t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
523 t.c_cflag = TTYDEF_CFLAG;
524 tp->t_ospeed = 0; /* force register update */
525 (void)sioparam(tp, &t);
526 tp->t_iflag = TTYDEF_IFLAG;
527 tp->t_oflag = TTYDEF_OFLAG;
528 tp->t_lflag = TTYDEF_LFLAG;
529 ttychars(tp);
530 ttsetwater(tp);
531 /* raise RTS and DTR here; but, DTR lead is not wired */
532 /* then check DCD condition; but, DCD lead is not wired */
533 #if 0
534 if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0 ||
535 (tp->t_cflag & MDMBUF) != 0 ||
536 (getsiocsr(sc->sc_ctl) & RR_DCD) != 0)
537 tp->t_state |= TS_CARR_ON;
538 else
539 tp->t_state &= ~TS_CARR_ON;
540 #else
541 tp->t_state |= TS_CARR_ON; /* assume detected all the time */
542 #endif
543
544 s = splserial();
545 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
546 sc->sc_rbavail = siotty_rbuf_size;
547 splx(s);
548 }
549
550 error = ttyopen(tp, 0, (flag & O_NONBLOCK));
551 if (error > 0)
552 return error;
553 return (*tp->t_linesw->l_open)(dev, tp);
554 }
555
556 static int
557 sioclose(dev_t dev, int flag, int mode, struct lwp *l)
558 {
559 struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
560 struct tty *tp = sc->sc_tty;
561 int s;
562
563 (*tp->t_linesw->l_close)(tp, flag);
564
565 s = splserial();
566 siomctl(sc, TIOCM_BREAK, DMBIC);
567 #if 0 /* because unable to feed DTR signal */
568 if ((tp->t_cflag & HUPCL) != 0 ||
569 tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
570 siomctl(sc, TIOCM_DTR, DMBIC);
571 /* Yield CPU time to others for 1 second, then ... */
572 siomctl(sc, TIOCM_DTR, DMBIS);
573 }
574 #endif
575 splx(s);
576 return ttyclose(tp);
577 }
578
579 static int
580 sioread(dev_t dev, struct uio *uio, int flag)
581 {
582 struct siotty_softc *sc;
583 struct tty *tp;
584
585 sc = device_lookup_private(&siotty_cd, minor(dev));
586 tp = sc->sc_tty;
587 return (*tp->t_linesw->l_read)(tp, uio, flag);
588 }
589
590 static int
591 siowrite(dev_t dev, struct uio *uio, int flag)
592 {
593 struct siotty_softc *sc;
594 struct tty *tp;
595
596 sc = device_lookup_private(&siotty_cd, minor(dev));
597 tp = sc->sc_tty;
598 return (*tp->t_linesw->l_write)(tp, uio, flag);
599 }
600
601 static int
602 siopoll(dev_t dev, int events, struct lwp *l)
603 {
604 struct siotty_softc *sc;
605 struct tty *tp;
606
607 sc = device_lookup_private(&siotty_cd, minor(dev));
608 tp = sc->sc_tty;
609 return (*tp->t_linesw->l_poll)(tp, events, l);
610 }
611
612 static int
613 sioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
614 {
615 struct siotty_softc *sc;
616 struct tty *tp;
617 int error;
618
619 sc = device_lookup_private(&siotty_cd, minor(dev));
620 tp = sc->sc_tty;
621 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
622 if (error != EPASSTHROUGH)
623 return error;
624
625 error = ttioctl(tp, cmd, data, flag, l);
626 if (error != EPASSTHROUGH)
627 return error;
628
629 /* the last resort for TIOC ioctl tranversing */
630 switch (cmd) {
631 case TIOCSBRK: /* Set the hardware into BREAK condition */
632 siomctl(sc, TIOCM_BREAK, DMBIS);
633 break;
634 case TIOCCBRK: /* Clear the hardware BREAK condition */
635 siomctl(sc, TIOCM_BREAK, DMBIC);
636 break;
637 case TIOCSDTR: /* Assert DTR signal */
638 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
639 break;
640 case TIOCCDTR: /* Clear DTR signal */
641 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
642 break;
643 case TIOCMSET: /* Set modem state replacing current one */
644 siomctl(sc, *(int *)data, DMSET);
645 break;
646 case TIOCMGET: /* Return current modem state */
647 *(int *)data = siomctl(sc, 0, DMGET);
648 break;
649 case TIOCMBIS: /* Set individual bits of modem state */
650 siomctl(sc, *(int *)data, DMBIS);
651 break;
652 case TIOCMBIC: /* Clear individual bits of modem state */
653 siomctl(sc, *(int *)data, DMBIC);
654 break;
655 case TIOCSFLAGS: /* Instruct how serial port behaves */
656 sc->sc_flags = *(int *)data;
657 break;
658 case TIOCGFLAGS: /* Return current serial port state */
659 *(int *)data = sc->sc_flags;
660 break;
661 default:
662 return EPASSTHROUGH;
663 }
664 return 0;
665 }
666
667 /* ARSGUSED */
668 static struct tty *
669 siotty(dev_t dev)
670 {
671 struct siotty_softc *sc;
672
673 sc = device_lookup_private(&siotty_cd, minor(dev));
674 return sc->sc_tty;
675 }
676
677 /*--------------------- console interface ----------------------*/
678
679 struct consdev siottycons = {
680 .cn_probe = NULL,
681 .cn_init = siottycninit,
682 .cn_getc = siottycngetc,
683 .cn_putc = siottycnputc,
684 .cn_pollc = nullcnpollc,
685 .cn_bell = NULL,
686 .cn_halt = NULL,
687 .cn_flush = NULL,
688 .cn_dev = NODEV,
689 .cn_pri = CN_REMOTE,
690 };
691
692 static void
693 siottycninit(struct consdev *cn)
694 {
695 /*
696 * Channel A is immediately initialized with 9600N1 right after cold
697 * boot/reset/poweron. ROM monitor emits one line message on CH.A.
698 */
699 struct sioreg *sio, *sio_base, *sio_a, *sio_b;
700
701 sio_base = (struct sioreg *)OBIO_SIO;
702 sio_a = &sio_base[0];
703 sio_b = &sio_base[1];
704 sio = sio_a;
705
706 siottycons.cn_dev =
707 makedev(cdevsw_lookup_major(&siotty_cdevsw), 0);
708 cn_init_magic(&siotty_cnm_state);
709 cn_set_magic("\047\001");
710
711 setsioreg(sio, WR0, WR0_CHANRST);
712 setsioreg(sio_a, WR2A, WR2A_VEC86 | WR2A_INTR_1);
713 setsioreg(sio_b, WR2B, 0);
714 setsioreg(sio, WR0, ch0_regs[WR0]);
715 setsioreg(sio, WR4, ch0_regs[WR4]);
716 setsioreg(sio, WR3, ch0_regs[WR3]);
717 setsioreg(sio, WR5, ch0_regs[WR5]);
718 setsioreg(sio, WR0, ch0_regs[WR0]);
719 }
720
721 static int
722 siottycngetc(dev_t dev)
723 {
724 struct sioreg *sio;
725
726 sio = (struct sioreg *)OBIO_SIO;
727 return siogetc(sio);
728 }
729
730 static void
731 siottycnputc(dev_t dev, int c)
732 {
733 struct sioreg *sio;
734
735 sio = (struct sioreg *)OBIO_SIO;
736 sioputc(sio, c);
737 }
738