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