xref: /netbsd-src/sys/arch/arm/clps711x/clpscom.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*      $NetBSD: clpscom.c,v 1.2 2014/03/16 05:20:23 dholland Exp $      */
2 /*
3  * Copyright (c) 2013 KIYOHARA Takashi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: clpscom.c,v 1.2 2014/03/16 05:20:23 dholland Exp $");
29 
30 #include "rnd.h"
31 
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/device.h>
36 #include <sys/errno.h>
37 #include <sys/fcntl.h>
38 #include <sys/intr.h>
39 #include <sys/kauth.h>
40 #include <sys/lwp.h>
41 #include <sys/malloc.h>
42 #include <sys/systm.h>
43 #include <sys/termios.h>
44 #include <sys/tty.h>
45 #include <sys/types.h>
46 
47 #include <arm/clps711x/clps711xreg.h>
48 #include <arm/clps711x/clpssocvar.h>
49 
50 #include <dev/cons.h>
51 
52 #ifdef RND_COM
53 #include <sys/rnd.h>
54 #endif
55 
56 #include "ioconf.h"
57 #include "locators.h"
58 
59 #define COMUNIT_MASK	0x7ffff
60 #define COMDIALOUT_MASK	0x80000
61 
62 #define COMUNIT(x)	(minor(x) & COMUNIT_MASK)
63 #define COMDIALOUT(x)	(minor(x) & COMDIALOUT_MASK)
64 
65 #define CLPSCOM_RING_SIZE	2048
66 #define UART_FIFO_SIZE		16
67 
68 #define CLPSCOM_READ_CON(sc) \
69 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON)
70 #define CLPSCOM_WRITE_CON(sc, val) \
71 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON, (val))
72 #define CLPSCOM_READ_FLG(sc) \
73 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG)
74 #define CLPSCOM_WRITE_FLG(sc, val) \
75 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG, (val))
76 #define CLPSCOM_READ(sc) \
77 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR)
78 #define CLPSCOM_WRITE(sc, val) \
79 	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val))
80 #define CLPSCOM_WRITE_MULTI(sc, val, n) \
81   bus_space_write_multi_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val), (n))
82 #define CLPSCOM_READ_UBRLCR(sc) \
83 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR)
84 #define CLPSCOM_WRITE_UBRLCR(sc, val) \
85 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR, (val))
86 
87 struct clpscom_softc {
88 	device_t sc_dev;
89 	bus_space_tag_t sc_iot;
90 	bus_space_handle_t sc_ioh;
91 	int sc_irq[3];
92 	void *sc_ih[3];
93 #define CLPSCOM_TXINT	0
94 #define CLPSCOM_RXINT	1
95 #define CLPSCOM_MSINT	2
96 
97 	void *sc_si;
98 
99 	struct tty *sc_tty;
100 
101 	u_char *sc_tba;
102 	u_int sc_tbc;
103 	u_char *sc_rbuf;
104 	char *volatile sc_rbget;
105 	char *volatile sc_rbput;
106 	volatile int sc_rbavail;
107 
108 #define CLPSCOM_MODEM_STATUS_MASK (SYSFLG_DCD | SYSFLG_DSR | SYSFLG_CTS)
109 	uint32_t sc_ms;
110 	uint32_t sc_ms_dcd;
111 	uint32_t sc_ms_cts;
112 	uint32_t sc_ms_mask;
113 	uint32_t sc_ms_delta;
114 
115 	int sc_tx_stopped;
116 
117 	int sc_tx_done;
118 	int sc_rx_ready;
119 	int sc_ms_changed;
120 
121 	int sc_hwflags;
122 #define COM_HW_CONSOLE	(1 << 0)
123 #define COM_HW_DEV_OK	(1 << 1)
124 #define COM_HW_KGDB	(1 << 2)
125 	int sc_swflags;
126 
127 #ifdef RND_COM
128 	krandsource_t rnd_source;
129 #endif
130 };
131 
132 static int clpscom_match(device_t, cfdata_t, void *);
133 static void clpscom_attach(device_t, device_t, void *);
134 
135 static int clpscom_txintr(void *);
136 static int clpscom_rxintr(void *);
137 static int clpscom_msintr(void *);
138 static void clpscom_soft(void *);
139 
140 static void clpscom_start(struct tty *);
141 static int clpscom_param(struct tty *, struct termios *);
142 static int clpscom_hwiflow(struct tty *, int);
143 
144 dev_type_open(clpscomopen);
145 dev_type_close(clpscomclose);
146 dev_type_read(clpscomread);
147 dev_type_write(clpscomwrite);
148 dev_type_ioctl(clpscomioctl);
149 dev_type_stop(clpscomstop);
150 dev_type_tty(clpscomtty);
151 dev_type_poll(clpscompoll);
152 
153 static void clpscom_iflush(struct clpscom_softc *);
154 static void clpscom_shutdown(struct clpscom_softc *);
155 static void clpscom_break(struct clpscom_softc *, int);
156 static int clpscom_to_tiocm(struct clpscom_softc *);
157 
158 static void clpscom_rxsoft(struct clpscom_softc *, struct tty *);
159 static void clpscom_mssoft(struct clpscom_softc *, struct tty *);
160 
161 static inline uint32_t clpscom_rate2ubrlcr(int);
162 static uint32_t clpscom_cflag2ubrlcr(tcflag_t);
163 
164 static int clpscom_cngetc(dev_t);
165 static void clpscom_cnputc(dev_t, int);
166 static void clpscom_cnpollc(dev_t, int);
167 
168 CFATTACH_DECL_NEW(clpscom, sizeof(struct clpscom_softc),
169     clpscom_match, clpscom_attach, NULL, NULL);
170 
171 const struct cdevsw clpscom_cdevsw = {
172 	.d_open = clpscomopen,
173 	.d_close = clpscomclose,
174 	.d_read = clpscomread,
175 	.d_write = clpscomwrite,
176 	.d_ioctl = clpscomioctl,
177 	.d_stop = clpscomstop,
178 	.d_tty = clpscomtty,
179 	.d_poll = clpscompoll,
180 	.d_mmap = nommap,
181 	.d_kqfilter = ttykqfilter,
182 	.d_flag = D_TTY
183 };
184 
185 static struct cnm_state clpscom_cnm_state;
186 static vaddr_t clpscom_cnaddr = 0;
187 static int clpscom_cnrate;
188 static tcflag_t clpscom_cncflag;
189 
190 
191 /* ARGSUSED */
192 static int
193 clpscom_match(device_t parent, cfdata_t match, void *aux)
194 {
195 
196 	return 1;
197 }
198 
199 /* ARGSUSED */
200 static void
201 clpscom_attach(device_t parent, device_t self, void *aux)
202 {
203 	struct clpscom_softc *sc = device_private(self);
204 	struct clpssoc_attach_args *aa = aux;
205 	int i;
206 
207 	aprint_naive("\n");
208 	aprint_normal("\n");
209 
210 	sc->sc_dev = self;
211 	sc->sc_iot = aa->aa_iot;
212 	sc->sc_ioh = *aa->aa_ioh;
213 	for (i = 0; i < __arraycount(aa->aa_irq); i++) {
214 		sc->sc_irq[i] = aa->aa_irq[i];
215 		sc->sc_ih[i] = NULL;
216 	}
217 
218 	if (clpscom_cnaddr != 0)
219 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
220 
221 	sc->sc_tty = tty_alloc();
222 	sc->sc_tty->t_oproc = clpscom_start;
223 	sc->sc_tty->t_param = clpscom_param;
224 	sc->sc_tty->t_hwiflow = clpscom_hwiflow;
225 
226 	sc->sc_tbc = 0;
227 	sc->sc_rbuf = malloc(CLPSCOM_RING_SIZE << 1, M_DEVBUF, M_NOWAIT);
228 	if (sc->sc_rbuf == NULL) {
229 		aprint_error_dev(self, "unable to allocate ring buffer\n");
230 		return;
231 	}
232 	sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
233 	sc->sc_rbavail = CLPSCOM_RING_SIZE;
234 
235 	tty_attach(sc->sc_tty);
236 
237 	if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
238 		int maj = cdevsw_lookup_major(&clpscom_cdevsw);
239 
240 		sc->sc_tty->t_dev = makedev(maj, device_unit(sc->sc_dev));
241 		cn_tab->cn_dev = sc->sc_tty->t_dev;
242 
243 		aprint_normal_dev(self, "console\n");
244 	}
245 
246 	sc->sc_si = softint_establish(SOFTINT_SERIAL, clpscom_soft, sc);
247 
248 #ifdef RND_COM
249 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
250 	    RND_TYPE_TTY, 0);
251 #endif
252 
253 	SET(sc->sc_hwflags, COM_HW_DEV_OK);
254 }
255 
256 static int
257 clpscom_txintr(void *arg)
258 {
259 	struct clpscom_softc *sc = arg;
260 	uint32_t sysflg;
261 
262 	if (!device_is_active(sc->sc_dev))
263 		return 0;
264 
265 	sysflg = CLPSCOM_READ_FLG(sc);
266 
267 	/*
268 	 * Done handling any receive interrupts. See if data can be
269 	 * transmitted as well. Schedule tx done event if no data left
270 	 * and tty was marked busy.
271 	 */
272 
273 	if (!ISSET(sysflg, SYSFLG_UTXFF)) {
274 		/* Output the next chunk of the contiguous buffer, if any. */
275 		if (sc->sc_tbc > 0) {
276 			while (sc->sc_tbc > 0 && !ISSET(sysflg, SYSFLG_UTXFF)) {
277 				CLPSCOM_WRITE(sc, *sc->sc_tba);
278 				sc->sc_tba++;
279 				sc->sc_tbc--;
280 				sysflg = CLPSCOM_READ_FLG(sc);
281 			}
282 		} else if (!ISSET(sysflg, SYSFLG_UBUSY) &&
283 					sc->sc_ih[CLPSCOM_TXINT] != NULL) {
284 			intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]);
285 			sc->sc_ih[CLPSCOM_TXINT] = NULL;
286 			sc->sc_tx_done = 1;
287 		}
288 	}
289 
290 	/* Wake up the poller. */
291 	softint_schedule(sc->sc_si);
292 
293 	return 1;
294 }
295 
296 static int
297 clpscom_rxintr(void *arg)
298 {
299 	struct clpscom_softc *sc = arg;
300 	int cc;
301 	uint32_t sysflg;
302 	uint16_t data;
303 	u_char *put;
304 
305 	if (!device_is_active(sc->sc_dev))
306 		return 0;
307 
308 	if (sc->sc_ih[CLPSCOM_RXINT] != NULL) {
309 		put = sc->sc_rbput;
310 		cc = sc->sc_rbavail;
311 		while (cc > 0) {
312 			sysflg = CLPSCOM_READ_FLG(sc);
313 			if (ISSET(sysflg, SYSFLG_URXFE))
314 				break;
315 			data = CLPSCOM_READ(sc);
316 			cn_check_magic(sc->sc_tty->t_dev, data & 0xff,
317 			    clpscom_cnm_state);
318 
319 			put[0] = data & 0xff;
320 			put[1] = (data >> 8) & 0xff;
321 			put += 2;
322 			if (put >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1))
323 				put = sc->sc_rbuf;
324 			cc--;
325 			sc->sc_rx_ready = 1;
326 		}
327 
328 		/*
329 		 * Current string of incoming characters ended because
330 		 * no more data was available or we ran out of space.
331 		 * Schedule a receive event if any data was received.
332 		 * If we're out of space, turn off receive interrupts.
333 		 */
334 		sc->sc_rbput = put;
335 		sc->sc_rbavail = cc;
336 
337 		/*
338 		 * See if we are in danger of overflowing a buffer. If
339 		 * so, use hardware flow control to ease the pressure.
340 		 */
341 
342 		/* but clpscom cannot. X-( */
343 
344 		/*
345 		 * If we're out of space, disable receive interrupts
346 		 * until the queue has drained a bit.
347 		 */
348 		if (cc <= 0) {
349 			intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]);
350 			sc->sc_ih[CLPSCOM_RXINT] = NULL;
351 		}
352 	}
353 
354 	/* Wake up the poller. */
355 	softint_schedule(sc->sc_si);
356 
357 	return 1;
358 }
359 
360 static int
361 clpscom_msintr(void *arg)
362 {
363 	struct clpscom_softc *sc = arg;
364 	uint32_t ms, delta;
365 
366 	if (!device_is_active(sc->sc_dev))
367 		return 0;
368 
369 	if (sc->sc_ih[CLPSCOM_MSINT] != NULL) {
370 		ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK;
371 		delta = ms ^ sc->sc_ms;
372 		sc->sc_ms = ms;
373 
374 		if (ISSET(delta, sc->sc_ms_mask)) {
375 			SET(sc->sc_ms_delta, delta);
376 
377 			/*
378 			 * Stop output immediately if we lose the output
379 			 * flow control signal or carrier detect.
380 			 */
381 			if (ISSET(~ms, sc->sc_ms_mask))
382 				sc->sc_tbc = 0;
383 			sc->sc_ms_changed = 1;
384 		}
385 	}
386 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_UMSEOI, 1);
387 
388 	/* Wake up the poller. */
389 	softint_schedule(sc->sc_si);
390 
391 	return 1;
392 }
393 
394 static void
395 clpscom_soft(void *arg)
396 {
397 	struct clpscom_softc *sc = arg;
398 	struct tty *tp = sc->sc_tty;
399 
400 	if (!device_is_active(sc->sc_dev))
401 		return;
402 
403 	if (sc->sc_rx_ready) {
404 		sc->sc_rx_ready = 0;
405 		clpscom_rxsoft(sc, tp);
406 	}
407 	if (sc->sc_tx_done) {
408 		sc->sc_tx_done = 0;
409 		CLR(tp->t_state, TS_BUSY);
410 		if (ISSET(tp->t_state, TS_FLUSH))
411 			CLR(tp->t_state, TS_FLUSH);
412 		else
413 			ndflush(&tp->t_outq,
414 			    (int)(sc->sc_tba - tp->t_outq.c_cf));
415 		(*tp->t_linesw->l_start)(tp);
416 	}
417 	if (sc->sc_ms_changed == 1) {
418 		sc->sc_ms_changed = 0;
419 		clpscom_mssoft(sc, tp);
420 	}
421 }
422 
423 static void
424 clpscom_start(struct tty *tp)
425 {
426 	struct clpscom_softc *sc
427 		= device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev));
428 	int s, n;
429 
430 	if (!device_is_active(sc->sc_dev))
431 		return;
432 
433 	s = spltty();
434 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
435 		goto out;
436 	if (sc->sc_tx_stopped)
437 		goto out;
438 	if (!ttypull(tp))
439 		goto out;
440 
441 	/* Grab the first contiguous region of buffer space. */
442 	{
443 		u_char *tba;
444 		int tbc;
445 
446 		tba = tp->t_outq.c_cf;
447 		tbc = ndqb(&tp->t_outq, 0);
448 
449 		(void)splserial();
450 
451 		sc->sc_tba = tba;
452 		sc->sc_tbc = tbc;
453 	}
454 
455 	SET(tp->t_state, TS_BUSY);
456 
457 	if (sc->sc_ih[CLPSCOM_TXINT] == NULL) {
458 		sc->sc_ih[CLPSCOM_TXINT] =
459 		    intr_establish(sc->sc_irq[CLPSCOM_TXINT], IPL_SERIAL, 0,
460 		    clpscom_txintr, sc);
461 		if (sc->sc_ih[CLPSCOM_TXINT] == NULL)
462 			printf("%s: can't establish tx interrupt\n",
463 			    device_xname(sc->sc_dev));
464 
465 		/* Output the first chunk of the contiguous buffer. */
466 		n = min(sc->sc_tbc, UART_FIFO_SIZE);
467 		CLPSCOM_WRITE_MULTI(sc, sc->sc_tba, n);
468 		sc->sc_tba += n;
469 		sc->sc_tbc -= n;
470 	}
471 out:
472 	splx(s);
473 	return;
474 }
475 
476 static int
477 clpscom_param(struct tty *tp, struct termios *t)
478 {
479 	struct clpscom_softc *sc =
480 	    device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev));
481 	int s;
482 
483 	if (!device_is_active(sc->sc_dev))
484 		return ENXIO;
485 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
486 		return EINVAL;
487 
488 	/*
489 	 * For the console, always force CLOCAL and !HUPCL, so that the port
490 	 * is always active.
491 	 */
492 	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
493 	    ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
494 		SET(t->c_cflag, CLOCAL);
495 		CLR(t->c_cflag, HUPCL);
496 	}
497 
498 	/*
499 	 * If there were no changes, don't do anything.  This avoids dropping
500 	 * input and improves performance when all we did was frob things like
501 	 * VMIN and VTIME.
502 	 */
503 	if (tp->t_ospeed == t->c_ospeed &&
504 	    tp->t_cflag == t->c_cflag)
505 		return 0;
506 
507 	/*
508 	 * If we're not in a mode that assumes a connection is present, then
509 	 * ignore carrier changes.
510 	 */
511 	if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
512 		sc->sc_ms_dcd = 0;
513 	else
514 		sc->sc_ms_dcd = SYSFLG_DCD;
515 	/*
516 	 * Set the flow control pins depending on the current flow control
517 	 * mode.
518 	 */
519 	if (ISSET(t->c_cflag, CRTSCTS)) {
520 		sc->sc_ms_cts = SYSFLG_CTS;
521 	} else if (ISSET(t->c_cflag, MDMBUF)) {
522 		/*
523 		 * For DTR/DCD flow control, make sure we don't toggle DTR for
524 		 * carrier detection.
525 		 */
526 		sc->sc_ms_cts = SYSFLG_DCD;
527 	} else {
528 		/*
529 		 * If no flow control, then always set RTS.  This will make
530 		 * the other side happy if it mistakenly thinks we're doing
531 		 * RTS/CTS flow control.
532 		 */
533 		sc->sc_ms_cts = 0;
534 	}
535 	sc->sc_ms_mask = sc->sc_ms_cts | sc->sc_ms_dcd;
536 
537 	s = splserial();
538 	CLPSCOM_WRITE_UBRLCR(sc,
539 	    UBRLCR_FIFOEN |
540 	    clpscom_rate2ubrlcr(t->c_ospeed) |
541 	    clpscom_cflag2ubrlcr(t->c_cflag));
542 
543 	/* And copy to tty. */
544 	tp->t_ispeed = 0;
545 	tp->t_ospeed = t->c_ospeed;
546 	tp->t_cflag = t->c_cflag;
547 	splx(s);
548 
549 	/*
550 	 * Update the tty layer's idea of the carrier bit, in case we changed
551 	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
552 	 * explicit request.
553 	 */
554 	(*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_ms, SYSFLG_DCD));
555 
556 	if (!ISSET(t->c_cflag, CHWFLOW))
557 		if (sc->sc_tx_stopped) {
558 			sc->sc_tx_stopped = 0;
559 			clpscom_start(tp);
560 		}
561 
562 	return 0;
563 }
564 
565 static int
566 clpscom_hwiflow(struct tty *tp, int block)
567 {
568 	/* Nothing */
569 	return 0;
570 }
571 
572 /* ARGSUSED */
573 int
574 clpscomopen(dev_t dev, int flag, int mode, struct lwp *l)
575 {
576 	struct clpscom_softc *sc;
577 	struct tty *tp;
578 	int error, s, s2;
579 
580 	sc = device_lookup_private(&clpscom_cd, COMUNIT(dev));
581 	if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK))
582 		return ENXIO;
583 	if (!device_is_active(sc->sc_dev))
584 		return ENXIO;
585 
586 #ifdef KGDB
587 	/*
588 	 * If this is the kgdb port, no other use is permitted.
589 	 */
590 	if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
591 		return EBUSY;
592 #endif
593 
594 	tp = sc->sc_tty;
595 
596 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
597 		return EBUSY;
598 
599 	s = spltty();
600 
601 	/*
602 	 * Do the following iff this is a first open.
603 	 */
604 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
605 		struct termios t;
606 
607 		tp->t_dev = dev;
608 
609 		/* Enable and turn on interrupt */
610 		CLPSCOM_WRITE_CON(sc, CLPSCOM_READ_CON(sc) | SYSCON_UARTEN);
611 
612 		/* Fetch the current modem control status, needed later. */
613 		sc->sc_ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK;
614 
615 		/*
616 		 * Initialize the termios status to the defaults.  Add in the
617 		 * sticky bits from TIOCSFLAGS.
618 		 */
619 		t.c_ispeed = 0;
620 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
621 			t.c_ospeed = clpscom_cnrate;
622 			t.c_cflag = clpscom_cncflag;
623 		} else {
624 			t.c_ospeed = TTYDEF_SPEED;
625 			t.c_cflag = TTYDEF_CFLAG;
626 		}
627 		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
628 			SET(t.c_cflag, CLOCAL);
629 		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
630 			SET(t.c_cflag, CRTSCTS);
631 		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
632 			SET(t.c_cflag, MDMBUF);
633 		/* Make sure pscom_param() we do something */
634 		tp->t_ospeed = 0;
635 		clpscom_param(tp, &t);
636 		tp->t_iflag = TTYDEF_IFLAG;
637 		tp->t_oflag = TTYDEF_OFLAG;
638 		tp->t_lflag = TTYDEF_LFLAG;
639 		ttychars(tp);
640 		ttsetwater(tp);
641 
642 		s2 = splserial();
643 
644 		/* Clear the input ring. */
645 		sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
646 		sc->sc_rbavail = CLPSCOM_RING_SIZE;
647 		clpscom_iflush(sc);
648 
649 		splx(s2);
650 	}
651 
652 	splx(s);
653 
654 	error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
655 	if (error)
656 		goto bad;
657 
658 	error = (*tp->t_linesw->l_open)(dev, tp);
659 	if (error)
660 		goto bad;
661 	return 0;
662 
663 bad:
664 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
665 		/*
666 		 * We failed to open the device, and nobody else had it opened.
667 		 * Clean up the state as appropriate.
668 		 */
669 		clpscom_shutdown(sc);
670 
671 		/* Disable UART */
672 		if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
673 			CLPSCOM_WRITE_CON(sc,
674 			    CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN);
675 	}
676 
677 	return error;
678 }
679 
680 /* ARGSUSED */
681 int
682 clpscomclose(dev_t dev, int flag, int mode, struct lwp *l)
683 {
684 	struct clpscom_softc *sc =
685 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
686 	struct tty *tp = sc->sc_tty;
687 
688 	/* XXXX This is for cons.c. */
689 	if (!ISSET(tp->t_state, TS_ISOPEN))
690 		return 0;
691 
692 	(*tp->t_linesw->l_close)(tp, flag);
693 	ttyclose(tp);
694 
695 	if (!device_is_active(sc->sc_dev))
696 		return 0;
697 
698 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
699 		/*
700 		 * Although we got a last close, the device may still be in
701 		 * use; e.g. if this was the dialout node, and there are still
702 		 * processes waiting for carrier on the non-dialout node.
703 		 */
704 		clpscom_shutdown(sc);
705 
706 		/* Disable UART */
707 		if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
708 			CLPSCOM_WRITE_CON(sc,
709 			    CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN);
710 	}
711 
712 	return 0;
713 }
714 
715 int
716 clpscomread(dev_t dev, struct uio *uio, int flag)
717 {
718 	struct clpscom_softc *sc =
719 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
720 	struct tty *tp = sc->sc_tty;
721 
722 	if (!device_is_active(sc->sc_dev))
723 		return EIO;
724 
725 	return (*tp->t_linesw->l_read)(tp, uio, flag);
726 }
727 
728 int
729 clpscomwrite(dev_t dev, struct uio *uio, int flag)
730 {
731 	struct clpscom_softc *sc =
732 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
733 	struct tty *tp = sc->sc_tty;
734 
735 	if (!device_is_active(sc->sc_dev))
736 		return EIO;
737 
738 	return (*tp->t_linesw->l_write)(tp, uio, flag);
739 }
740 
741 int
742 clpscomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
743 {
744 	struct clpscom_softc *sc =
745 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
746 	struct tty *tp = sc->sc_tty;
747 	int error, s;
748 
749 	if (!device_is_active(sc->sc_dev))
750 		return EIO;
751 
752 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
753 	if (error != EPASSTHROUGH)
754 		return error;
755 
756 	error = ttioctl(tp, cmd, data, flag, l);
757 	if (error != EPASSTHROUGH)
758 		return error;
759 
760 	switch (cmd) {
761 	case TIOCSFLAGS:
762 		error = kauth_authorize_device_tty(l->l_cred,
763 		    KAUTH_DEVICE_TTY_PRIVSET, tp);
764 		break;
765 	default:
766 		break;
767 	}
768 	if (error)
769 		return error;
770 
771 	s = splserial();
772 	error = 0;
773 	switch (cmd) {
774 	case TIOCSBRK:
775 		clpscom_break(sc, 1);
776 		break;
777 
778 	case TIOCCBRK:
779 		clpscom_break(sc, 0);
780 		break;
781 
782 	case TIOCGFLAGS:
783 		*(int *)data = sc->sc_swflags;
784 		break;
785 
786 	case TIOCSFLAGS:
787 		sc->sc_swflags = *(int *)data;
788 		break;
789 
790 	case TIOCMGET:
791 		*(int *)data = clpscom_to_tiocm(sc);
792 		break;
793 
794 	default:
795 		error = EPASSTHROUGH;
796 		break;
797 	}
798 	splx(s);
799 	return error;
800 }
801 
802 int
803 clpscompoll(dev_t dev, int events, struct lwp *l)
804 {
805 	struct clpscom_softc *sc =
806 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
807 	struct tty *tp = sc->sc_tty;
808 
809 	if (!device_is_active(sc->sc_dev))
810 		return EIO;
811 
812 	return (*tp->t_linesw->l_poll)(tp, events, l);
813 }
814 
815 struct tty *
816 clpscomtty(dev_t dev)
817 {
818 	struct clpscom_softc *sc =
819 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
820 
821 	return sc->sc_tty;
822 }
823 
824 void
825 clpscomstop(struct tty *tp, int flag)
826 {
827 	int s;
828 
829 	s = splserial();
830 	if (ISSET(tp->t_state, TS_BUSY)) {
831 		/* Stop transmitting at the next chunk. */
832 		if (!ISSET(tp->t_state, TS_TTSTOP))
833 			SET(tp->t_state, TS_FLUSH);
834 	}
835 	splx(s);
836 }
837 
838 
839 static void
840 clpscom_iflush(struct clpscom_softc *sc)
841 {
842 	int timo;
843 
844 	timo = 50000;
845 	while ((CLPSCOM_READ_FLG(sc) & SYSFLG_URXFE) == 0
846 	    && timo--)
847 		CLPSCOM_READ(sc);
848 	if (timo == 0)
849 		printf("%s: iflush timeout\n", device_xname(sc->sc_dev));
850 }
851 
852 static void
853 clpscom_shutdown(struct clpscom_softc *sc)
854 {
855 	int s;
856 
857 	s = splserial();
858 
859 	/* Turn off all interrupts */
860 	if (sc->sc_ih[CLPSCOM_TXINT] != NULL)
861 		intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]);
862 	sc->sc_ih[CLPSCOM_TXINT] = NULL;
863 	if (sc->sc_ih[CLPSCOM_RXINT] != NULL)
864 		intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]);
865 	sc->sc_ih[CLPSCOM_RXINT] = NULL;
866 	if (sc->sc_ih[CLPSCOM_MSINT] != NULL)
867 		intr_disestablish(sc->sc_ih[CLPSCOM_MSINT]);
868 	sc->sc_ih[CLPSCOM_MSINT] = NULL;
869 
870 	/* Clear any break condition set with TIOCSBRK. */
871 	clpscom_break(sc, 0);
872 
873 	splx(s);
874 }
875 
876 static void
877 clpscom_break(struct clpscom_softc *sc, int onoff)
878 {
879 	int s;
880 	uint8_t ubrlcr;
881 
882 	s = splserial();
883 	ubrlcr = CLPSCOM_READ_UBRLCR(sc);
884 	if (onoff)
885 		SET(ubrlcr, UBRLCR_BREAK);
886 	else
887 		CLR(ubrlcr, UBRLCR_BREAK);
888 	CLPSCOM_WRITE_UBRLCR(sc, ubrlcr);
889 	splx(s);
890 }
891 
892 static int
893 clpscom_to_tiocm(struct clpscom_softc *sc)
894 {
895 	uint32_t combits;
896 	int ttybits = 0;
897 
898 	combits = sc->sc_ms;
899 	if (ISSET(combits, SYSFLG_DCD))
900 		SET(ttybits, TIOCM_CD);
901 	if (ISSET(combits, SYSFLG_CTS))
902 		SET(ttybits, TIOCM_CTS);
903 	if (ISSET(combits, SYSFLG_DSR))
904 		SET(ttybits, TIOCM_DSR);
905 
906 	return ttybits;
907 }
908 
909 static void
910 clpscom_rxsoft(struct clpscom_softc *sc, struct tty *tp)
911 {
912 	int code, s;
913 	u_int cc, scc;
914 	u_char sts, *get;
915 
916 	get = sc->sc_rbget;
917 	scc = cc = CLPSCOM_RING_SIZE - sc->sc_rbavail;
918 	while (cc) {
919 		code = get[0];
920 		sts = get[1];
921 		if (ISSET(sts, UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)) {
922 			if (ISSET(sts, (UARTDR_FRMERR)))
923 				SET(code, TTY_FE);
924 			if (ISSET(sts, UARTDR_PARERR))
925 				SET(code, TTY_PE);
926 			if (ISSET(sts, UARTDR_OVERR))
927 				;		/* XXXXX: Overrun */
928 		}
929 		if ((*tp->t_linesw->l_rint)(code, tp) == -1) {
930 			/*
931 			 * The line discipline's buffer is out of space.
932 			 */
933 			/*
934 			 * We're either not using flow control, or the
935 			 * line discipline didn't tell us to block for
936 			 * some reason.  Either way, we have no way to
937 			 * know when there's more space available, so
938 			 * just drop the rest of the data.
939 			 */
940 			get += cc << 1;
941 			if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1))
942 				get -= (CLPSCOM_RING_SIZE << 1);
943 			cc = 0;
944 			break;
945 		}
946 		get += 2;
947 		if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1))
948 			get = sc->sc_rbuf;
949 		cc--;
950 	}
951 
952 	if (cc != scc) {
953 		sc->sc_rbget = get;
954 		s = splserial();
955 
956 		cc = sc->sc_rbavail += scc - cc;
957 		/* Buffers should be ok again, release possible block. */
958 		if (cc >= 1) {
959 			if (sc->sc_ih[CLPSCOM_RXINT] == NULL) {
960 				sc->sc_ih[CLPSCOM_RXINT] =
961 				    intr_establish(sc->sc_irq[CLPSCOM_RXINT],
962 				    IPL_SERIAL, 0, clpscom_rxintr, sc);
963 				if (sc->sc_ih[CLPSCOM_RXINT] == NULL)
964 					printf("%s: can't establish"
965 					    " rx interrupt\n",
966 					    device_xname(sc->sc_dev));
967 			}
968 			if (sc->sc_ih[CLPSCOM_MSINT] == NULL) {
969 				sc->sc_ih[CLPSCOM_MSINT] =
970 				    intr_establish(sc->sc_irq[CLPSCOM_MSINT],
971 				    IPL_SERIAL, 0, clpscom_msintr, sc);
972 				if (sc->sc_ih[CLPSCOM_MSINT] == NULL)
973 					printf("%s: can't establish"
974 					    " ms interrupt\n",
975 					    device_xname(sc->sc_dev));
976 			}
977 		}
978 		splx(s);
979 	}
980 }
981 
982 static void
983 clpscom_mssoft(struct clpscom_softc *sc, struct tty *tp)
984 {
985 	uint32_t ms, delta;
986 
987 	ms = sc->sc_ms;
988 	delta = sc->sc_ms_delta;
989 	sc->sc_ms_delta = 0;
990 
991 	if (ISSET(delta, sc->sc_ms_dcd))
992 		/*
993 		 * Inform the tty layer that carrier detect changed.
994 		 */
995 		(void) (*tp->t_linesw->l_modem)(tp, ISSET(ms, SYSFLG_DCD));
996 
997 	if (ISSET(delta, sc->sc_ms_cts)) {
998 		/* Block or unblock output according to flow control. */
999 		if (ISSET(ms, sc->sc_ms_cts)) {
1000 			sc->sc_tx_stopped = 0;
1001 			(*tp->t_linesw->l_start)(tp);
1002 		} else
1003 			sc->sc_tx_stopped = 1;
1004 	}
1005 }
1006 
1007 static inline uint32_t
1008 clpscom_rate2ubrlcr(int rate)
1009 {
1010 
1011 	return 230400 / rate - 1;
1012 }
1013 
1014 static uint32_t
1015 clpscom_cflag2ubrlcr(tcflag_t cflag)
1016 {
1017 	int32_t ubrlcr = 0;
1018 
1019 	switch (cflag & CSIZE) {
1020 	case CS5: SET(ubrlcr, UBRLCR_WRDLEN_5B); break;
1021 	case CS6: SET(ubrlcr, UBRLCR_WRDLEN_6B); break;
1022 	case CS7: SET(ubrlcr, UBRLCR_WRDLEN_7B); break;
1023 	case CS8: SET(ubrlcr, UBRLCR_WRDLEN_8B); break;
1024 	default:  SET(ubrlcr, UBRLCR_WRDLEN_8B); break;
1025 	}
1026 	if (cflag & CSTOPB)
1027 		SET(ubrlcr, UBRLCR_XSTOP);
1028 	if (cflag & PARENB) {
1029 		SET(ubrlcr, (UBRLCR_PRTEN | UBRLCR_EVENPRT));
1030 		if (cflag & PARODD)
1031 			CLR(ubrlcr, UBRLCR_EVENPRT);
1032 	}
1033 	return ubrlcr;
1034 }
1035 
1036 #define CLPSCOM_CNREAD() \
1037 	(*(volatile uint32_t *)(clpscom_cnaddr + PS711X_UARTDR))
1038 #define CLPSCOM_CNWRITE(val) \
1039 	(*(volatile uint8_t *)(clpscom_cnaddr + PS711X_UARTDR) = val)
1040 #define CLPSCOM_CNSTATUS() \
1041 	(*(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG))
1042 
1043 static struct consdev clpscomcons = {
1044 	NULL, NULL, clpscom_cngetc, clpscom_cnputc, clpscom_cnpollc,
1045 	NULL, NULL, NULL, NODEV, CN_NORMAL
1046 };
1047 
1048 int
1049 clpscom_cnattach(vaddr_t addr, int rate, tcflag_t cflag)
1050 {
1051 
1052 	clpscom_cnaddr = addr;
1053 	clpscom_cnrate = rate;
1054 	clpscom_cncflag = cflag;
1055 	*(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG) |= SYSCON_UARTEN;
1056 	*(volatile uint32_t *)(clpscom_cnaddr + PS711X_UBRLCR) =
1057 	    UBRLCR_FIFOEN |
1058 	    clpscom_cflag2ubrlcr(cflag) |
1059 	    clpscom_rate2ubrlcr(rate);
1060 
1061 	cn_tab = &clpscomcons;
1062 	cn_init_magic(&clpscom_cnm_state);
1063 	cn_set_magic("\047\001");	/* default magic is BREAK */
1064 
1065 	return 0;
1066 }
1067 
1068 /* ARGSUSED */
1069 static int
1070 clpscom_cngetc(dev_t dev)
1071 {
1072 	int s = splserial();
1073 	char ch;
1074 
1075 	while (CLPSCOM_CNSTATUS() & SYSFLG_URXFE);
1076 
1077 	ch = CLPSCOM_CNREAD();
1078 
1079 	{
1080 #ifdef DDB
1081 		extern int db_active;
1082 		if (!db_active)
1083 #endif
1084 			cn_check_magic(dev, ch, clpscom_cnm_state);
1085 	}
1086 
1087 	splx(s);
1088 	return ch;
1089 }
1090 
1091 /* ARGSUSED */
1092 static void
1093 clpscom_cnputc(dev_t dev, int c)
1094 {
1095 	int s = splserial();
1096 
1097 	while (CLPSCOM_CNSTATUS() & SYSFLG_UTXFF);
1098 
1099 	CLPSCOM_CNWRITE(c);
1100 
1101 	/* Make sure output. */
1102 	while (CLPSCOM_CNSTATUS() & SYSFLG_UBUSY);
1103 
1104 	splx(s);
1105 }
1106 
1107 /* ARGSUSED */
1108 static void
1109 clpscom_cnpollc(dev_t dev, int on)
1110 {
1111 	/* Nothing */
1112 }
1113