xref: /openbsd-src/sys/arch/sparc64/dev/sab.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: sab.c,v 1.1 2001/10/28 02:19:16 jason Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Jason L. Wright
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * SAB82532 Dual UART driver
36  */
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/conf.h>
43 #include <sys/file.h>
44 #include <sys/ioctl.h>
45 #include <sys/kernel.h>
46 #include <sys/proc.h>
47 #include <sys/tty.h>
48 #include <sys/time.h>
49 #include <sys/syslog.h>
50 
51 #include <machine/autoconf.h>
52 #include <machine/openfirm.h>
53 #include <machine/bsd_openprom.h>
54 #include <machine/conf.h>
55 #include <machine/cpu.h>
56 #include <machine/eeprom.h>
57 #include <machine/psl.h>
58 
59 #include <dev/cons.h>
60 #include <ddb/db_output.h>
61 
62 #include <sparc64/dev/ebusreg.h>
63 #include <sparc64/dev/ebusvar.h>
64 #include <sparc64/dev/cons.h>
65 #include <sparc64/dev/sab82532reg.h>
66 
67 #define	SAB_CARD(x)	((minor(x) >> 6) & 3)
68 #define	SAB_PORT(x)	(minor(x) & 7)
69 #define	SAB_DIALOUT(x)	(minor(x) & 0x10)
70 #define	SABTTY_RBUF_SIZE	1024	/* must be divisible by 2 */
71 
72 struct sab_softc {
73 	struct device		sc_dv;
74 	struct intrhand *	sc_ih;
75 	bus_space_tag_t		sc_bt;
76 	bus_space_handle_t	sc_bh;
77 	struct sabtty_softc *	sc_child[SAB_NCHAN];
78 	u_int			sc_nchild;
79 	void *			sc_softintr;
80 };
81 
82 struct sabtty_attach_args {
83 	u_int sbt_portno;
84 };
85 
86 struct sabtty_softc {
87 	struct device		sc_dv;
88 	struct sab_softc *	sc_parent;
89 	bus_space_tag_t		sc_bt;
90 	bus_space_handle_t	sc_bh;
91 	struct tty *		sc_tty;
92 	u_int			sc_portno;
93 	u_int8_t		sc_pvr_dtr, sc_pvr_dsr;
94 	u_int8_t		sc_imr0, sc_imr1;
95 	int			sc_openflags;
96 	u_char *		sc_txp;
97 	int			sc_txc;
98 	int			sc_flags;
99 #define SABTTYF_STOP		0x01
100 #define	SABTTYF_DONE		0x02
101 #define	SABTTYF_RINGOVERFLOW	0x04
102 #define	SABTTYF_CDCHG		0x08
103 	u_int8_t		sc_rbuf[SABTTY_RBUF_SIZE];
104 	u_int8_t		*sc_rend, *sc_rput, *sc_rget;
105 };
106 
107 #define	SAB_READ(sc,r)		\
108     bus_space_read_1((sc)->sc_bt, (sc)->sc_bh, (r))
109 #define	SAB_WRITE(sc,r,v)	\
110     bus_space_write_1((sc)->sc_bt, (sc)->sc_bh, (r), (v))
111 
112 int sab_match __P((struct device *, void *, void *));
113 void sab_attach __P((struct device *, struct device *, void *));
114 int sab_print __P((void *, const char *));
115 int sab_intr __P((void *));
116 void sab_softintr __P((void *));
117 
118 int sabtty_match __P((struct device *, void *, void *));
119 void sabtty_attach __P((struct device *, struct device *, void *));
120 void sabtty_start __P((struct tty *));
121 int sabtty_param __P((struct tty *, struct termios *));
122 int sabtty_intr __P((struct sabtty_softc *, int *));
123 void sabtty_softintr __P((struct sabtty_softc *));
124 int sabtty_mdmctrl __P((struct sabtty_softc *, int, int));
125 void sabtty_cec_wait __P((struct sabtty_softc *));
126 void sabtty_tec_wait __P((struct sabtty_softc *));
127 void sabtty_reset __P((struct sabtty_softc *));
128 void sabtty_flush __P((struct sabtty_softc *));
129 int sabtty_speed __P((int));
130 
131 int sabttyopen __P((dev_t, int, int, struct proc *));
132 int sabttyclose __P((dev_t, int, int, struct proc *));
133 int sabttyread __P((dev_t, struct uio *, int));
134 int sabttywrite __P((dev_t, struct uio *, int));
135 int sabttyioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
136 int sabttystop __P((struct tty *, int));
137 struct tty *sabttytty __P((dev_t));
138 
139 struct cfattach sab_ca = {
140 	sizeof(struct sab_softc), sab_match, sab_attach
141 };
142 
143 struct cfdriver sab_cd = {
144 	NULL, "sab", DV_DULL
145 };
146 
147 struct cfattach sabtty_ca = {
148 	sizeof(struct sabtty_softc), sabtty_match, sabtty_attach
149 };
150 
151 struct cfdriver sabtty_cd = {
152 	NULL, "sabtty", DV_TTY
153 };
154 
155 struct sabtty_rate {
156 	int baud;
157 	int n, m;
158 };
159 
160 struct sabtty_rate sabtty_baudtable[] = {
161 	{      50,	35,     10 },
162 	{      75,	47,	9 },
163 	{     110,	32,	9 },
164 	{     134,	53,	8 },
165 	{     150,	47,	8 },
166 	{     200,	35,	8 },
167 	{     300,	47,	7 },
168 	{     600,	47,	6 },
169 	{    1200,	47,	5 },
170 	{    1800,	31,	5 },
171 	{    2400,	47,	4 },
172 	{    4800,	47,	3 },
173 	{    9600,	47,	2 },
174 	{   19200,	47,	1 },
175 	{   38400,	23,	1 },
176 	{   57600,	15,	1 },
177 	{  115200,	 7,	1 },
178 	{  230400,	 3,	1 },
179 	{  460800,	 1,	1 },
180 	{   76800,	11,	1 },
181 	{  153600,	 5,	1 },
182 	{  307200,	 3,	1 },
183 	{  614400,	 3,	0 },
184 	{  921600,	 0,	1 },
185 };
186 
187 int
188 sab_match(parent, match, aux)
189 	struct device *parent;
190 	void *match, *aux;
191 {
192 	struct ebus_attach_args *ea = aux;
193 
194 	if (strcmp(ea->ea_name, "se") == 0)
195 		return (1);
196 	return (0);
197 }
198 
199 void
200 sab_attach(parent, self, aux)
201 	struct device *parent;
202 	struct device *self;
203 	void *aux;
204 {
205 	struct sab_softc *sc = (struct sab_softc *)self;
206 	struct ebus_attach_args *ea = aux;
207 	u_int8_t r;
208 	u_int i;
209 
210 	sc->sc_bt = ea->ea_bustag;
211 
212 	/* Use prom mapping, if available. */
213 	if (ea->ea_nvaddrs)
214 		sc->sc_bh = (bus_space_handle_t)ea->ea_vaddrs[0];
215 	else if (ebus_bus_map(sc->sc_bt, 0,
216 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size,
217 	    BUS_SPACE_MAP_LINEAR, 0, &sc->sc_bh) != 0) {
218 		printf(": can't map register space\n");
219 		return;
220 	}
221 
222 	sc->sc_ih = bus_intr_establish(ea->ea_bustag, ea->ea_intrs[0],
223 	    IPL_TTY, 0, sab_intr, sc);
224 	if (sc->sc_ih == NULL) {
225 		printf(": can't map interrupt\n");
226 		return;
227 	}
228 
229 	sc->sc_softintr = softintr_establish(IPL_TTY, sab_softintr, sc);
230 	if (sc->sc_softintr == NULL) {
231 		printf(": can't get soft intr\n");
232 		return;
233 	}
234 
235 	printf(": rev ");
236 	r = SAB_READ(sc, SAB_VSTR) & SAB_VSTR_VMASK;
237 	switch (r) {
238 	case SAB_VSTR_V_1:
239 		printf("1");
240 		break;
241 	case SAB_VSTR_V_2:
242 		printf("2");
243 		break;
244 	case SAB_VSTR_V_32:
245 		printf("3.2");
246 		break;
247 	default:
248 		printf("unknown(0x%x)", r);
249 		break;
250 	}
251 	printf("\n");
252 
253 	/* Set all pins, except DTR pins to be inputs */
254 	SAB_WRITE(sc, SAB_PCR, ~(SAB_PVR_DTR_A | SAB_PVR_DTR_B));
255 	/* Disable port interrupts */
256 	SAB_WRITE(sc, SAB_PIM, 0xff);
257 	SAB_WRITE(sc, SAB_PVR, SAB_PVR_DTR_A | SAB_PVR_DTR_B | SAB_PVR_MAGIC);
258 	SAB_WRITE(sc, SAB_IPC, SAB_IPC_ICPL);
259 
260 	for (i = 0; i < SAB_NCHAN; i++) {
261 		struct sabtty_attach_args sta;
262 
263 		sta.sbt_portno = i;
264 		sc->sc_child[i] = (struct sabtty_softc *)config_found_sm(self,
265 		    &sta, sab_print, sabtty_match);
266 		if (sc->sc_child[i] != NULL)
267 			sc->sc_nchild++;
268 	}
269 }
270 
271 int
272 sab_print(args, name)
273 	void *args;
274 	const char *name;
275 {
276 	struct sabtty_attach_args *sa = args;
277 
278 	if (name)
279 		printf("sabtty at %s", name);
280 	printf(" port %d", sa->sbt_portno);
281 	return (UNCONF);
282 }
283 
284 int
285 sab_intr(vsc)
286 	void *vsc;
287 {
288 	struct sab_softc *sc = vsc;
289 	int r = 0, needsoft = 0;
290 	u_int8_t gis;
291 
292 	gis = SAB_READ(sc, SAB_GIS);
293 
294 	/* channel A */
295 	if ((gis & (SAB_GIS_ISA1 | SAB_GIS_ISA0)) && sc->sc_child[0] &&
296 	    sc->sc_child[0]->sc_tty)
297 		r |= sabtty_intr(sc->sc_child[0], &needsoft);
298 
299 	/* channel B */
300 	if ((gis & (SAB_GIS_ISB1 | SAB_GIS_ISB0)) && sc->sc_child[1] &&
301 	    sc->sc_child[1]->sc_tty)
302 		r |= sabtty_intr(sc->sc_child[1], &needsoft);
303 
304 	if (needsoft)
305 		softintr_schedule(sc->sc_softintr);
306 
307 	return (r);
308 }
309 
310 void
311 sab_softintr(vsc)
312 	void *vsc;
313 {
314 	struct sab_softc *sc = vsc;
315 
316 	if (sc->sc_child[0] && sc->sc_child[0]->sc_tty)
317 		sabtty_softintr(sc->sc_child[0]);
318 	if (sc->sc_child[1] && sc->sc_child[1]->sc_tty)
319 		sabtty_softintr(sc->sc_child[1]);
320 }
321 
322 int
323 sabtty_match(parent, match, aux)
324 	struct device *parent;
325 	void *match, *aux;
326 {
327 	struct sabtty_attach_args *sa = aux;
328 
329 	if (sa->sbt_portno < SAB_NCHAN)
330 		return (1);
331 	return (0);
332 }
333 
334 void
335 sabtty_attach(parent, self, aux)
336 	struct device *parent;
337 	struct device *self;
338 	void *aux;
339 {
340 	struct sabtty_softc *sc = (struct sabtty_softc *)self;
341 	struct sabtty_attach_args *sa = aux;
342 	int r;
343 
344 	sc->sc_tty = ttymalloc();
345 	if (sc->sc_tty == NULL) {
346 		printf(": failed to allocate tty\n");
347 		return;
348 	}
349 	tty_attach(sc->sc_tty);
350 	sc->sc_tty->t_oproc = sabtty_start;
351 	sc->sc_tty->t_param = sabtty_param;
352 
353 	sc->sc_parent = (struct sab_softc *)parent;
354 	sc->sc_bt = sc->sc_parent->sc_bt;
355 	sc->sc_portno = sa->sbt_portno;
356 	sc->sc_rend = sc->sc_rbuf + SABTTY_RBUF_SIZE;
357 
358 	switch (sa->sbt_portno) {
359 	case 0:	/* port A */
360 		sc->sc_pvr_dtr = SAB_PVR_DTR_A;
361 		sc->sc_pvr_dsr = SAB_PVR_DSR_A;
362 		r = bus_space_subregion(sc->sc_bt, sc->sc_parent->sc_bh,
363 		    SAB_CHAN_A, SAB_CHANLEN, &sc->sc_bh);
364 		break;
365 	case 1:	/* port B */
366 		sc->sc_pvr_dtr = SAB_PVR_DTR_B;
367 		sc->sc_pvr_dsr = SAB_PVR_DSR_B;
368 		r = bus_space_subregion(sc->sc_bt, sc->sc_parent->sc_bh,
369 		    SAB_CHAN_B, SAB_CHANLEN, &sc->sc_bh);
370 		break;
371 	default:
372 		printf(": invalid channel: %u\n", sa->sbt_portno);
373 		return;
374 	}
375 	if (r != 0) {
376 		printf(": failed to allocate register subregion\n");
377 		return;
378 	}
379 
380 	sabtty_reset(sc);
381 	printf("\n");
382 }
383 
384 int
385 sabtty_intr(sc, needsoftp)
386 	struct sabtty_softc *sc;
387 	int *needsoftp;
388 {
389 	u_int8_t isr0, isr1;
390 	int i, len = 0, needsoft = 0, r = 0, clearfifo = 0;
391 
392 	isr0 = SAB_READ(sc, SAB_ISR0);
393 	isr1 = SAB_READ(sc, SAB_ISR1);
394 
395 	if (isr0 || isr1)
396 		r = 1;
397 
398 	if (isr0 & SAB_ISR0_RPF) {
399 		len = 32;
400 		clearfifo = 1;
401 	}
402 	if (isr0 & SAB_ISR0_TCD) {
403 		len = (32 - 1) & SAB_READ(sc, SAB_RBCL);
404 		clearfifo = 1;
405 	}
406 	if (isr0 & SAB_ISR0_TIME) {
407 		sabtty_cec_wait(sc);
408 		SAB_WRITE(sc, SAB_CMDR, SAB_CMDR_RFRD);
409 	}
410 	if (isr0 & SAB_ISR0_RFO) {
411 		sc->sc_flags |= SABTTYF_RINGOVERFLOW;
412 		clearfifo = 1;
413 	}
414 	if (len != 0) {
415 		u_int8_t *ptr;
416 
417 		ptr = sc->sc_rput;
418 		for (i = 0; i < len; i++) {
419 			*ptr++ = SAB_READ(sc, SAB_RFIFO);
420 			if (ptr == sc->sc_rend)
421 				ptr = sc->sc_rbuf;
422 			if (ptr == sc->sc_rget) {
423 				if (ptr == sc->sc_rbuf)
424 					ptr = sc->sc_rend;
425 				ptr--;
426 				sc->sc_flags |= SABTTYF_RINGOVERFLOW;
427 			}
428 		}
429 		sc->sc_rput = ptr;
430 		needsoft = 1;
431 	}
432 
433 	if (clearfifo) {
434 		sabtty_cec_wait(sc);
435 		SAB_WRITE(sc, SAB_CMDR, SAB_CMDR_RMC);
436 	}
437 
438 	if (isr0 & SAB_ISR0_CDSC) {
439 		sc->sc_flags |= SABTTYF_CDCHG;
440 		needsoft = 1;
441 	}
442 
443 	if (isr1 & SAB_ISR1_XPR) {
444 		r = 1;
445 		if ((sc->sc_flags & SABTTYF_STOP) == 0) {
446 			len = 32;
447 			if (sc->sc_txc < 32)
448 				len = sc->sc_txc;
449 			for (i = 0; i < len; i++) {
450 				SAB_WRITE(sc, SAB_XFIFO + i, *sc->sc_txp);
451 				sc->sc_txp++;
452 				sc->sc_txc--;
453 			}
454 			if (i != 0) {
455 				sabtty_cec_wait(sc);
456 				SAB_WRITE(sc, SAB_CMDR, SAB_CMDR_XF);
457 			}
458 		}
459 
460 		if ((sc->sc_txc == 0) || (sc->sc_flags & SABTTYF_STOP)) {
461 			sc->sc_imr1 |= SAB_IMR1_XPR;
462 			SAB_WRITE(sc, SAB_IMR1, sc->sc_imr1);
463 			sc->sc_flags &= ~SABTTYF_STOP;
464 			sc->sc_flags |= SABTTYF_DONE;
465 			needsoft = 1;
466 		}
467 	}
468 
469 	if (needsoft)
470 		*needsoftp = needsoft;
471 	return (r);
472 }
473 
474 void
475 sabtty_softintr(sc)
476 	struct sabtty_softc *sc;
477 {
478 	struct tty *tp = sc->sc_tty;
479 	int s, flags;
480 	u_int8_t r;
481 
482 	if (tp == NULL)
483 		return;
484 
485 	if ((tp->t_state & TS_ISOPEN) == 0)
486 		return;
487 
488 	while (sc->sc_rget != sc->sc_rput) {
489 		int data;
490 		u_int8_t stat;
491 
492 		data = sc->sc_rget[0];
493 		stat = sc->sc_rget[1];
494 		sc->sc_rget += 2;
495 		if (stat & SAB_RSTAT_PE)
496 			data |= TTY_PE;
497 		if (stat & SAB_RSTAT_FE)
498 			data |= TTY_FE;
499 		if (sc->sc_rget == sc->sc_rend)
500 			sc->sc_rget = sc->sc_rbuf;
501 
502 		(*linesw[tp->t_line].l_rint)(data, tp);
503 	}
504 
505 	s = splhigh();
506 	flags = sc->sc_flags;
507 	sc->sc_flags &= ~(SABTTYF_DONE|SABTTYF_CDCHG|SABTTYF_RINGOVERFLOW);
508 	splx(s);
509 
510 	if (flags & SABTTYF_CDCHG) {
511 		s = spltty();
512 		r = SAB_READ(sc, SAB_VSTR) & SAB_VSTR_CD;
513 		splx(s);
514 
515 		(*linesw[tp->t_line].l_modem)(tp, r);
516 	}
517 
518 	if (flags & SABTTYF_RINGOVERFLOW)
519 		log(LOG_WARNING, "%s: ring overflow\n", sc->sc_dv.dv_xname);
520 
521 	if (flags & SABTTYF_DONE) {
522 		ndflush(&tp->t_outq, sc->sc_txp - tp->t_outq.c_cf);
523 		tp->t_state &= ~TS_BUSY;
524 		(*linesw[tp->t_line].l_start)(tp);
525 	}
526 }
527 
528 int
529 sabttyopen(dev, flags, mode, p)
530 	dev_t dev;
531 	int flags, mode;
532 	struct proc *p;
533 {
534 	struct sab_softc *bc;
535 	struct sabtty_softc *sc;
536 	struct tty *tp;
537 	int card = SAB_CARD(dev), port = SAB_PORT(dev), s;
538 
539 	if (card >= sab_cd.cd_ndevs)
540 		return (ENXIO);
541 	bc = sab_cd.cd_devs[card];
542 	if (bc == NULL)
543 		return (ENXIO);
544 
545 	if (port >= bc->sc_nchild)
546 		return (ENXIO);
547 	sc = bc->sc_child[port];
548 	if (sc == NULL)
549 		return (ENXIO);
550 
551 	tp = sc->sc_tty;
552 	tp->t_dev = dev;
553 
554 	if ((tp->t_state & TS_ISOPEN) == 0) {
555 		tp->t_state |= TS_WOPEN;
556 
557 		ttychars(tp);
558 		tp->t_iflag = TTYDEF_IFLAG;
559 		tp->t_oflag = TTYDEF_OFLAG;
560 		tp->t_cflag = TTYDEF_CFLAG;
561 		if (sc->sc_openflags & TIOCFLAG_CLOCAL)
562 			tp->t_cflag |= CLOCAL;
563 		if (sc->sc_openflags & TIOCFLAG_CRTSCTS)
564 			tp->t_cflag |= CRTSCTS;
565 		if (sc->sc_openflags & TIOCFLAG_MDMBUF)
566 			tp->t_cflag |= MDMBUF;
567 		tp->t_lflag = TTYDEF_LFLAG;
568 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
569 
570 		sc->sc_rput = sc->sc_rget = sc->sc_rbuf;
571 
572 		s = spltty();
573 
574 		sabtty_reset(sc);
575 		sabtty_param(tp, &tp->t_termios);
576 		ttsetwater(tp);
577 
578 		sc->sc_imr0 = SAB_IMR0_PERR | SAB_IMR0_FERR | SAB_IMR0_PLLA;
579 		SAB_WRITE(sc, SAB_IMR0, sc->sc_imr0);
580 
581 		sc->sc_imr1 = SAB_IMR1_BRKT | SAB_IMR1_ALLS | SAB_IMR1_XDU |
582 		    SAB_IMR1_TIN | SAB_IMR1_CSC | SAB_IMR1_XMR | SAB_IMR1_XPR;
583 		SAB_WRITE(sc, SAB_IMR1, sc->sc_imr1);
584 		SAB_WRITE(sc, SAB_CCR0, SAB_READ(sc, SAB_CCR0) | SAB_CCR0_PU);
585 		sabtty_flush(sc);
586 
587 		if ((sc->sc_openflags & TIOCFLAG_SOFTCAR) ||
588 		    (SAB_READ(sc, SAB_VSTR) & SAB_VSTR_CD))
589 			tp->t_state |= TS_CARR_ON;
590 		else
591 			tp->t_state &= ~TS_CARR_ON;
592 	} else if ((tp->t_state & TS_XCLUDE) &&
593 	    (!suser(p->p_ucred, &p->p_acflag))) {
594 		return (EBUSY);
595 	} else {
596 		s = spltty();
597 	}
598 
599 	if ((flags & O_NONBLOCK) == 0) {
600 		while ((tp->t_cflag & CLOCAL) == 0 &&
601 		    (tp->t_state & TS_CARR_ON) == 0) {
602 			int error;
603 
604 			tp->t_state |= TS_WOPEN;
605 			error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
606 			    "sabttycd", 0);
607 			if (error != 0) {
608 				splx(s);
609 				tp->t_state &= ~TS_WOPEN;
610 				return (error);
611 			}
612 		}
613 	}
614 
615 	splx(s);
616 
617 	return ((*linesw[tp->t_line].l_open)(dev, tp));
618 }
619 
620 int
621 sabttyclose(dev, flags, mode, p)
622 	dev_t dev;
623 	int flags, mode;
624 	struct proc *p;
625 {
626 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(dev)];
627 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(dev)];
628 	struct tty *tp = sc->sc_tty;
629 	int s;
630 
631 	(*linesw[tp->t_line].l_close)(tp, flags);
632 	s = spltty();
633 
634 	if ((tp->t_cflag & HUPCL) || ((tp->t_state & TS_ISOPEN) == 0)) {
635 		sabtty_mdmctrl(sc, 0, DMSET);
636 		sabtty_flush(sc);
637 		sabtty_reset(sc);
638 	}
639 	splx(s);
640 	ttyclose(tp);
641 	return (0);
642 }
643 
644 int
645 sabttyread(dev, uio, flags)
646 	dev_t dev;
647 	struct uio *uio;
648 	int flags;
649 {
650 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(dev)];
651 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(dev)];
652 	struct tty *tp = sc->sc_tty;
653 
654 	return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
655 }
656 
657 int
658 sabttywrite(dev, uio, flags)
659 	dev_t dev;
660 	struct uio *uio;
661 	int flags;
662 {
663 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(dev)];
664 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(dev)];
665 	struct tty *tp = sc->sc_tty;
666 
667 	return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
668 }
669 
670 int
671 sabttyioctl(dev, cmd, data, flags, p)
672 	dev_t dev;
673 	u_long cmd;
674 	caddr_t data;
675 	int flags;
676 	struct proc *p;
677 {
678 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(dev)];
679 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(dev)];
680 	struct tty *tp = sc->sc_tty;
681 	int error;
682 
683 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p);
684 	if (error >= 0)
685 		return (error);
686 
687 	error = ttioctl(tp, cmd, data, flags, p);
688 	if (error >= 0)
689 		return (error);
690 
691 	error = 0;
692 
693 	switch (cmd) {
694 	case TIOCSBRK:
695 		SAB_WRITE(sc, SAB_DAFO,
696 		    SAB_READ(sc, SAB_DAFO) | SAB_DAFO_XBRK);
697 		break;
698 	case TIOCCBRK:
699 		SAB_WRITE(sc, SAB_DAFO,
700 		    SAB_READ(sc, SAB_DAFO) & ~SAB_DAFO_XBRK);
701 		break;
702 	case TIOCSDTR:
703 		sabtty_mdmctrl(sc, TIOCM_DTR, DMBIS);
704 		break;
705 	case TIOCCDTR:
706 		sabtty_mdmctrl(sc, TIOCM_DTR, DMBIC);
707 		break;
708 	case TIOCMBIS:
709 		sabtty_mdmctrl(sc, *((int *)data), DMBIS);
710 		break;
711 	case TIOCMBIC:
712 		sabtty_mdmctrl(sc, *((int *)data), DMBIC);
713 		break;
714 	case TIOCMGET:
715 		*((int *)data) = sabtty_mdmctrl(sc, 0, DMGET);
716 		break;
717 	case TIOCMSET:
718 		sabtty_mdmctrl(sc, *((int *)data), DMSET);
719 		break;
720 	case TIOCGFLAGS:
721 		*((int *)data) = sc->sc_openflags;
722 		break;
723 	case TIOCSFLAGS:
724 		if (suser(p->p_ucred, &p->p_acflag))
725 			error = EPERM;
726 		else
727 			sc->sc_openflags = *((int *)data) &
728 			    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
729 			     TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
730 		break;
731 	default:
732 		error = ENOTTY;
733 	}
734 
735 	return (error);
736 }
737 
738 struct tty *
739 sabttytty(dev)
740 	dev_t dev;
741 {
742 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(dev)];
743 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(dev)];
744 
745 	return (sc->sc_tty);
746 }
747 
748 int
749 sabttystop(tp, flags)
750 	struct tty *tp;
751 	int flags;
752 {
753 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(tp->t_dev)];
754 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(tp->t_dev)];
755 	int s;
756 
757 	s = spltty();
758 	if (tp->t_state & TS_BUSY) {
759 		if ((tp->t_state & TS_TTSTOP) == 0)
760 			tp->t_state |= TS_FLUSH;
761 		sc->sc_flags |= SABTTYF_STOP;
762 	}
763 	splx(s);
764 	return (0);
765 }
766 
767 int
768 sabtty_mdmctrl(sc, bits, how)
769 	struct sabtty_softc *sc;
770 	int bits, how;
771 {
772 	u_int8_t r;
773 	int s;
774 
775 	s = spltty();
776 	switch (how) {
777 	case DMGET:
778 		bits = 0;
779 		if (SAB_READ(sc, SAB_STAR) & SAB_STAR_CTS)
780 			bits |= TIOCM_CTS;
781 		if ((SAB_READ(sc, SAB_VSTR) & SAB_VSTR_CD) == 0)
782 			bits |= TIOCM_CD;
783 
784 		r = SAB_READ(sc, SAB_PVR);
785 		if ((r & sc->sc_pvr_dtr) == 0)
786 			bits |= TIOCM_DTR;
787 		if ((r & sc->sc_pvr_dsr) == 0)
788 			bits |= TIOCM_DSR;
789 
790 		r = SAB_READ(sc, SAB_MODE);
791 		if ((r & (SAB_MODE_RTS|SAB_MODE_FRTS)) == SAB_MODE_RTS)
792 			bits |= TIOCM_RTS;
793 		break;
794 	case DMSET:
795 		r = SAB_READ(sc, SAB_MODE);
796 		if (bits & TIOCM_RTS) {
797 			r &= ~SAB_MODE_FRTS;
798 			r |= SAB_MODE_RTS;
799 		} else
800 			r |= SAB_MODE_FRTS | SAB_MODE_RTS;
801 		SAB_WRITE(sc, SAB_MODE, r);
802 
803 		r = SAB_READ(sc, SAB_PVR);
804 		if (bits & TIOCM_DTR)
805 			r &= ~sc->sc_pvr_dtr;
806 		else
807 			r |= sc->sc_pvr_dtr;
808 		SAB_WRITE(sc, SAB_PVR, r);
809 		break;
810 	case DMBIS:
811 		if (bits & TIOCM_RTS) {
812 			r = SAB_READ(sc, SAB_MODE);
813 			r &= ~SAB_MODE_FRTS;
814 			r |= SAB_MODE_RTS;
815 			SAB_WRITE(sc, SAB_MODE, r);
816 		}
817 		if (bits & TIOCM_DTR) {
818 			r = SAB_READ(sc, SAB_PVR);
819 			r &= ~sc->sc_pvr_dtr;
820 			SAB_WRITE(sc, SAB_PVR, r);
821 		}
822 		break;
823 	case DMBIC:
824 		if (bits & TIOCM_RTS) {
825 			r = SAB_READ(sc, SAB_MODE);
826 			r |= SAB_MODE_FRTS | SAB_MODE_RTS;
827 			SAB_WRITE(sc, SAB_MODE, r);
828 		}
829 		if (bits & TIOCM_DTR) {
830 			r = SAB_READ(sc, SAB_PVR);
831 			r |= sc->sc_pvr_dtr;
832 			SAB_WRITE(sc, SAB_PVR, r);
833 		}
834 		break;
835 	}
836 	splx(s);
837 	return (bits);
838 }
839 
840 int
841 sabtty_param(tp, t)
842 	struct tty *tp;
843 	struct termios *t;
844 {
845 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(tp->t_dev)];
846 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(tp->t_dev)];
847 	int s, ospeed;
848 	u_int8_t dafo, r;
849 
850 	ospeed = sabtty_speed(t->c_ospeed);
851 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
852 		return (EINVAL);
853 
854 	s = spltty();
855 
856 	/* hang up line if ospeed is zero, otherwise raise dtr */
857 	sabtty_mdmctrl(sc, TIOCM_DTR,
858 	    (t->c_ospeed == 0) ? DMBIC : DMBIS);
859 
860 	dafo = SAB_READ(sc, SAB_DAFO);
861 
862 	if (t->c_cflag & CSTOPB)
863 		dafo |= SAB_DAFO_STOP;
864 	else
865 		dafo &= ~SAB_DAFO_STOP;
866 
867 	dafo &= ~SAB_DAFO_CHL_CSIZE;
868 	switch (t->c_cflag & CSIZE) {
869 	case CS5:
870 		dafo |= SAB_DAFO_CHL_CS5;
871 		break;
872 	case CS6:
873 		dafo |= SAB_DAFO_CHL_CS6;
874 		break;
875 	case CS7:
876 		dafo |= SAB_DAFO_CHL_CS7;
877 		break;
878 	default:
879 		dafo |= SAB_DAFO_CHL_CS8;
880 		break;
881 	}
882 
883 	dafo &= ~SAB_DAFO_PARMASK;
884 	if (t->c_cflag & PARENB) {
885 		if (tp->t_cflag & PARODD)
886 			dafo |= SAB_DAFO_PAR_ODD;
887 		else
888 			dafo |= SAB_DAFO_PAR_EVEN;
889 	} else
890 		dafo |= SAB_DAFO_PAR_NONE;
891 
892 	if (ospeed != 0) {
893 		SAB_WRITE(sc, SAB_BGR, ospeed & 0xff);
894 		r = SAB_READ(sc, SAB_CCR2);
895 		r &= ~(SAB_CCR2_BR9 | SAB_CCR2_BR8);
896 		r |= (ospeed >> 2) & (SAB_CCR2_BR9 | SAB_CCR2_BR8);
897 		SAB_WRITE(sc, SAB_CCR2, r);
898 	}
899 
900 	r = SAB_READ(sc, SAB_MODE);
901 	r |= SAB_MODE_RAC;
902 	if (t->c_cflag & CRTSCTS) {
903 		r &= ~(SAB_MODE_RTS | SAB_MODE_FCTS);
904 		r |= SAB_MODE_FRTS;
905 		sc->sc_imr1 &= ~SAB_IMR1_CSC;
906 	} else {
907 		r |= SAB_MODE_RTS | SAB_MODE_FCTS;
908 		r &= ~SAB_MODE_FRTS;
909 		sc->sc_imr1 |= SAB_IMR1_CSC;
910 	}
911 	SAB_WRITE(sc, SAB_MODE, r);
912 	SAB_WRITE(sc, SAB_IMR1, sc->sc_imr1);
913 
914 	splx(s);
915 	return (0);
916 }
917 
918 void
919 sabtty_start(tp)
920 	struct tty *tp;
921 {
922 	struct sab_softc *bc = sab_cd.cd_devs[SAB_CARD(tp->t_dev)];
923 	struct sabtty_softc *sc = bc->sc_child[SAB_PORT(tp->t_dev)];
924 	int s;
925 
926 	s = spltty();
927 	if ((tp->t_state & (TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) == 0) {
928 		if (tp->t_outq.c_cc <= tp->t_lowat) {
929 			if (tp->t_state & TS_ASLEEP) {
930 				tp->t_state &= ~TS_ASLEEP;
931 				wakeup(&tp->t_outq);
932 			}
933 			selwakeup(&tp->t_wsel);
934 		}
935 		if (tp->t_outq.c_cc) {
936 			sc->sc_txc = ndqb(&tp->t_outq, 0);
937 			sc->sc_txp = tp->t_outq.c_cf;
938 			tp->t_state |= TS_BUSY;
939 			sc->sc_imr1 &= ~SAB_IMR1_XPR;
940 			SAB_WRITE(sc, SAB_IMR1, sc->sc_imr1);
941 		}
942 	}
943 	splx(s);
944 }
945 
946 void
947 sabtty_cec_wait(sc)
948 	struct sabtty_softc *sc;
949 {
950 	int i = 50000;
951 
952 	for (;;) {
953 		if ((SAB_READ(sc, SAB_STAR) & SAB_STAR_CEC) == 0)
954 			return;
955 		if (--i == 0)
956 			break;
957 		DELAY(1);
958 	}
959 	if (i == 0)
960 		printf("%s: cec timeout\n", sc->sc_dv.dv_xname);
961 }
962 
963 void
964 sabtty_tec_wait(sc)
965 	struct sabtty_softc *sc;
966 {
967 	int i = 200000;
968 
969 	for (;;) {
970 		if ((SAB_READ(sc, SAB_STAR) & SAB_STAR_TEC) == 0)
971 			return;
972 		if (--i == 0)
973 			break;
974 		DELAY(1);
975 	}
976 	if (i == 0)
977 		printf("%s: tec timeout\n", sc->sc_dv.dv_xname);
978 }
979 
980 void
981 sabtty_reset(sc)
982 	struct sabtty_softc *sc;
983 {
984 	/* power down */
985 	SAB_WRITE(sc, SAB_CCR0, 0);
986 
987 	/* set basic configuration */
988 	SAB_WRITE(sc, SAB_CCR0,
989 	    SAB_CCR0_MCE | SAB_CCR0_SC_NRZ | SAB_CCR0_SM_ASYNC);
990 	SAB_WRITE(sc, SAB_CCR1, SAB_CCR1_ODS | SAB_CCR1_BCR | SAB_CCR1_CM_7);
991 	SAB_WRITE(sc, SAB_CCR2, SAB_CCR2_BDF | SAB_CCR2_SSEL | SAB_CCR2_TOE);
992 	SAB_WRITE(sc, SAB_CCR3, 0);
993 	SAB_WRITE(sc, SAB_CCR4, SAB_CCR4_MCK4 | SAB_CCR4_EBRG);
994 	SAB_WRITE(sc, SAB_MODE, SAB_MODE_RTS | SAB_MODE_FCTS | SAB_MODE_RAC);
995 	SAB_WRITE(sc, SAB_RFC,
996 	    SAB_RFC_DPS | SAB_RFC_RFDF | SAB_RFC_RFTH_32CHAR);
997 
998 	/* clear interrupts */
999 	sc->sc_imr0 = sc->sc_imr1 = 0xff;
1000 	SAB_WRITE(sc, SAB_IMR0, sc->sc_imr0);
1001 	SAB_WRITE(sc, SAB_IMR1, sc->sc_imr1);
1002 	SAB_READ(sc, SAB_ISR0);
1003 	SAB_READ(sc, SAB_ISR1);
1004 }
1005 
1006 void
1007 sabtty_flush(sc)
1008 	struct sabtty_softc *sc;
1009 {
1010 	/* clear rx fifo */
1011 	sabtty_cec_wait(sc);
1012 	SAB_WRITE(sc, SAB_CMDR, SAB_CMDR_RRES);
1013 
1014 	/* clear tx fifo */
1015 	sabtty_cec_wait(sc);
1016 	SAB_WRITE(sc, SAB_CMDR, SAB_CMDR_XRES);
1017 }
1018 
1019 int
1020 sabtty_speed(rate)
1021 	int rate;
1022 {
1023 	int i, len, r;
1024 
1025 	if (rate == 0)
1026 		return (0);
1027 	len = sizeof(sabtty_baudtable)/sizeof(sabtty_baudtable[0]);
1028 	for (i = 0; i < len; i++) {
1029 		if (rate == sabtty_baudtable[i].baud) {
1030 			r = sabtty_baudtable[i].n |
1031 			    (sabtty_baudtable[i].m << 6);
1032 			return (r);
1033 		}
1034 	}
1035 	return (-1);
1036 }
1037