1 /* $NetBSD: epcom.c,v 1.36 2022/10/26 23:38:06 riastradh Exp $ */
2 /*
3 * Copyright (c) 1998, 1999, 2001, 2002, 2004 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Jesse Off
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Ichiro FUKUHARA and Naoto Shimazaki.
11 *
12 * This code is derived from software contributed to The NetBSD Foundation
13 * by IWAMOTO Toshihiro.
14 *
15 * This code is derived from software contributed to The NetBSD Foundation
16 * by Charles M. Hannum.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1991 The Regents of the University of California.
42 * All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * @(#)com.c 7.5 (Berkeley) 5/16/91
69 */
70
71 /*
72 * TODO: hardware flow control
73 */
74
75 #include <sys/cdefs.h>
76 __KERNEL_RCSID(0, "$NetBSD: epcom.c,v 1.36 2022/10/26 23:38:06 riastradh Exp $");
77
78 #include "opt_kgdb.h"
79 #include "epcom.h"
80
81 #ifdef RND_COM
82 #include <sys/rndsource.h>
83 #endif
84
85 /*
86 * Override cnmagic(9) macro before including <sys/systm.h>.
87 * We need to know if cn_check_magic triggered debugger, so set a flag.
88 * Callers of cn_check_magic must declare int cn_trapped = 0;
89 * XXX: this is *ugly*!
90 */
91 #define cn_trap() \
92 do { \
93 console_debugger(); \
94 cn_trapped = 1; \
95 } while (/* CONSTCOND */ 0)
96
97
98 #include <sys/param.h>
99 #include <sys/systm.h>
100 #include <sys/types.h>
101 #include <sys/conf.h>
102 #include <sys/file.h>
103 #include <sys/device.h>
104 #include <sys/kernel.h>
105 #include <sys/kmem.h>
106 #include <sys/tty.h>
107 #include <sys/uio.h>
108 #include <sys/vnode.h>
109 #include <sys/kauth.h>
110
111 #include <machine/intr.h>
112 #include <sys/bus.h>
113
114 #include <ddb/db_active.h>
115
116 #include <arm/ep93xx/epcomreg.h>
117 #include <arm/ep93xx/epcomvar.h>
118 #include <arm/ep93xx/ep93xxreg.h>
119 #include <arm/ep93xx/ep93xxvar.h>
120
121 #include <dev/cons.h>
122
123 static int epcomparam(struct tty *, struct termios *);
124 static void epcomstart(struct tty *);
125 static int epcomhwiflow(struct tty *, int);
126
127 static u_int cflag2lcrhi(tcflag_t);
128 static void epcom_iflush(struct epcom_softc *);
129 static void epcom_set(struct epcom_softc *);
130
131 int epcomcngetc(dev_t);
132 void epcomcnputc(dev_t, int);
133 void epcomcnpollc(dev_t, int);
134
135 static void epcomsoft(void* arg);
136 inline static void epcom_txsoft(struct epcom_softc *, struct tty *);
137 inline static void epcom_rxsoft(struct epcom_softc *, struct tty *);
138
139 void epcomcnprobe(struct consdev *);
140 void epcomcninit(struct consdev *);
141
142 static struct epcom_cons_softc {
143 bus_space_tag_t sc_iot;
144 bus_space_handle_t sc_ioh;
145 bus_addr_t sc_hwbase;
146 int sc_ospeed;
147 tcflag_t sc_cflag;
148 } epcomcn_sc;
149
150 static int epcom_common_getc(struct epcom_cons_softc *, dev_t);
151 static void epcom_common_putc(struct epcom_cons_softc *, int);
152 static void epcominit(struct epcom_cons_softc *, bus_space_tag_t,
153 bus_addr_t, bus_space_handle_t, int, tcflag_t);
154
155 static struct cnm_state epcom_cnm_state;
156
157 extern struct cfdriver epcom_cd;
158
159 dev_type_open(epcomopen);
160 dev_type_close(epcomclose);
161 dev_type_read(epcomread);
162 dev_type_write(epcomwrite);
163 dev_type_ioctl(epcomioctl);
164 dev_type_stop(epcomstop);
165 dev_type_tty(epcomtty);
166 dev_type_poll(epcompoll);
167
168 const struct cdevsw epcom_cdevsw = {
169 .d_open = epcomopen,
170 .d_close = epcomclose,
171 .d_read = epcomread,
172 .d_write = epcomwrite,
173 .d_ioctl = epcomioctl,
174 .d_stop = epcomstop,
175 .d_tty = epcomtty,
176 .d_poll = epcompoll,
177 .d_mmap = nommap,
178 .d_kqfilter = ttykqfilter,
179 .d_discard = nodiscard,
180 .d_flag = D_TTY
181 };
182
183 struct consdev epcomcons = {
184 NULL, NULL, epcomcngetc, epcomcnputc, epcomcnpollc, NULL,
185 NULL, NULL, NODEV, CN_NORMAL
186 };
187
188 #if defined(KGDB)
189 #include <sys/kgdb.h>
190
191 static int epcom_kgdb_getc(void *);
192 static void epcom_kgdb_putc(void *, int);
193
194 /*
195 * Reuse the console softc structure because
196 * we'll be reusing the console I/O code.
197 */
198 static struct epcom_cons_softc kgdb_sc;
199 #endif
200
201 #ifndef DEFAULT_COMSPEED
202 #define DEFAULT_COMSPEED 115200
203 #endif
204
205 #define COMUNIT(x) TTUNIT(x)
206 #define COMDIALOUT(x) TTDIALOUT(x)
207
208 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \
209 device_is_active((sc)->sc_dev))
210
211 void
epcom_attach_subr(struct epcom_softc * sc)212 epcom_attach_subr(struct epcom_softc *sc)
213 {
214 struct tty *tp;
215
216 if (sc->sc_iot == epcomcn_sc.sc_iot
217 && sc->sc_hwbase == epcomcn_sc.sc_hwbase) {
218 sc->sc_lcrlo = EPCOMSPEED2BRD(epcomcn_sc.sc_ospeed) & 0xff;
219 sc->sc_lcrmid = EPCOMSPEED2BRD(epcomcn_sc.sc_ospeed) >> 8;
220
221 /* Make sure the console is always "hardwired". */
222 delay(10000); /* wait for output to finish */
223 SET(sc->sc_hwflags, COM_HW_CONSOLE);
224 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
225 }
226
227 tp = tty_alloc();
228 tp->t_oproc = epcomstart;
229 tp->t_param = epcomparam;
230 tp->t_hwiflow = epcomhwiflow;
231
232 sc->sc_tty = tp;
233 sc->sc_rbuf = kmem_alloc(EPCOM_RING_SIZE << 1, KM_SLEEP);
234 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
235 sc->sc_rbavail = EPCOM_RING_SIZE;
236 sc->sc_ebuf = sc->sc_rbuf + (EPCOM_RING_SIZE << 1);
237 sc->sc_tbc = 0;
238
239 sc->sc_lcrlo = EPCOMSPEED2BRD(DEFAULT_COMSPEED) & 0xff;
240 sc->sc_lcrmid = EPCOMSPEED2BRD(DEFAULT_COMSPEED) >> 8;
241 sc->sc_lcrhi = cflag2lcrhi(CS8); /* 8N1 */
242
243 tty_attach(tp);
244
245 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
246 int maj;
247
248 /* locate the major number */
249 maj = cdevsw_lookup_major(&epcom_cdevsw);
250
251 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
252
253 aprint_normal("%s: console\n", device_xname(sc->sc_dev));
254 }
255
256 #ifdef KGDB
257 /*
258 * Allow kgdb to "take over" this port. If this is
259 * the kgdb device, it has exclusive use.
260 */
261 if (sc->sc_iot == kgdb_sc.sc_iot &&
262 sc->sc_hwbase == kgdb_sc.sc_hwbase) {
263 SET(sc->sc_hwflags, COM_HW_KGDB);
264 device_printf(sc->sc_dev, "kgdb\n");
265 }
266 #endif
267
268 sc->sc_si = softint_establish(SOFTINT_SERIAL, epcomsoft, sc);
269
270 #ifdef RND_COM
271 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
272 RND_TYPE_TTY, RND_FLAG_DEFAULT);
273 #endif
274
275 /* if there are no enable/disable functions, assume the device
276 is always enabled */
277 if (!sc->enable)
278 sc->enabled = 1;
279
280 /* XXX configure register */
281 /* xxx_config(sc) */
282
283 SET(sc->sc_hwflags, COM_HW_DEV_OK);
284 }
285
286 static int
epcomparam(struct tty * tp,struct termios * t)287 epcomparam(struct tty *tp, struct termios *t)
288 {
289 struct epcom_softc *sc
290 = device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev));
291 int s;
292
293 if (COM_ISALIVE(sc) == 0)
294 return (EIO);
295
296 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
297 return (EINVAL);
298
299 /*
300 * For the console, always force CLOCAL and !HUPCL, so that the port
301 * is always active.
302 */
303 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
304 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
305 SET(t->c_cflag, CLOCAL);
306 CLR(t->c_cflag, HUPCL);
307 }
308
309 /*
310 * If there were no changes, don't do anything. This avoids dropping
311 * input and improves performance when all we did was frob things like
312 * VMIN and VTIME.
313 */
314 if (tp->t_ospeed == t->c_ospeed &&
315 tp->t_cflag == t->c_cflag)
316 return (0);
317
318 s = splserial();
319
320 sc->sc_lcrhi = cflag2lcrhi(t->c_cflag);
321 sc->sc_lcrlo = EPCOMSPEED2BRD(t->c_ospeed) & 0xff;
322 sc->sc_lcrmid = EPCOMSPEED2BRD(t->c_ospeed) >> 8;
323
324 /* And copy to tty. */
325 tp->t_ispeed = 0;
326 tp->t_ospeed = t->c_ospeed;
327 tp->t_cflag = t->c_cflag;
328 epcom_set(sc);
329
330 splx(s);
331
332 /*
333 * Update the tty layer's idea of the carrier bit.
334 * We tell tty the carrier is always on.
335 */
336 (void) (*tp->t_linesw->l_modem)(tp, 1);
337
338 #ifdef COM_DEBUG
339 if (com_debug)
340 comstatus(sc, "comparam ");
341 #endif
342
343 if (!ISSET(t->c_cflag, CHWFLOW)) {
344 if (sc->sc_tx_stopped) {
345 sc->sc_tx_stopped = 0;
346 epcomstart(tp);
347 }
348 }
349
350 return (0);
351 }
352
353 static int
epcomhwiflow(struct tty * tp,int block)354 epcomhwiflow(struct tty *tp, int block)
355 {
356 return (0);
357 }
358
359 static void
epcom_filltx(struct epcom_softc * sc)360 epcom_filltx(struct epcom_softc *sc)
361 {
362 bus_space_tag_t iot = sc->sc_iot;
363 bus_space_handle_t ioh = sc->sc_ioh;
364 int n;
365
366 n = 0;
367 while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFF) == 0) {
368 if (n >= sc->sc_tbc)
369 break;
370 bus_space_write_4(iot, ioh, EPCOM_Data,
371 0xff & *(sc->sc_tba + n));
372 n++;
373 }
374 sc->sc_tbc -= n;
375 sc->sc_tba += n;
376 }
377
378 static void
epcomstart(struct tty * tp)379 epcomstart(struct tty *tp)
380 {
381 struct epcom_softc *sc
382 = device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev));
383 int s;
384
385 if (COM_ISALIVE(sc) == 0)
386 return;
387
388 s = spltty();
389 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
390 goto out;
391 if (sc->sc_tx_stopped)
392 goto out;
393 if (!ttypull(tp))
394 goto out;
395
396 /* Grab the first contiguous region of buffer space. */
397 {
398 u_char *tba;
399 int tbc;
400
401 tba = tp->t_outq.c_cf;
402 tbc = ndqb(&tp->t_outq, 0);
403
404 (void)splserial();
405
406 sc->sc_tba = tba;
407 sc->sc_tbc = tbc;
408 }
409
410 SET(tp->t_state, TS_BUSY);
411 sc->sc_tx_busy = 1;
412
413 /* Output the first chunk of the contiguous buffer. */
414 epcom_filltx(sc);
415
416 if (!ISSET(sc->sc_ctrl, Ctrl_TIE)) {
417 SET(sc->sc_ctrl, Ctrl_TIE);
418 epcom_set(sc);
419 }
420
421 out:
422 splx(s);
423 return;
424 }
425
426 static void
epcom_break(struct epcom_softc * sc,int onoff)427 epcom_break(struct epcom_softc *sc, int onoff)
428 {
429 if (onoff)
430 SET(sc->sc_lcrhi, LinCtrlHigh_BRK);
431 else
432 CLR(sc->sc_lcrhi, LinCtrlHigh_BRK);
433 epcom_set(sc);
434 }
435
436 static void
epcom_shutdown(struct epcom_softc * sc)437 epcom_shutdown(struct epcom_softc *sc)
438 {
439 int s;
440
441 s = splserial();
442
443 /* Turn off interrupts. */
444 CLR(sc->sc_ctrl, (Ctrl_TIE|Ctrl_RTIE|Ctrl_RIE));
445
446 /* Clear any break condition set with TIOCSBRK. */
447 epcom_break(sc, 0);
448 epcom_set(sc);
449
450 if (sc->disable) {
451 #ifdef DIAGNOSTIC
452 if (!sc->enabled)
453 panic("epcom_shutdown: not enabled?");
454 #endif
455 (*sc->disable)(sc);
456 sc->enabled = 0;
457 }
458 splx(s);
459 }
460
461 int
epcomopen(dev_t dev,int flag,int mode,struct lwp * l)462 epcomopen(dev_t dev, int flag, int mode, struct lwp *l)
463 {
464 struct epcom_softc *sc;
465 struct tty *tp;
466 int s, s2;
467 int error;
468
469 sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
470 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) ||
471 sc->sc_rbuf == NULL)
472 return (ENXIO);
473
474 if (!device_is_active(sc->sc_dev))
475 return (ENXIO);
476
477 #ifdef KGDB
478 /*
479 * If this is the kgdb port, no other use is permitted.
480 */
481 if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
482 return (EBUSY);
483 #endif
484
485 tp = sc->sc_tty;
486
487 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
488 return (EBUSY);
489
490 s = spltty();
491
492 /*
493 * Do the following iff this is a first open.
494 */
495 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
496 struct termios t;
497
498 tp->t_dev = dev;
499
500 s2 = splserial();
501
502 if (sc->enable) {
503 if ((*sc->enable)(sc)) {
504 splx(s2);
505 splx(s);
506 printf("%s: device enable failed\n",
507 device_xname(sc->sc_dev));
508 return (EIO);
509 }
510 sc->enabled = 1;
511 #if 0
512 /* XXXXXXXXXXXXXXX */
513 com_config(sc);
514 #endif
515 }
516
517 /* Turn on interrupts. */
518 SET(sc->sc_ctrl, (Ctrl_UARTE|Ctrl_RIE|Ctrl_RTIE));
519 epcom_set(sc);
520
521 #if 0
522 /* Fetch the current modem control status, needed later. */
523 sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr);
524
525 /* Clear PPS capture state on first open. */
526 sc->sc_ppsmask = 0;
527 sc->ppsparam.mode = 0;
528 #endif
529
530 splx(s2);
531
532 /*
533 * Initialize the termios status to the defaults. Add in the
534 * sticky bits from TIOCSFLAGS.
535 */
536 t.c_ispeed = 0;
537 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
538 t.c_ospeed = epcomcn_sc.sc_ospeed;
539 t.c_cflag = epcomcn_sc.sc_cflag;
540 } else {
541 t.c_ospeed = TTYDEF_SPEED;
542 t.c_cflag = TTYDEF_CFLAG;
543 }
544 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
545 SET(t.c_cflag, CLOCAL);
546 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
547 SET(t.c_cflag, CRTSCTS);
548 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
549 SET(t.c_cflag, MDMBUF);
550 /* Make sure epcomparam() will do something. */
551 tp->t_ospeed = 0;
552 (void) epcomparam(tp, &t);
553 tp->t_iflag = TTYDEF_IFLAG;
554 tp->t_oflag = TTYDEF_OFLAG;
555 tp->t_lflag = TTYDEF_LFLAG;
556 ttychars(tp);
557 ttsetwater(tp);
558
559 s2 = splserial();
560
561 /* Clear the input ring, and unblock. */
562 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
563 sc->sc_rbavail = EPCOM_RING_SIZE;
564 epcom_iflush(sc);
565 CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
566
567 #ifdef COM_DEBUG
568 if (epcom_debug)
569 comstatus(sc, "epcomopen ");
570 #endif
571
572 splx(s2);
573 }
574
575 splx(s);
576
577 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
578 if (error)
579 goto bad;
580
581 error = (*tp->t_linesw->l_open)(dev, tp);
582 if (error)
583 goto bad;
584
585 return (0);
586
587 bad:
588 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
589 /*
590 * We failed to open the device, and nobody else had it opened.
591 * Clean up the state as appropriate.
592 */
593 epcom_shutdown(sc);
594 }
595
596 return (error);
597 }
598
599 int
epcomclose(dev_t dev,int flag,int mode,struct lwp * l)600 epcomclose(dev_t dev, int flag, int mode, struct lwp *l)
601 {
602 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
603 struct tty *tp = sc->sc_tty;
604
605 /* XXX This is for cons.c. */
606 if (!ISSET(tp->t_state, TS_ISOPEN))
607 return (0);
608
609 (*tp->t_linesw->l_close)(tp, flag);
610 ttyclose(tp);
611
612 if (COM_ISALIVE(sc) == 0)
613 return (0);
614
615 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
616 /*
617 * Although we got a last close, the device may still be in
618 * use; e.g. if this was the dialout node, and there are still
619 * processes waiting for carrier on the non-dialout node.
620 */
621 epcom_shutdown(sc);
622 }
623
624 return (0);
625 }
626
627 int
epcomread(dev_t dev,struct uio * uio,int flag)628 epcomread(dev_t dev, struct uio *uio, int flag)
629 {
630 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
631 struct tty *tp = sc->sc_tty;
632
633 if (COM_ISALIVE(sc) == 0)
634 return (EIO);
635
636 return ((*tp->t_linesw->l_read)(tp, uio, flag));
637 }
638
639 int
epcomwrite(dev_t dev,struct uio * uio,int flag)640 epcomwrite(dev_t dev, struct uio *uio, int flag)
641 {
642 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
643 struct tty *tp = sc->sc_tty;
644
645 if (COM_ISALIVE(sc) == 0)
646 return (EIO);
647
648 return ((*tp->t_linesw->l_write)(tp, uio, flag));
649 }
650
651 int
epcompoll(dev_t dev,int events,struct lwp * l)652 epcompoll(dev_t dev, int events, struct lwp *l)
653 {
654 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
655 struct tty *tp = sc->sc_tty;
656
657 if (COM_ISALIVE(sc) == 0)
658 return (EIO);
659
660 return ((*tp->t_linesw->l_poll)(tp, events, l));
661 }
662
663 struct tty *
epcomtty(dev_t dev)664 epcomtty(dev_t dev)
665 {
666 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
667 struct tty *tp = sc->sc_tty;
668
669 return (tp);
670 }
671
672 int
epcomioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)673 epcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
674 {
675 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
676 struct tty *tp = sc->sc_tty;
677 int error;
678 int s;
679
680 if (COM_ISALIVE(sc) == 0)
681 return (EIO);
682
683 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
684 if (error != EPASSTHROUGH)
685 return (error);
686
687 error = ttioctl(tp, cmd, data, flag, l);
688 if (error != EPASSTHROUGH)
689 return (error);
690
691 error = 0;
692
693 s = splserial();
694
695 switch (cmd) {
696 case TIOCSBRK:
697 epcom_break(sc, 1);
698 break;
699
700 case TIOCCBRK:
701 epcom_break(sc, 0);
702 break;
703
704 case TIOCGFLAGS:
705 *(int *)data = sc->sc_swflags;
706 break;
707
708 case TIOCSFLAGS:
709 error = kauth_authorize_device_tty(l->l_cred,
710 KAUTH_DEVICE_TTY_PRIVSET, tp);
711 if (error)
712 break;
713 sc->sc_swflags = *(int *)data;
714 break;
715
716 default:
717 error = EPASSTHROUGH;
718 break;
719 }
720
721 splx(s);
722
723 return (error);
724 }
725
726 /*
727 * Stop output on a line.
728 */
729 void
epcomstop(struct tty * tp,int flag)730 epcomstop(struct tty *tp, int flag)
731 {
732 struct epcom_softc *sc
733 = device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev));
734 int s;
735
736 s = splserial();
737 if (ISSET(tp->t_state, TS_BUSY)) {
738 /* Stop transmitting at the next chunk. */
739 sc->sc_tbc = 0;
740 if (!ISSET(tp->t_state, TS_TTSTOP))
741 SET(tp->t_state, TS_FLUSH);
742 }
743 splx(s);
744 }
745
746 static u_int
cflag2lcrhi(tcflag_t cflag)747 cflag2lcrhi(tcflag_t cflag)
748 {
749 u_int lcrhi;
750
751 switch (cflag & CSIZE) {
752 case CS7:
753 lcrhi = 0x40;
754 break;
755 case CS6:
756 lcrhi = 0x20;
757 break;
758 case CS8:
759 default:
760 lcrhi = 0x60;
761 break;
762 }
763 lcrhi |= (cflag & PARENB) ? LinCtrlHigh_PEN : 0;
764 lcrhi |= (cflag & PARODD) ? 0 : LinCtrlHigh_EPS;
765 lcrhi |= (cflag & CSTOPB) ? LinCtrlHigh_STP2 : 0;
766 lcrhi |= LinCtrlHigh_FEN; /* FIFO always enabled */
767
768 return (lcrhi);
769 }
770
771 static void
epcom_iflush(struct epcom_softc * sc)772 epcom_iflush(struct epcom_softc *sc)
773 {
774 bus_space_tag_t iot = sc->sc_iot;
775 bus_space_handle_t ioh = sc->sc_ioh;
776 #ifdef DIAGNOSTIC
777 int reg;
778 #endif
779 int timo;
780
781 #ifdef DIAGNOSTIC
782 reg = 0xffff;
783 #endif
784 timo = 50000;
785 /* flush any pending I/O */
786 while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_RXFE) == 0
787 && --timo)
788 #ifdef DIAGNOSTIC
789 reg =
790 #else
791 (void)
792 #endif
793 bus_space_read_4(iot, ioh, EPCOM_Data);
794 #ifdef DIAGNOSTIC
795 if (!timo)
796 printf("%s: com_iflush timeout %02x\n", device_xname(sc->sc_dev),
797 reg);
798 #endif
799 }
800
801 static void
epcom_set(struct epcom_softc * sc)802 epcom_set(struct epcom_softc *sc)
803 {
804 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlLow,
805 sc->sc_lcrlo);
806 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlMid,
807 sc->sc_lcrmid);
808 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlHigh,
809 sc->sc_lcrhi);
810 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_Ctrl,
811 sc->sc_ctrl);
812 }
813
814 int
epcomcnattach(bus_space_tag_t iot,bus_addr_t iobase,bus_space_handle_t ioh,int ospeed,tcflag_t cflag)815 epcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh,
816 int ospeed, tcflag_t cflag)
817 {
818 cn_tab = &epcomcons;
819 cn_init_magic(&epcom_cnm_state);
820 cn_set_magic("\047\001");
821
822 epcominit(&epcomcn_sc, iot, iobase, ioh, ospeed, cflag);
823
824 return (0);
825 }
826
827 void
epcomcnprobe(struct consdev * cp)828 epcomcnprobe(struct consdev *cp)
829 {
830 cp->cn_pri = CN_REMOTE;
831 }
832
833 void
epcomcnpollc(dev_t dev,int on)834 epcomcnpollc(dev_t dev, int on)
835 {
836 }
837
838 void
epcomcnputc(dev_t dev,int c)839 epcomcnputc(dev_t dev, int c)
840 {
841 epcom_common_putc(&epcomcn_sc, c);
842 }
843
844 static void
epcom_common_putc(struct epcom_cons_softc * sc,int c)845 epcom_common_putc(struct epcom_cons_softc *sc, int c)
846 {
847 int s;
848 bus_space_tag_t iot = sc->sc_iot;
849 bus_space_handle_t ioh = sc->sc_ioh;
850
851 s = splserial();
852
853 while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFF) != 0)
854 ;
855
856 bus_space_write_4(iot, ioh, EPCOM_Data, c);
857
858 #ifdef DEBUG
859 if (c == '\r') {
860 while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFE) == 0)
861 ;
862 }
863 #endif
864
865 splx(s);
866 }
867
868 int
epcomcngetc(dev_t dev)869 epcomcngetc(dev_t dev)
870 {
871 return epcom_common_getc (&epcomcn_sc, dev);
872 }
873
874 static int
epcom_common_getc(struct epcom_cons_softc * sc,dev_t dev)875 epcom_common_getc(struct epcom_cons_softc *sc, dev_t dev)
876 {
877 int c, sts;
878 int s;
879 bus_space_tag_t iot = sc->sc_iot;
880 bus_space_handle_t ioh = sc->sc_ioh;
881
882 s = splserial();
883
884 while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_RXFE) != 0)
885 continue;
886
887 c = bus_space_read_4(iot, ioh, EPCOM_Data);
888 sts = bus_space_read_4(iot, ioh, EPCOM_RXSts);
889 if (ISSET(sts, RXSts_BE))
890 c = CNC_BREAK;
891 if (!db_active) {
892 int cn_trapped __unused = 0;
893
894 cn_check_magic(dev, c, epcom_cnm_state);
895 }
896 c &= 0xff;
897 splx(s);
898
899 return (c);
900 }
901
902 inline static void
epcom_txsoft(struct epcom_softc * sc,struct tty * tp)903 epcom_txsoft(struct epcom_softc *sc, struct tty *tp)
904 {
905 CLR(tp->t_state, TS_BUSY);
906 if (ISSET(tp->t_state, TS_FLUSH))
907 CLR(tp->t_state, TS_FLUSH);
908 else
909 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
910 (*tp->t_linesw->l_start)(tp);
911 }
912
913 inline static void
epcom_rxsoft(struct epcom_softc * sc,struct tty * tp)914 epcom_rxsoft(struct epcom_softc *sc, struct tty *tp)
915 {
916 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
917 u_char *get, *end;
918 u_int cc, scc;
919 u_char sts;
920 int code;
921 int s;
922
923 end = sc->sc_ebuf;
924 get = sc->sc_rbget;
925 scc = cc = EPCOM_RING_SIZE - sc->sc_rbavail;
926 #if 0
927 if (cc == EPCOM_RING_SIZE) {
928 sc->sc_floods++;
929 if (sc->sc_errors++ == 0)
930 callout_reset(&sc->sc_diag_callout, 60 * hz,
931 comdiag, sc);
932 }
933 #endif
934 while (cc) {
935 code = get[0];
936 sts = get[1];
937 if (ISSET(sts, RXSts_OE | RXSts_FE | RXSts_PE | RXSts_BE)) {
938 #if 0
939 if (ISSET(lsr, DR_ROR)) {
940 sc->sc_overflows++;
941 if (sc->sc_errors++ == 0)
942 callout_reset(&sc->sc_diag_callout,
943 60 * hz, comdiag, sc);
944 }
945 #endif
946 if (ISSET(sts, (RXSts_FE|RXSts_BE)))
947 SET(code, TTY_FE);
948 if (ISSET(sts, RXSts_PE))
949 SET(code, TTY_PE);
950 }
951 if ((*rint)(code, tp) == -1) {
952 /*
953 * The line discipline's buffer is out of space.
954 */
955 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
956 /*
957 * We're either not using flow control, or the
958 * line discipline didn't tell us to block for
959 * some reason. Either way, we have no way to
960 * know when there's more space available, so
961 * just drop the rest of the data.
962 */
963 get += cc << 1;
964 if (get >= end)
965 get -= EPCOM_RING_SIZE << 1;
966 cc = 0;
967 } else {
968 /*
969 * Don't schedule any more receive processing
970 * until the line discipline tells us there's
971 * space available (through comhwiflow()).
972 * Leave the rest of the data in the input
973 * buffer.
974 */
975 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
976 }
977 break;
978 }
979 get += 2;
980 if (get >= end)
981 get = sc->sc_rbuf;
982 cc--;
983 }
984
985 if (cc != scc) {
986 sc->sc_rbget = get;
987 s = splserial();
988
989 cc = sc->sc_rbavail += scc - cc;
990 /* Buffers should be ok again, release possible block. */
991 if (cc >= 1) {
992 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
993 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
994 SET(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE));
995 epcom_set(sc);
996 }
997 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
998 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
999 #if 0
1000 com_hwiflow(sc);
1001 #endif
1002 }
1003 }
1004 splx(s);
1005 }
1006 }
1007
1008 static void
epcomsoft(void * arg)1009 epcomsoft(void* arg)
1010 {
1011 struct epcom_softc *sc = arg;
1012
1013 if (COM_ISALIVE(sc) == 0)
1014 return;
1015
1016 if (sc->sc_rx_ready) {
1017 sc->sc_rx_ready = 0;
1018 epcom_rxsoft(sc, sc->sc_tty);
1019 }
1020 if (sc->sc_tx_done) {
1021 sc->sc_tx_done = 0;
1022 epcom_txsoft(sc, sc->sc_tty);
1023 }
1024 }
1025
1026 int
epcomintr(void * arg)1027 epcomintr(void* arg)
1028 {
1029 struct epcom_softc *sc = arg;
1030 bus_space_tag_t iot = sc->sc_iot;
1031 bus_space_handle_t ioh = sc->sc_ioh;
1032 u_char *put, *end;
1033 u_int cc;
1034 u_int flagr;
1035 uint32_t c, csts;
1036
1037 (void) bus_space_read_4(iot, ioh, EPCOM_IntIDIntClr);
1038
1039 if (COM_ISALIVE(sc) == 0)
1040 panic("intr on disabled epcom");
1041
1042 flagr = bus_space_read_4(iot, ioh, EPCOM_Flag);
1043
1044 end = sc->sc_ebuf;
1045 put = sc->sc_rbput;
1046 cc = sc->sc_rbavail;
1047
1048 if (!(ISSET(flagr, Flag_RXFE))) {
1049 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1050 while (cc > 0) {
1051 if (ISSET(flagr, Flag_RXFE))
1052 break;
1053 c = bus_space_read_4(iot, ioh, EPCOM_Data);
1054 csts = bus_space_read_4(iot, ioh, EPCOM_RXSts);
1055 if (ISSET(csts, RXSts_BE)) {
1056 int cn_trapped = 0;
1057
1058 cn_check_magic(sc->sc_tty->t_dev,
1059 CNC_BREAK, epcom_cnm_state);
1060 if (cn_trapped)
1061 goto next;
1062 #if defined(KGDB) && !defined(DDB)
1063 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)){
1064 kgdb_connect(1);
1065 goto next;
1066 }
1067 #endif
1068 } else {
1069 int cn_trapped = 0;
1070
1071 cn_check_magic(sc->sc_tty->t_dev,
1072 (c & 0xff), epcom_cnm_state);
1073 if (cn_trapped)
1074 goto next;
1075 }
1076
1077
1078 put[0] = c & 0xff;
1079 put[1] = csts & 0xf;
1080 put += 2;
1081 if (put >= end)
1082 put = sc->sc_rbuf;
1083 cc--;
1084 next:
1085 flagr = bus_space_read_4(iot, ioh, EPCOM_Flag);
1086 }
1087
1088 /*
1089 * Current string of incoming characters ended because
1090 * no more data was available or we ran out of space.
1091 * Schedule a receive event if any data was received.
1092 * If we're out of space, turn off receive interrupts.
1093 */
1094 sc->sc_rbput = put;
1095 sc->sc_rbavail = cc;
1096 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1097 sc->sc_rx_ready = 1;
1098
1099 /*
1100 * See if we are in danger of overflowing a buffer. If
1101 * so, use hardware flow control to ease the pressure.
1102 */
1103
1104 /* but epcom cannot. X-( */
1105
1106 /*
1107 * If we're out of space, disable receive interrupts
1108 * until the queue has drained a bit.
1109 */
1110 if (!cc) {
1111 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1112 CLR(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE));
1113 epcom_set(sc);
1114 }
1115 } else {
1116 #ifdef DIAGNOSTIC
1117 panic("epcomintr: we shouldn't reach here");
1118 #endif
1119 CLR(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE));
1120 epcom_set(sc);
1121 }
1122 }
1123
1124 /*
1125 * Done handling any receive interrupts. See if data can be
1126 * transmitted as well. Schedule tx done event if no data left
1127 * and tty was marked busy.
1128 */
1129
1130 if (!ISSET(flagr, Flag_TXFF) && sc->sc_tbc > 0) {
1131 /* Output the next chunk of the contiguous buffer, if any. */
1132 epcom_filltx(sc);
1133 } else {
1134 /* Disable transmit completion interrupts if necessary. */
1135 if (ISSET(sc->sc_ctrl, Ctrl_TIE)) {
1136 CLR(sc->sc_ctrl, Ctrl_TIE);
1137 epcom_set(sc);
1138 }
1139 if (sc->sc_tx_busy) {
1140 sc->sc_tx_busy = 0;
1141 sc->sc_tx_done = 1;
1142 }
1143 }
1144
1145 /* Wake up the poller. */
1146 softint_schedule(sc->sc_si);
1147
1148 #if 0 /* XXX: broken */
1149 #ifdef RND_COM
1150 rnd_add_uint32(&sc->rnd_source, intr ^ flagr);
1151 #endif
1152 #endif
1153 return (1);
1154 }
1155
1156 #ifdef KGDB
1157 int
epcom_kgdb_attach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)1158 epcom_kgdb_attach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
1159 tcflag_t cflag)
1160 {
1161 bus_space_handle_t ioh;
1162
1163 if (iot == epcomcn_sc.sc_iot && iobase == epcomcn_sc.sc_hwbase) {
1164 #if !defined(DDB)
1165 return EBUSY; /* cannot share with console */
1166 #else
1167 /*
1168 * XXX I have no intention of ever testing and code path
1169 * implied by getting here
1170 */
1171 kgdb_sc = epcomcn_sc;
1172 #endif
1173 } else {
1174 bus_space_map(iot, iobase, EP93XX_APB_UART_SIZE, 0, &ioh);
1175 epcominit(&kgdb_sc, iot, iobase, ioh, rate, cflag);
1176 }
1177
1178 kgdb_attach(epcom_kgdb_getc, epcom_kgdb_putc, &kgdb_sc);
1179 kgdb_dev = 123; /* unneeded, only to satisfy some tests */
1180
1181 return 0;
1182 }
1183
1184 static int
epcom_kgdb_getc(void * sc)1185 epcom_kgdb_getc (void *sc)
1186 {
1187 return epcom_common_getc(sc, NODEV);
1188 }
1189
1190 static void
epcom_kgdb_putc(void * sc,int c)1191 epcom_kgdb_putc (void *sc, int c)
1192 {
1193 epcom_common_putc(sc, c);
1194 }
1195 #endif /* KGDB */
1196
1197 /*
1198 * Common code used for initialisation of the console or KGDB connection
1199 */
1200 static void
epcominit(struct epcom_cons_softc * sc,bus_space_tag_t iot,bus_addr_t iobase,bus_space_handle_t ioh,int rate,tcflag_t cflag)1201 epcominit(struct epcom_cons_softc *sc, bus_space_tag_t iot,
1202 bus_addr_t iobase, bus_space_handle_t ioh, int rate, tcflag_t cflag)
1203 {
1204 u_int lcrlo, lcrmid, lcrhi, ctrl, pwrcnt;
1205 bus_space_handle_t syscon_ioh;
1206
1207 sc->sc_iot = iot;
1208 sc->sc_ioh = ioh;
1209 sc->sc_hwbase = iobase;
1210 sc->sc_ospeed = rate;
1211 sc->sc_cflag = cflag;
1212
1213 lcrhi = cflag2lcrhi(cflag);
1214 lcrlo = EPCOMSPEED2BRD(rate) & 0xff;
1215 lcrmid = EPCOMSPEED2BRD(rate) >> 8;
1216 ctrl = Ctrl_UARTE;
1217
1218 /* Make sure the UARTs are clocked at the system default rate */
1219 bus_space_map(iot, EP93XX_APB_HWBASE + EP93XX_APB_SYSCON,
1220 EP93XX_APB_SYSCON_SIZE, 0, &syscon_ioh);
1221 pwrcnt = bus_space_read_4(iot, syscon_ioh, EP93XX_SYSCON_PwrCnt);
1222 pwrcnt &= ~(PwrCnt_UARTBAUD);
1223 bus_space_write_4(iot, syscon_ioh, EP93XX_SYSCON_PwrCnt, pwrcnt);
1224 bus_space_unmap(iot, syscon_ioh, EP93XX_APB_SYSCON_SIZE);
1225
1226 bus_space_write_4(iot, ioh, EPCOM_LinCtrlLow, lcrlo);
1227 bus_space_write_4(iot, ioh, EPCOM_LinCtrlMid, lcrmid);
1228 bus_space_write_4(iot, ioh, EPCOM_LinCtrlHigh, lcrhi);
1229 bus_space_write_4(iot, ioh, EPCOM_Ctrl, ctrl);
1230 }
1231