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