jcs's openbsd hax
openbsd
1/* $OpenBSD: exuart.c,v 1.13 2025/07/03 21:06:51 kettenis Exp $ */
2/*
3 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/param.h>
19#include <sys/ioctl.h>
20#include <sys/proc.h>
21#include <sys/tty.h>
22#include <sys/uio.h>
23#include <sys/systm.h>
24#include <sys/time.h>
25#include <sys/device.h>
26#include <sys/syslog.h>
27#include <sys/conf.h>
28#include <sys/fcntl.h>
29#include <sys/kernel.h>
30
31#include <machine/bus.h>
32#include <machine/fdt.h>
33
34#include <dev/cons.h>
35
36#ifdef DDB
37#include <ddb/db_var.h>
38#endif
39
40#include <dev/fdt/exuartreg.h>
41
42#include <dev/ofw/openfirm.h>
43#include <dev/ofw/ofw_power.h>
44#include <dev/ofw/fdt.h>
45
46#define DEVUNIT(x) (minor(x) & 0x7f)
47#define DEVCUA(x) (minor(x) & 0x80)
48
49struct exuart_softc {
50 struct device sc_dev;
51 bus_space_tag_t sc_iot;
52 bus_space_handle_t sc_ioh;
53 struct soft_intrhand *sc_si;
54 void *sc_irq;
55 struct tty *sc_tty;
56 struct timeout sc_diag_tmo;
57 struct timeout sc_dtr_tmo;
58
59 uint32_t sc_rx_fifo_cnt_mask;
60 uint32_t sc_rx_fifo_full;
61 uint32_t sc_tx_fifo_full;
62 int sc_type;
63#define EXUART_TYPE_EXYNOS 0
64#define EXUART_TYPE_S5L 1
65
66 int sc_fifo;
67 int sc_overflows;
68 int sc_floods;
69 int sc_errors;
70 int sc_halt;
71 u_int32_t sc_ulcon;
72 u_int32_t sc_ucon;
73 u_int32_t sc_ufcon;
74 u_int32_t sc_umcon;
75 u_int32_t sc_uintm;
76 u_int8_t sc_hwflags;
77#define COM_HW_NOIEN 0x01
78#define COM_HW_FIFO 0x02
79#define COM_HW_SIR 0x20
80#define COM_HW_CONSOLE 0x40
81 u_int8_t sc_swflags;
82#define COM_SW_SOFTCAR 0x01
83#define COM_SW_CLOCAL 0x02
84#define COM_SW_CRTSCTS 0x04
85#define COM_SW_MDMBUF 0x08
86#define COM_SW_PPS 0x10
87
88 u_int8_t sc_initialize;
89 u_int8_t sc_cua;
90 u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
91#define EXUART_IBUFSIZE 128
92#define EXUART_IHIGHWATER 100
93 u_int16_t sc_ibufs[2][EXUART_IBUFSIZE];
94};
95
96
97int exuart_match(struct device *, void *, void *);
98void exuart_attach(struct device *, struct device *, void *);
99
100void exuartcnprobe(struct consdev *cp);
101void exuartcninit(struct consdev *cp);
102int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
103 tcflag_t cflag);
104int exuartcngetc(dev_t dev);
105void exuartcnputc(dev_t dev, int c);
106void exuartcnpollc(dev_t dev, int on);
107int exuart_param(struct tty *tp, struct termios *t);
108void exuart_start(struct tty *);
109void exuart_diag(void *arg);
110void exuart_raisedtr(void *arg);
111void exuart_softint(void *arg);
112struct exuart_softc *exuart_sc(dev_t dev);
113
114int exuart_intr(void *);
115int exuart_s5l_intr(void *);
116
117/* XXX - we imitate 'com' serial ports and take over their entry points */
118/* XXX: These belong elsewhere */
119cdev_decl(com);
120cdev_decl(exuart);
121
122struct cfdriver exuart_cd = {
123 NULL, "exuart", DV_TTY
124};
125
126const struct cfattach exuart_ca = {
127 sizeof(struct exuart_softc), exuart_match, exuart_attach
128};
129
130bus_space_tag_t exuartconsiot;
131bus_space_handle_t exuartconsioh;
132bus_addr_t exuartconsaddr;
133tcflag_t exuartconscflag = TTYDEF_CFLAG;
134int exuartdefaultrate = B115200;
135
136uint32_t exuart_rx_fifo_cnt_mask;
137uint32_t exuart_rx_fifo_full;
138uint32_t exuart_tx_fifo_full;
139
140struct cdevsw exuartdev =
141 cdev_tty_init(3/*XXX NEXUART */ ,exuart); /* 12: serial port */
142
143void
144exuart_init_cons(void)
145{
146 struct fdt_reg reg;
147 void *node, *root;
148
149 if ((node = fdt_find_cons("apple,s5l-uart")) == NULL &&
150 (node = fdt_find_cons("samsung,exynos4210-uart")) == NULL)
151 return;
152
153 /* dtb uses serial2, qemu uses serial0 */
154 root = fdt_find_node("/");
155 if (root == NULL)
156 panic("%s: could not get fdt root node", __func__);
157 if (fdt_is_compatible(root, "samsung,universal_c210")) {
158 if ((node = fdt_find_node("/serial@13800000")) == NULL) {
159 return;
160 }
161 stdout_node = OF_finddevice("/serial@13800000");
162 }
163
164 if (fdt_get_reg(node, 0, ®))
165 return;
166
167 if (fdt_is_compatible(node, "apple,s5l-uart")) {
168 exuart_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK;
169 exuart_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL;
170 exuart_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL;
171 } else {
172 exuart_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK;
173 exuart_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL;
174 exuart_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL;
175 }
176
177 exuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
178}
179
180int
181exuart_match(struct device *parent, void *self, void *aux)
182{
183 struct fdt_attach_args *faa = aux;
184
185 return (OF_is_compatible(faa->fa_node, "apple,s5l-uart") ||
186 OF_is_compatible(faa->fa_node, "samsung,exynos4210-uart"));
187}
188
189void
190exuart_attach(struct device *parent, struct device *self, void *aux)
191{
192 struct exuart_softc *sc = (struct exuart_softc *) self;
193 struct fdt_attach_args *faa = aux;
194 int maj;
195
196 if (faa->fa_nreg < 1)
197 return;
198
199 sc->sc_iot = faa->fa_iot;
200 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
201 0, &sc->sc_ioh))
202 panic("%s: bus_space_map failed!", __func__);
203
204 if (stdout_node == faa->fa_node) {
205 /* Locate the major number. */
206 for (maj = 0; maj < nchrdev; maj++)
207 if (cdevsw[maj].d_open == exuartopen)
208 break;
209 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
210
211 printf(": console");
212 SET(sc->sc_hwflags, COM_HW_CONSOLE);
213 }
214
215 printf("\n");
216
217 power_domain_enable(faa->fa_node);
218
219 if (OF_is_compatible(faa->fa_node, "apple,s5l-uart")) {
220 sc->sc_type = EXUART_TYPE_S5L;
221 sc->sc_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK;
222 sc->sc_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL;
223 sc->sc_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL;
224
225 /* Mask and clear interrupts. */
226 sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
227 EXUART_UCON);
228 CLR(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT);
229 CLR(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH);
230 CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
231 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
232 sc->sc_ucon);
233 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UTRSTAT,
234 EXUART_S5L_UTRSTAT_RX_TIMEOUT |
235 EXUART_S5L_UTRSTAT_RXTHRESH |
236 EXUART_S5L_UTRSTAT_TXTHRESH);
237
238 sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
239 EXUART_UCON);
240 SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
241 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
242 sc->sc_ucon);
243
244 sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
245 exuart_s5l_intr, sc, sc->sc_dev.dv_xname);
246 } else {
247 sc->sc_type = EXUART_TYPE_EXYNOS;
248 sc->sc_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK;
249 sc->sc_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL;
250 sc->sc_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL;
251
252 /* Mask and clear interrupts. */
253 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTM,
254 EXUART_UINTM_RXD | EXUART_UINTM_ERROR |
255 EXUART_UINTM_TXD | EXUART_UINTM_MODEM);
256 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTP,
257 EXUART_UINTP_RXD | EXUART_UINTP_ERROR |
258 EXUART_UINTP_TXD | EXUART_UINTP_MODEM);
259
260 sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
261 EXUART_UCON);
262 CLR(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT_EMPTY_FIFO);
263 SET(sc->sc_ucon, EXUART_UCON_RX_INT_TYPE_LEVEL);
264 SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
265 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
266 sc->sc_ucon);
267
268 sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
269 exuart_intr, sc, sc->sc_dev.dv_xname);
270 }
271
272 timeout_set(&sc->sc_diag_tmo, exuart_diag, sc);
273 timeout_set(&sc->sc_dtr_tmo, exuart_raisedtr, sc);
274 sc->sc_si = softintr_establish(IPL_TTY, exuart_softint, sc);
275
276 if(sc->sc_si == NULL)
277 panic("%s: can't establish soft interrupt.",
278 sc->sc_dev.dv_xname);
279}
280
281void
282exuart_rx_intr(struct exuart_softc *sc)
283{
284 bus_space_tag_t iot = sc->sc_iot;
285 bus_space_handle_t ioh = sc->sc_ioh;
286 u_int16_t *p;
287 u_int16_t c;
288
289 p = sc->sc_ibufp;
290
291 while (bus_space_read_4(iot, ioh, EXUART_UFSTAT) &
292 (sc->sc_rx_fifo_cnt_mask | sc->sc_rx_fifo_full)) {
293 c = bus_space_read_4(iot, ioh, EXUART_URXH);
294 if (p >= sc->sc_ibufend) {
295 sc->sc_floods++;
296 if (sc->sc_errors++ == 0)
297 timeout_add_sec(&sc->sc_diag_tmo, 60);
298 } else {
299 *p++ = c;
300#if 0
301 if (p == sc->sc_ibufhigh &&
302 ISSET(tp->t_cflag, CRTSCTS)) {
303 /* XXX */
304 }
305#endif
306 }
307 }
308
309 sc->sc_ibufp = p;
310
311 softintr_schedule(sc->sc_si);
312}
313
314void
315exuart_tx_intr(struct exuart_softc *sc)
316{
317 struct tty *tp = sc->sc_tty;
318
319 if (ISSET(tp->t_state, TS_BUSY)) {
320 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
321 if (sc->sc_halt > 0)
322 wakeup(&tp->t_outq);
323 (*linesw[tp->t_line].l_start)(tp);
324 }
325}
326
327int
328exuart_intr(void *arg)
329{
330 struct exuart_softc *sc = arg;
331 bus_space_tag_t iot = sc->sc_iot;
332 bus_space_handle_t ioh = sc->sc_ioh;
333 u_int32_t uintp;
334
335 uintp = bus_space_read_4(iot, ioh, EXUART_UINTP);
336 if (uintp == 0)
337 return (0);
338
339 if (sc->sc_tty == NULL)
340 return (0);
341
342 if (ISSET(uintp, EXUART_UINTP_RXD)) {
343 exuart_rx_intr(sc);
344 bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_RXD);
345 }
346
347 if (ISSET(uintp, EXUART_UINTP_TXD)) {
348 exuart_tx_intr(sc);
349 bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_TXD);
350 }
351
352#if 0
353 if(!ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR))
354 return 0;
355
356 p = sc->sc_ibufp;
357
358 while(ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) {
359 c = bus_space_read_4(iot, ioh, EXUART_URXH);
360 if (p >= sc->sc_ibufend) {
361 sc->sc_floods++;
362 if (sc->sc_errors++ == 0)
363 timeout_add_sec(&sc->sc_diag_tmo, 60);
364 } else {
365 *p++ = c;
366 if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS))
367 /* XXX */
368 //CLR(sc->sc_ucr3, EXUART_CR3_DSR);
369 //bus_space_write_2(iot, ioh, EXUART_UCR3,
370 // sc->sc_ucr3);
371
372 }
373 /* XXX - msr stuff ? */
374 }
375 sc->sc_ibufp = p;
376
377 softintr_schedule(sc->sc_si);
378#endif
379
380 return 1;
381}
382
383int
384exuart_s5l_intr(void *arg)
385{
386 struct exuart_softc *sc = arg;
387 bus_space_tag_t iot = sc->sc_iot;
388 bus_space_handle_t ioh = sc->sc_ioh;
389 u_int32_t utrstat, uerstat;
390
391 utrstat = bus_space_read_4(iot, ioh, EXUART_UTRSTAT);
392 uerstat = bus_space_read_4(iot, ioh, EXUART_UERSTAT);
393
394 if (sc->sc_tty == NULL)
395 return (0);
396
397#ifdef DDB
398 if (uerstat & EXUART_UERSTAT_BREAK) {
399 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
400 if (db_console)
401 db_enter();
402 }
403 }
404#endif
405
406 if (utrstat & (EXUART_S5L_UTRSTAT_RXTHRESH |
407 EXUART_S5L_UTRSTAT_RX_TIMEOUT))
408 exuart_rx_intr(sc);
409
410 if (utrstat & EXUART_S5L_UTRSTAT_TXTHRESH)
411 exuart_tx_intr(sc);
412
413 bus_space_write_4(iot, ioh, EXUART_UTRSTAT, utrstat);
414
415 return 1;
416}
417
418int
419exuart_param(struct tty *tp, struct termios *t)
420{
421 struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
422 bus_space_tag_t iot = sc->sc_iot;
423 bus_space_handle_t ioh = sc->sc_ioh;
424 int ospeed = t->c_ospeed;
425 int error;
426 tcflag_t oldcflag;
427
428
429 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
430 return EINVAL;
431
432 switch (ISSET(t->c_cflag, CSIZE)) {
433 case CS5:
434 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
435 SET(sc->sc_ulcon, EXUART_ULCON_WORD_FIVE);
436 break;
437 case CS6:
438 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
439 SET(sc->sc_ulcon, EXUART_ULCON_WORD_SIX);
440 break;
441 case CS7:
442 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
443 SET(sc->sc_ulcon, EXUART_ULCON_WORD_SEVEN);
444 break;
445 case CS8:
446 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
447 SET(sc->sc_ulcon, EXUART_ULCON_WORD_EIGHT);
448 break;
449 }
450
451 CLR(sc->sc_ulcon, EXUART_ULCON_PARITY_MASK);
452 if (ISSET(t->c_cflag, PARENB)) {
453 if (ISSET(t->c_cflag, PARODD))
454 SET(sc->sc_ulcon, EXUART_ULCON_PARITY_ODD);
455 else
456 SET(sc->sc_ulcon, EXUART_ULCON_PARITY_EVEN);
457 }
458
459 if (ISSET(t->c_cflag, CSTOPB))
460 SET(sc->sc_ulcon, EXUART_ULCON_STOP_TWO);
461 else
462 CLR(sc->sc_ulcon, EXUART_ULCON_STOP_ONE);
463
464 bus_space_write_4(iot, ioh, EXUART_ULCON, sc->sc_ulcon);
465
466 if (ospeed == 0) {
467 /* lower dtr */
468 }
469
470 if (ospeed != 0) {
471 while (ISSET(tp->t_state, TS_BUSY)) {
472 ++sc->sc_halt;
473 error = ttysleep(tp, &tp->t_outq,
474 TTOPRI | PCATCH, "exuartprm");
475 --sc->sc_halt;
476 if (error) {
477 exuart_start(tp);
478 return (error);
479 }
480 }
481 /* set speed */
482 }
483
484 /* setup fifo */
485
486 /* When not using CRTSCTS, RTS follows DTR. */
487 /* sc->sc_dtr = MCR_DTR; */
488
489
490 /* and copy to tty */
491 tp->t_ispeed = t->c_ispeed;
492 tp->t_ospeed = t->c_ospeed;
493 oldcflag = tp->t_cflag;
494 tp->t_cflag = t->c_cflag;
495
496 /*
497 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
498 * stop the device.
499 */
500 /* XXX */
501
502 exuart_start(tp);
503
504 return 0;
505}
506
507void
508exuart_start(struct tty *tp)
509{
510 struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
511 bus_space_tag_t iot = sc->sc_iot;
512 bus_space_handle_t ioh = sc->sc_ioh;
513 int s;
514
515 s = spltty();
516 if (ISSET(tp->t_state, TS_BUSY))
517 goto out;
518 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
519 goto stopped;
520#ifdef DAMNFUCKSHIT
521 /* clear to send (IE the RTS pin on this shit) is not directly \
522 * readable - skip check for now
523 */
524 if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, EXUART_CTS))
525 goto stopped;
526#endif
527 ttwakeupwr(tp);
528 if (tp->t_outq.c_cc == 0)
529 goto stopped;
530 SET(tp->t_state, TS_BUSY);
531
532 {
533 u_char buffer[16];
534 int i, n;
535
536 n = q_to_b(&tp->t_outq, buffer, sizeof buffer);
537 for (i = 0; i < n; i++)
538 bus_space_write_4(iot, ioh, EXUART_UTXH, buffer[i]);
539 bzero(buffer, n);
540 }
541
542 if (sc->sc_type == EXUART_TYPE_S5L) {
543 if (!ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) {
544 SET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
545 bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
546 }
547 } else {
548 if (ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) {
549 CLR(sc->sc_uintm, EXUART_UINTM_TXD);
550 bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
551 }
552 }
553
554out:
555 splx(s);
556 return;
557stopped:
558 if (sc->sc_type == EXUART_TYPE_S5L) {
559 if (ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) {
560 CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
561 bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
562 }
563 } else {
564 if (!ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) {
565 SET(sc->sc_uintm, EXUART_UINTM_TXD);
566 bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
567 }
568 }
569 splx(s);
570}
571
572void
573exuart_diag(void *arg)
574{
575 struct exuart_softc *sc = arg;
576 int overflows, floods;
577 int s;
578
579 s = spltty();
580 sc->sc_errors = 0;
581 overflows = sc->sc_overflows;
582 sc->sc_overflows = 0;
583 floods = sc->sc_floods;
584 sc->sc_floods = 0;
585 splx(s);
586 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
587 sc->sc_dev.dv_xname,
588 overflows, overflows == 1 ? "" : "s",
589 floods, floods == 1 ? "" : "s");
590}
591
592void
593exuart_raisedtr(void *arg)
594{
595 //struct exuart_softc *sc = arg;
596
597 //SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
598 //bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, sc->sc_ucr3);
599}
600
601void
602exuart_softint(void *arg)
603{
604 struct exuart_softc *sc = arg;
605 struct tty *tp;
606 u_int16_t *ibufp;
607 u_int16_t *ibufend;
608 int c;
609 int err;
610 int s;
611
612 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
613 return;
614
615 tp = sc->sc_tty;
616
617 s = spltty();
618
619 ibufp = sc->sc_ibuf;
620 ibufend = sc->sc_ibufp;
621
622 if (ibufp == ibufend) {
623 splx(s);
624 return;
625 }
626
627 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
628 sc->sc_ibufs[1] : sc->sc_ibufs[0];
629 sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
630 sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
631
632 if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
633 splx(s);
634 return;
635 }
636
637#if 0
638 if (ISSET(tp->t_cflag, CRTSCTS) &&
639 !ISSET(sc->sc_ucr3, EXUART_CR3_DSR)) {
640 /* XXX */
641 SET(sc->sc_ucr3, EXUART_CR3_DSR);
642 bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3,
643 sc->sc_ucr3);
644 }
645#endif
646
647 splx(s);
648
649 while (ibufp < ibufend) {
650 c = *ibufp++;
651#if 0
652 if (ISSET(c, EXUART_UERSTAT_OVERRUN)) {
653 sc->sc_overflows++;
654 if (sc->sc_errors++ == 0)
655 timeout_add_sec(&sc->sc_diag_tmo, 60);
656 }
657#endif
658 err = 0;
659#if 0
660 if (ISSET(c, EXUART_UERSTAT_PARITY))
661 err |= TTY_PE;
662 if (ISSET(c, EXUART_UERSTAT_FRAME))
663 err |= TTY_FE;
664#endif
665 c = (c & 0xff) | err;
666 (*linesw[tp->t_line].l_rint)(c, tp);
667 }
668}
669
670int
671exuartopen(dev_t dev, int flag, int mode, struct proc *p)
672{
673 int unit = DEVUNIT(dev);
674 struct exuart_softc *sc;
675 bus_space_tag_t iot;
676 bus_space_handle_t ioh;
677 struct tty *tp;
678 int s;
679 int error = 0;
680
681 if (unit >= exuart_cd.cd_ndevs)
682 return ENXIO;
683 sc = exuart_cd.cd_devs[unit];
684 if (sc == NULL)
685 return ENXIO;
686
687 s = spltty();
688 if (sc->sc_tty == NULL)
689 tp = sc->sc_tty = ttymalloc(0);
690 else
691 tp = sc->sc_tty;
692 splx(s);
693
694 tp->t_oproc = exuart_start;
695 tp->t_param = exuart_param;
696 tp->t_dev = dev;
697 if (!ISSET(tp->t_state, TS_ISOPEN)) {
698 SET(tp->t_state, TS_WOPEN);
699 ttychars(tp);
700 tp->t_iflag = TTYDEF_IFLAG;
701 tp->t_oflag = TTYDEF_OFLAG;
702
703 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
704 tp->t_cflag = exuartconscflag;
705 else
706 tp->t_cflag = TTYDEF_CFLAG;
707 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
708 SET(tp->t_cflag, CLOCAL);
709 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
710 SET(tp->t_cflag, CRTSCTS);
711 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
712 SET(tp->t_cflag, MDMBUF);
713 tp->t_lflag = TTYDEF_LFLAG;
714 tp->t_ispeed = tp->t_ospeed = exuartdefaultrate;
715
716 s = spltty();
717
718 sc->sc_initialize = 1;
719 exuart_param(tp, &tp->t_termios);
720 ttsetwater(tp);
721
722 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
723 sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
724 sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
725
726 iot = sc->sc_iot;
727 ioh = sc->sc_ioh;
728
729 sc->sc_ulcon = bus_space_read_4(iot, ioh, EXUART_ULCON);
730 sc->sc_ucon = bus_space_read_4(iot, ioh, EXUART_UCON);
731 sc->sc_ufcon = bus_space_read_4(iot, ioh, EXUART_UFCON);
732 sc->sc_umcon = bus_space_read_4(iot, ioh, EXUART_UMCON);
733
734 if (sc->sc_type == EXUART_TYPE_S5L) {
735 SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
736 SET(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH);
737 SET(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT);
738 bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
739 } else {
740 sc->sc_uintm = bus_space_read_4(iot, ioh, EXUART_UINTM);
741 CLR(sc->sc_uintm, EXUART_UINTM_RXD);
742 bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
743 }
744
745#if 0
746 /* interrupt after one char on tx/rx */
747 /* reference frequency divider: 1 */
748 bus_space_write_2(iot, ioh, EXUART_UFCR,
749 1 << EXUART_FCR_TXTL_SH |
750 5 << EXUART_FCR_RFDIV_SH |
751 1 << EXUART_FCR_RXTL_SH);
752
753 bus_space_write_2(iot, ioh, EXUART_UBIR,
754 (exuartdefaultrate / 100) - 1);
755
756 /* formula: clk / (rfdiv * 1600) */
757 bus_space_write_2(iot, ioh, EXUART_UBMR,
758 (exccm_get_uartclk() * 1000) / 1600);
759
760 SET(sc->sc_ucr1, EXUART_CR1_EN|EXUART_CR1_RRDYEN);
761 SET(sc->sc_ucr2, EXUART_CR2_TXEN|EXUART_CR2_RXEN);
762 bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
763 bus_space_write_2(iot, ioh, EXUART_UCR2, sc->sc_ucr2);
764
765 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
766 SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
767 bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
768#endif
769
770 SET(tp->t_state, TS_CARR_ON); /* XXX */
771
772
773 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
774 return EBUSY;
775 else
776 s = spltty();
777
778 if (DEVCUA(dev)) {
779 if (ISSET(tp->t_state, TS_ISOPEN)) {
780 splx(s);
781 return EBUSY;
782 }
783 sc->sc_cua = 1;
784 } else {
785 /* tty (not cua) device; wait for carrier if necessary */
786 if (ISSET(flag, O_NONBLOCK)) {
787 if (sc->sc_cua) {
788 /* Opening TTY non-blocking... but the CUA is busy */
789 splx(s);
790 return EBUSY;
791 }
792 } else {
793 while (sc->sc_cua ||
794 (!ISSET(tp->t_cflag, CLOCAL) &&
795 !ISSET(tp->t_state, TS_CARR_ON))) {
796 SET(tp->t_state, TS_WOPEN);
797 error = ttysleep(tp, &tp->t_rawq,
798 TTIPRI | PCATCH, ttopen);
799 /*
800 * If TS_WOPEN has been reset, that means the
801 * cua device has been closed. We don't want
802 * to fail in that case,
803 * so just go around again.
804 */
805 if (error && ISSET(tp->t_state, TS_WOPEN)) {
806 CLR(tp->t_state, TS_WOPEN);
807 splx(s);
808 return error;
809 }
810 }
811 }
812 }
813 splx(s);
814
815 return (*linesw[tp->t_line].l_open)(dev,tp,p);
816}
817
818int
819exuartclose(dev_t dev, int flag, int mode, struct proc *p)
820{
821 int unit = DEVUNIT(dev);
822 struct exuart_softc *sc = exuart_cd.cd_devs[unit];
823 //bus_space_tag_t iot = sc->sc_iot;
824 //bus_space_handle_t ioh = sc->sc_ioh;
825 struct tty *tp = sc->sc_tty;
826 int s;
827
828 /* XXX This is for cons.c. */
829 if (!ISSET(tp->t_state, TS_ISOPEN))
830 return 0;
831
832 (*linesw[tp->t_line].l_close)(tp, flag, p);
833 s = spltty();
834 if (ISSET(tp->t_state, TS_WOPEN)) {
835 /* tty device is waiting for carrier; drop dtr then re-raise */
836 //CLR(sc->sc_ucr3, EXUART_CR3_DSR);
837 //bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
838 timeout_add_sec(&sc->sc_dtr_tmo, 2);
839 }
840 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
841 sc->sc_cua = 0;
842 splx(s);
843 ttyclose(tp);
844
845 return 0;
846}
847
848int
849exuartread(dev_t dev, struct uio *uio, int flag)
850{
851 struct tty *tty;
852
853 tty = exuarttty(dev);
854 if (tty == NULL)
855 return ENODEV;
856
857 return((*linesw[tty->t_line].l_read)(tty, uio, flag));
858}
859
860int
861exuartwrite(dev_t dev, struct uio *uio, int flag)
862{
863 struct tty *tty;
864
865 tty = exuarttty(dev);
866 if (tty == NULL)
867 return ENODEV;
868
869 return((*linesw[tty->t_line].l_write)(tty, uio, flag));
870}
871
872int
873exuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
874{
875 struct exuart_softc *sc;
876 struct tty *tp;
877 int error;
878
879 sc = exuart_sc(dev);
880 if (sc == NULL)
881 return (ENODEV);
882
883 tp = sc->sc_tty;
884 if (tp == NULL)
885 return (ENXIO);
886
887 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
888 if (error >= 0)
889 return (error);
890
891 error = ttioctl(tp, cmd, data, flag, p);
892 if (error >= 0)
893 return (error);
894
895 switch(cmd) {
896 case TIOCSBRK:
897 /* */
898 break;
899
900 case TIOCCBRK:
901 /* */
902 break;
903
904 case TIOCSDTR:
905#if 0
906 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
907#endif
908 break;
909
910 case TIOCCDTR:
911#if 0
912 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
913#endif
914 break;
915
916 case TIOCMSET:
917#if 0
918 (void) clmctl(dev, *(int *) data, DMSET);
919#endif
920 break;
921
922 case TIOCMBIS:
923#if 0
924 (void) clmctl(dev, *(int *) data, DMBIS);
925#endif
926 break;
927
928 case TIOCMBIC:
929#if 0
930 (void) clmctl(dev, *(int *) data, DMBIC);
931#endif
932 break;
933
934 case TIOCMGET:
935#if 0
936 *(int *)data = clmctl(dev, 0, DMGET);
937#endif
938 break;
939
940 case TIOCGFLAGS:
941#if 0
942 *(int *)data = cl->cl_swflags;
943#endif
944 break;
945
946 case TIOCSFLAGS:
947 error = suser(p);
948 if (error != 0)
949 return(EPERM);
950
951#if 0
952 cl->cl_swflags = *(int *)data;
953 cl->cl_swflags &= /* only allow valid flags */
954 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
955#endif
956 break;
957 default:
958 return (ENOTTY);
959 }
960
961 return 0;
962}
963
964int
965exuartstop(struct tty *tp, int flag)
966{
967 return 0;
968}
969
970struct tty *
971exuarttty(dev_t dev)
972{
973 int unit;
974 struct exuart_softc *sc;
975 unit = DEVUNIT(dev);
976 if (unit >= exuart_cd.cd_ndevs)
977 return NULL;
978 sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
979 if (sc == NULL)
980 return NULL;
981 return sc->sc_tty;
982}
983
984struct exuart_softc *
985exuart_sc(dev_t dev)
986{
987 int unit;
988 struct exuart_softc *sc;
989 unit = DEVUNIT(dev);
990 if (unit >= exuart_cd.cd_ndevs)
991 return NULL;
992 sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
993 return sc;
994}
995
996
997/* serial console */
998void
999exuartcnprobe(struct consdev *cp)
1000{
1001}
1002
1003void
1004exuartcninit(struct consdev *cp)
1005{
1006}
1007
1008int
1009exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
1010{
1011 static struct consdev exuartcons = {
1012 NULL, NULL, exuartcngetc, exuartcnputc, exuartcnpollc, NULL,
1013 NODEV, CN_MIDPRI
1014 };
1015 int maj;
1016
1017 if (bus_space_map(iot, iobase, 0x100, 0, &exuartconsioh))
1018 return ENOMEM;
1019
1020 /* Look for major of com(4) to replace. */
1021 for (maj = 0; maj < nchrdev; maj++)
1022 if (cdevsw[maj].d_open == comopen)
1023 break;
1024 if (maj == nchrdev)
1025 return ENXIO;
1026
1027 cn_tab = &exuartcons;
1028 cn_tab->cn_dev = makedev(maj, 0);
1029 cdevsw[maj] = exuartdev; /* KLUDGE */
1030
1031 exuartconsiot = iot;
1032 exuartconsaddr = iobase;
1033 exuartconscflag = cflag;
1034
1035 return 0;
1036}
1037
1038int
1039exuartcngetc(dev_t dev)
1040{
1041 int c;
1042 int s;
1043 s = splhigh();
1044 while((bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
1045 EXUART_UTRSTAT_RXBREADY) == 0 &&
1046 (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
1047 (exuart_rx_fifo_cnt_mask | exuart_rx_fifo_full)) == 0)
1048 ;
1049 c = bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_URXH);
1050 splx(s);
1051 return c;
1052}
1053
1054void
1055exuartcnputc(dev_t dev, int c)
1056{
1057 int s;
1058 s = splhigh();
1059 while (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
1060 exuart_tx_fifo_full)
1061 ;
1062 bus_space_write_4(exuartconsiot, exuartconsioh, EXUART_UTXH, c);
1063 splx(s);
1064}
1065
1066void
1067exuartcnpollc(dev_t dev, int on)
1068{
1069}