Annotation of sys/arch/arm/s3c2xx0/sscom.c, Revision 1.1.1.1
1.1 nbrk 1: /* $NetBSD: sscom.c,v 1.27 2007/11/27 22:00:59 ad Exp $ */
2:
3: /*
4: * Copyright (c) 2002, 2003 Fujitsu Component Limited
5: * Copyright (c) 2002, 2003 Genetec Corporation
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of The Fujitsu Component Limited nor the name of
17: * Genetec corporation may not be used to endorse or promote products
18: * derived from this software without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
21: * CORPORATION ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24: * DISCLAIMED. IN NO EVENT SHALL FUJITSU COMPONENT LIMITED OR GENETEC
25: * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
35: /*-
36: * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
37: * All rights reserved.
38: *
39: * This code is derived from software contributed to The NetBSD Foundation
40: * by Charles M. Hannum.
41: *
42: * Redistribution and use in source and binary forms, with or without
43: * modification, are permitted provided that the following conditions
44: * are met:
45: * 1. Redistributions of source code must retain the above copyright
46: * notice, this list of conditions and the following disclaimer.
47: * 2. Redistributions in binary form must reproduce the above copyright
48: * notice, this list of conditions and the following disclaimer in the
49: * documentation and/or other materials provided with the distribution.
50: * 3. All advertising materials mentioning features or use of this software
51: * must display the following acknowledgement:
52: * This product includes software developed by the NetBSD
53: * Foundation, Inc. and its contributors.
54: * 4. Neither the name of The NetBSD Foundation nor the names of its
55: * contributors may be used to endorse or promote products derived
56: * from this software without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
59: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
60: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
61: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
62: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
63: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
64: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
65: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
66: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
67: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
68: * POSSIBILITY OF SUCH DAMAGE.
69: */
70:
71: /*
72: * Copyright (c) 1991 The Regents of the University of California.
73: * All rights reserved.
74: *
75: * Redistribution and use in source and binary forms, with or without
76: * modification, are permitted provided that the following conditions
77: * are met:
78: * 1. Redistributions of source code must retain the above copyright
79: * notice, this list of conditions and the following disclaimer.
80: * 2. Redistributions in binary form must reproduce the above copyright
81: * notice, this list of conditions and the following disclaimer in the
82: * documentation and/or other materials provided with the distribution.
83: * 3. Neither the name of the University nor the names of its contributors
84: * may be used to endorse or promote products derived from this software
85: * without specific prior written permission.
86: *
87: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
88: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
91: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
92: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
93: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
94: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
95: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
96: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
97: * SUCH DAMAGE.
98: *
99: * @(#)com.c 7.5 (Berkeley) 5/16/91
100: */
101:
102: /*
103: * Support integrated UARTs of Samsung S3C2800/2400X/2410X
104: * Derived from sys/dev/ic/com.c
105: */
106:
107: #include <sys/cdefs.h>
108: __KERNEL_RCSID(0, "$NetBSD: sscom.c,v 1.27 2007/11/27 22:00:59 ad Exp $");
109:
110: #include "opt_sscom.h"
111: #include "opt_ddb.h"
112: #include "opt_kgdb.h"
113: #include "opt_multiprocessor.h"
114: #include "opt_lockdebug.h"
115:
116: #include "rnd.h"
117: #if NRND > 0 && defined(RND_COM)
118: #include <sys/rnd.h>
119: #endif
120:
121: /*
122: * Override cnmagic(9) macro before including <sys/systm.h>.
123: * We need to know if cn_check_magic triggered debugger, so set a flag.
124: * Callers of cn_check_magic must declare int cn_trapped = 0;
125: * XXX: this is *ugly*!
126: */
127: #define cn_trap() \
128: do { \
129: console_debugger(); \
130: cn_trapped = 1; \
131: } while (/* CONSTCOND */ 0)
132:
133: #include <sys/param.h>
134: #include <sys/systm.h>
135: #include <sys/ioctl.h>
136: #include <sys/select.h>
137: #include <sys/tty.h>
138: #include <sys/proc.h>
139: #include <sys/user.h>
140: #include <sys/conf.h>
141: #include <sys/file.h>
142: #include <sys/uio.h>
143: #include <sys/kernel.h>
144: #include <sys/syslog.h>
145: #include <sys/types.h>
146: #include <sys/device.h>
147: #include <sys/malloc.h>
148: #include <sys/timepps.h>
149: #include <sys/vnode.h>
150: #include <sys/kauth.h>
151: #include <sys/intr.h>
152: #include <sys/bus.h>
153:
154: #include <arm/s3c2xx0/s3c2xx0reg.h>
155: #include <arm/s3c2xx0/s3c2xx0var.h>
156: #if defined(SSCOM_S3C2410) || defined(SSCOM_S3C2400)
157: #include <arm/s3c2xx0/s3c24x0reg.h>
158: #elif defined(SSCOM_S3C2800)
159: #include <arm/s3c2xx0/s3c2800reg.h>
160: #endif
161: #include <arm/s3c2xx0/sscom_var.h>
162: #include <dev/cons.h>
163:
164: dev_type_open(sscomopen);
165: dev_type_close(sscomclose);
166: dev_type_read(sscomread);
167: dev_type_write(sscomwrite);
168: dev_type_ioctl(sscomioctl);
169: dev_type_stop(sscomstop);
170: dev_type_tty(sscomtty);
171: dev_type_poll(sscompoll);
172:
173: int sscomcngetc (dev_t);
174: void sscomcnputc (dev_t, int);
175: void sscomcnpollc (dev_t, int);
176:
177: #define integrate static inline
178: void sscomsoft (void *);
179:
180: integrate void sscom_rxsoft (struct sscom_softc *, struct tty *);
181: integrate void sscom_txsoft (struct sscom_softc *, struct tty *);
182: integrate void sscom_stsoft (struct sscom_softc *, struct tty *);
183: integrate void sscom_schedrx (struct sscom_softc *);
184: static void sscom_modem(struct sscom_softc *, int);
185: static void sscom_break(struct sscom_softc *, int);
186: static void sscom_iflush(struct sscom_softc *);
187: static void sscom_hwiflow(struct sscom_softc *);
188: static void sscom_loadchannelregs(struct sscom_softc *);
189: static void tiocm_to_sscom(struct sscom_softc *, u_long, int);
190: static int sscom_to_tiocm(struct sscom_softc *);
191: static void tiocm_to_sscom(struct sscom_softc *, u_long, int);
192: static int sscom_to_tiocm(struct sscom_softc *);
193: static void sscom_iflush(struct sscom_softc *);
194:
195: static int sscomhwiflow(struct tty *tp, int block);
196: static int sscom_init(bus_space_tag_t, const struct sscom_uart_info *,
197: int, int, tcflag_t, bus_space_handle_t *);
198:
199: extern struct cfdriver sscom_cd;
200:
201: const struct cdevsw sscom_cdevsw = {
202: sscomopen, sscomclose, sscomread, sscomwrite, sscomioctl,
203: sscomstop, sscomtty, sscompoll, nommap, ttykqfilter, D_TTY
204: };
205:
206: /*
207: * Make this an option variable one can patch.
208: * But be warned: this must be a power of 2!
209: */
210: u_int sscom_rbuf_size = SSCOM_RING_SIZE;
211:
212: /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
213: u_int sscom_rbuf_hiwat = (SSCOM_RING_SIZE * 1) / 4;
214: u_int sscom_rbuf_lowat = (SSCOM_RING_SIZE * 3) / 4;
215:
216: static int sscomconsunit = -1;
217: static bus_space_tag_t sscomconstag;
218: static bus_space_handle_t sscomconsioh;
219: static int sscomconsattached;
220: static int sscomconsrate;
221: static tcflag_t sscomconscflag;
222: static struct cnm_state sscom_cnm_state;
223:
224: #ifdef KGDB
225: #include <sys/kgdb.h>
226:
227: static int sscom_kgdb_unit = -1;
228: static bus_space_tag_t sscom_kgdb_iot;
229: static bus_space_handle_t sscom_kgdb_ioh;
230: static int sscom_kgdb_attached;
231:
232: int sscom_kgdb_getc (void *);
233: void sscom_kgdb_putc (void *, int);
234: #endif /* KGDB */
235:
236: #define SSCOMUNIT_MASK 0x7f
237: #define SSCOMDIALOUT_MASK 0x80
238:
239: #define SSCOMUNIT(x) (minor(x) & SSCOMUNIT_MASK)
240: #define SSCOMDIALOUT(x) (minor(x) & SSCOMDIALOUT_MASK)
241:
242: #if 0
243: #define SSCOM_ISALIVE(sc) ((sc)->enabled != 0 && \
244: device_is_active(&(sc)->sc_dev))
245: #else
246: #define SSCOM_ISALIVE(sc) device_is_active(&(sc)->sc_dev)
247: #endif
248:
249: #define BR BUS_SPACE_BARRIER_READ
250: #define BW BUS_SPACE_BARRIER_WRITE
251: #define SSCOM_BARRIER(t, h, f) /* no-op */
252:
253: #if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && defined(SSCOM_MPLOCK)
254:
255: #define SSCOM_LOCK(sc) simple_lock(&(sc)->sc_lock)
256: #define SSCOM_UNLOCK(sc) simple_unlock(&(sc)->sc_lock)
257:
258: #else
259:
260: #define SSCOM_LOCK(sc)
261: #define SSCOM_UNLOCK(sc)
262:
263: #endif
264:
265: #ifndef SSCOM_TOLERANCE
266: #define SSCOM_TOLERANCE 30 /* XXX: baud rate tolerance, in 0.1% units */
267: #endif
268:
269: /* value for UCON */
270: #define UCON_RXINT_MASK \
271: (UCON_RXMODE_MASK|UCON_ERRINT|UCON_TOINT|UCON_RXINT_TYPE)
272: #define UCON_RXINT_ENABLE \
273: (UCON_RXMODE_INT|UCON_ERRINT|UCON_TOINT|UCON_RXINT_TYPE_LEVEL)
274: #define UCON_TXINT_MASK (UCON_TXMODE_MASK|UCON_TXINT_TYPE)
275: #define UCON_TXINT_ENABLE (UCON_TXMODE_INT|UCON_TXINT_TYPE_LEVEL)
276:
277: /* we don't want tx interrupt on debug port, but it is needed to
278: have transmitter active */
279: #define UCON_DEBUGPORT (UCON_RXINT_ENABLE|UCON_TXINT_ENABLE)
280:
281:
282: static inline void
283: __sscom_output_chunk(struct sscom_softc *sc, int ufstat)
284: {
285: int n, space;
286: bus_space_tag_t iot = sc->sc_iot;
287: bus_space_handle_t ioh = sc->sc_ioh;
288:
289: n = sc->sc_tbc;
290: space = 16 - ((ufstat & UFSTAT_TXCOUNT) >> UFSTAT_TXCOUNT_SHIFT);
291:
292: if (n > space)
293: n = space;
294:
295: if (n > 0) {
296: bus_space_write_multi_1(iot, ioh, SSCOM_UTXH, sc->sc_tba, n);
297: sc->sc_tbc -= n;
298: sc->sc_tba += n;
299: }
300: }
301:
302: static void
303: sscom_output_chunk(struct sscom_softc *sc)
304: {
305: int ufstat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSCOM_UFSTAT);
306:
307: if (!(ufstat & UFSTAT_TXFULL))
308: __sscom_output_chunk(sc, ufstat);
309: }
310:
311: int
312: sscomspeed(long speed, long frequency)
313: {
314: #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
315:
316: int x, err;
317:
318: if (speed <= 0)
319: return -1;
320: x = divrnd(frequency / 16, speed);
321: if (x <= 0)
322: return -1;
323: err = divrnd(((quad_t)frequency) * 1000 / 16, speed * x) - 1000;
324: if (err < 0)
325: err = -err;
326: if (err > SSCOM_TOLERANCE)
327: return -1;
328: return x-1;
329:
330: #undef divrnd
331: }
332:
333: void sscomstatus (struct sscom_softc *, const char *);
334:
335: #ifdef SSCOM_DEBUG
336: int sscom_debug = 0;
337:
338: void
339: sscomstatus(struct sscom_softc *sc, const char *str)
340: {
341: struct tty *tp = sc->sc_tty;
342: int umstat = bus_space_read_1(sc->sc_iot, sc->sc_iot, SSCOM_UMSTAT);
343: int umcon = bus_space_read_1(sc->sc_iot, sc->sc_iot, SSCOM_UMCON);
344:
345: printf("%s: %s %sclocal %sdcd %sts_carr_on %sdtr %stx_stopped\n",
346: sc->sc_dev.dv_xname, str,
347: ISSET(tp->t_cflag, CLOCAL) ? "+" : "-",
348: "+", /* DCD */
349: ISSET(tp->t_state, TS_CARR_ON) ? "+" : "-",
350: "+", /* DTR */
351: sc->sc_tx_stopped ? "+" : "-");
352:
353: printf("%s: %s %scrtscts %scts %sts_ttstop %srts %xrx_flags\n",
354: sc->sc_dev.dv_xname, str,
355: ISSET(tp->t_cflag, CRTSCTS) ? "+" : "-",
356: ISSET(umstat, UMSTAT_CTS) ? "+" : "-",
357: ISSET(tp->t_state, TS_TTSTOP) ? "+" : "-",
358: ISSET(umcon, UMCON_RTS) ? "+" : "-",
359: sc->sc_rx_flags);
360: }
361: #else
362: #define sscom_debug 0
363: #endif
364:
365: static void
366: sscom_enable_debugport(struct sscom_softc *sc)
367: {
368: int s;
369:
370: /* Turn on line break interrupt, set carrier. */
371: s = splserial();
372: SSCOM_LOCK(sc);
373: sc->sc_ucon = UCON_DEBUGPORT;
374: bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
375: sc->sc_umcon = UMCON_RTS|UMCON_DTR;
376: sc->set_modem_control(sc);
377: sscom_enable_rxint(sc);
378: sscom_disable_txint(sc);
379: SSCOM_UNLOCK(sc);
380: splx(s);
381: }
382:
383: static void
384: sscom_set_modem_control(struct sscom_softc *sc)
385: {
386: /* flob RTS */
387: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
388: SSCOM_UMCON, sc->sc_umcon & UMCON_HW_MASK);
389: /* ignore DTR */
390: }
391:
392: static int
393: sscom_read_modem_status(struct sscom_softc *sc)
394: {
395: int msts;
396:
397: msts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SSCOM_UMSTAT);
398:
399: /* DCD and DSR are always on */
400: return (msts & UMSTAT_CTS) | MSTS_DCD | MSTS_DSR;
401: }
402:
403: void
404: sscom_attach_subr(struct sscom_softc *sc)
405: {
406: int unit = sc->sc_unit;
407: bus_space_tag_t iot = sc->sc_iot;
408: bus_space_handle_t ioh = sc->sc_ioh;
409: struct tty *tp;
410:
411: callout_init(&sc->sc_diag_callout, 0);
412: #if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && defined(SSCOM_MPLOCK)
413: simple_lock_init(&sc->sc_lock);
414: #endif
415:
416: sc->sc_ucon = UCON_RXINT_ENABLE|UCON_TXINT_ENABLE;
417:
418: /*
419: * set default for modem control hook
420: */
421: if (sc->set_modem_control == NULL)
422: sc->set_modem_control = sscom_set_modem_control;
423: if (sc->read_modem_status == NULL)
424: sc->read_modem_status = sscom_read_modem_status;
425:
426: /* Disable interrupts before configuring the device. */
427: sscom_disable_txrxint(sc);
428:
429: #ifdef KGDB
430: /*
431: * Allow kgdb to "take over" this port. If this is
432: * the kgdb device, it has exclusive use.
433: */
434: if (unit == sscom_kgdb_unit) {
435: SET(sc->sc_hwflags, SSCOM_HW_KGDB);
436: sc->sc_ucon = UCON_DEBUGPORT;
437: }
438: #endif
439:
440: if (unit == sscomconsunit) {
441: sscomconsattached = 1;
442:
443: sscomconstag = iot;
444: sscomconsioh = ioh;
445:
446: /* Make sure the console is always "hardwired". */
447: delay(1000); /* XXX: wait for output to finish */
448: SET(sc->sc_hwflags, SSCOM_HW_CONSOLE);
449: SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
450:
451: sc->sc_ucon = UCON_DEBUGPORT;
452: }
453:
454: bus_space_write_1(iot, ioh, SSCOM_UFCON,
455: UFCON_TXTRIGGER_8|UFCON_RXTRIGGER_8|UFCON_FIFO_ENABLE|
456: UFCON_TXFIFO_RESET|UFCON_RXFIFO_RESET);
457:
458: bus_space_write_1(iot, ioh, SSCOM_UCON, sc->sc_ucon);
459:
460: #ifdef KGDB
461: if (ISSET(sc->sc_hwflags, SSCOM_HW_KGDB)) {
462: sscom_kgdb_attached = 1;
463: printf("%s: kgdb\n", sc->sc_dev.dv_xname);
464: sscom_enable_debugport(sc);
465: return;
466: }
467: #endif
468:
469:
470:
471: tp = ttymalloc();
472: tp->t_oproc = sscomstart;
473: tp->t_param = sscomparam;
474: tp->t_hwiflow = sscomhwiflow;
475:
476: sc->sc_tty = tp;
477: sc->sc_rbuf = malloc(sscom_rbuf_size << 1, M_DEVBUF, M_NOWAIT);
478: sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
479: sc->sc_rbavail = sscom_rbuf_size;
480: if (sc->sc_rbuf == NULL) {
481: printf("%s: unable to allocate ring buffer\n",
482: sc->sc_dev.dv_xname);
483: return;
484: }
485: sc->sc_ebuf = sc->sc_rbuf + (sscom_rbuf_size << 1);
486:
487: tty_attach(tp);
488:
489: if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE)) {
490: int maj;
491:
492: /* locate the major number */
493: maj = cdevsw_lookup_major(&sscom_cdevsw);
494:
495: cn_tab->cn_dev = makedev(maj, device_unit(&sc->sc_dev));
496:
497: printf("%s: console (major=%d)\n", sc->sc_dev.dv_xname, maj);
498: }
499:
500:
501: sc->sc_si = softint_establish(SOFTINT_SERIAL, sscomsoft, sc);
502:
503: #if NRND > 0 && defined(RND_COM)
504: rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
505: RND_TYPE_TTY, 0);
506: #endif
507:
508: /* if there are no enable/disable functions, assume the device
509: is always enabled */
510:
511: if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE))
512: sscom_enable_debugport(sc);
513: else
514: sscom_disable_txrxint(sc);
515:
516: SET(sc->sc_hwflags, SSCOM_HW_DEV_OK);
517: }
518:
519: int
520: sscom_detach(struct device *self, int flags)
521: {
522: return 0;
523: }
524:
525: int
526: sscom_activate(struct device *self, enum devact act)
527: {
528: #ifdef notyet
529: struct sscom_softc *sc = (struct sscom_softc *)self;
530: int s, rv = 0;
531:
532: s = splserial();
533: SSCOM_LOCK(sc);
534: switch (act) {
535: case DVACT_ACTIVATE:
536: rv = EOPNOTSUPP;
537: break;
538:
539: case DVACT_DEACTIVATE:
540: if (sc->sc_hwflags & (SSCOM_HW_CONSOLE|SSCOM_HW_KGDB)) {
541: rv = EBUSY;
542: break;
543: }
544:
545: sc->enabled = 0;
546: break;
547: }
548:
549: SSCOM_UNLOCK(sc);
550: splx(s);
551: return rv;
552: #else
553: return 0;
554: #endif
555: }
556:
557: void
558: sscom_shutdown(struct sscom_softc *sc)
559: {
560: #ifdef notyet
561: struct tty *tp = sc->sc_tty;
562: int s;
563:
564: s = splserial();
565: SSCOM_LOCK(sc);
566:
567: /* If we were asserting flow control, then deassert it. */
568: SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
569: sscom_hwiflow(sc);
570:
571: /* Clear any break condition set with TIOCSBRK. */
572: sscom_break(sc, 0);
573:
574: /*
575: * Hang up if necessary. Wait a bit, so the other side has time to
576: * notice even if we immediately open the port again.
577: * Avoid tsleeping above splhigh().
578: */
579: if (ISSET(tp->t_cflag, HUPCL)) {
580: sscom_modem(sc, 0);
581: SSCOM_UNLOCK(sc);
582: splx(s);
583: /* XXX tsleep will only timeout */
584: (void) tsleep(sc, TTIPRI, ttclos, hz);
585: s = splserial();
586: SSCOM_LOCK(sc);
587: }
588:
589: if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE))
590: /* interrupt on break */
591: sc->sc_ucon = UCON_DEBUGPORT;
592: else
593: sc->sc_ucon = 0;
594: bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
595:
596: #ifdef DIAGNOSTIC
597: if (!sc->enabled)
598: panic("sscom_shutdown: not enabled?");
599: #endif
600: sc->enabled = 0;
601: SSCOM_UNLOCK(sc);
602: splx(s);
603: #endif
604: }
605:
606: int
607: sscomopen(dev_t dev, int flag, int mode, struct lwp *l)
608: {
609: struct sscom_softc *sc;
610: struct tty *tp;
611: int s, s2;
612: int error;
613:
614: sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
615: if (sc == NULL || !ISSET(sc->sc_hwflags, SSCOM_HW_DEV_OK) ||
616: sc->sc_rbuf == NULL)
617: return ENXIO;
618:
619: if (!device_is_active(&sc->sc_dev))
620: return ENXIO;
621:
622: #ifdef KGDB
623: /*
624: * If this is the kgdb port, no other use is permitted.
625: */
626: if (ISSET(sc->sc_hwflags, SSCOM_HW_KGDB))
627: return EBUSY;
628: #endif
629:
630: tp = sc->sc_tty;
631:
632: if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
633: return (EBUSY);
634:
635: s = spltty();
636:
637: /*
638: * Do the following iff this is a first open.
639: */
640: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
641: struct termios t;
642:
643: tp->t_dev = dev;
644:
645: s2 = splserial();
646: SSCOM_LOCK(sc);
647:
648: /* Turn on interrupts. */
649: sscom_enable_txrxint(sc);
650:
651: /* Fetch the current modem control status, needed later. */
652: sc->sc_msts = sc->read_modem_status(sc);
653:
654: #if 0
655: /* Clear PPS capture state on first open. */
656: sc->sc_ppsmask = 0;
657: sc->ppsparam.mode = 0;
658: #endif
659:
660: SSCOM_UNLOCK(sc);
661: splx(s2);
662:
663: /*
664: * Initialize the termios status to the defaults. Add in the
665: * sticky bits from TIOCSFLAGS.
666: */
667: t.c_ispeed = 0;
668: if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE)) {
669: t.c_ospeed = sscomconsrate;
670: t.c_cflag = sscomconscflag;
671: } else {
672: t.c_ospeed = TTYDEF_SPEED;
673: t.c_cflag = TTYDEF_CFLAG;
674: }
675: if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
676: SET(t.c_cflag, CLOCAL);
677: if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
678: SET(t.c_cflag, CRTSCTS);
679: if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
680: SET(t.c_cflag, MDMBUF);
681: /* Make sure sscomparam() will do something. */
682: tp->t_ospeed = 0;
683: (void) sscomparam(tp, &t);
684: tp->t_iflag = TTYDEF_IFLAG;
685: tp->t_oflag = TTYDEF_OFLAG;
686: tp->t_lflag = TTYDEF_LFLAG;
687: ttychars(tp);
688: ttsetwater(tp);
689:
690: s2 = splserial();
691: SSCOM_LOCK(sc);
692:
693: /*
694: * Turn on DTR. We must always do this, even if carrier is not
695: * present, because otherwise we'd have to use TIOCSDTR
696: * immediately after setting CLOCAL, which applications do not
697: * expect. We always assert DTR while the device is open
698: * unless explicitly requested to deassert it.
699: */
700: sscom_modem(sc, 1);
701:
702: /* Clear the input ring, and unblock. */
703: sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
704: sc->sc_rbavail = sscom_rbuf_size;
705: sscom_iflush(sc);
706: CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
707: sscom_hwiflow(sc);
708:
709: if (sscom_debug)
710: sscomstatus(sc, "sscomopen ");
711:
712: SSCOM_UNLOCK(sc);
713: splx(s2);
714: }
715:
716: splx(s);
717:
718: error = ttyopen(tp, SSCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
719: if (error)
720: goto bad;
721:
722: error = (*tp->t_linesw->l_open)(dev, tp);
723: if (error)
724: goto bad;
725:
726: return 0;
727:
728: bad:
729: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
730: /*
731: * We failed to open the device, and nobody else had it opened.
732: * Clean up the state as appropriate.
733: */
734: sscom_shutdown(sc);
735: }
736:
737: return error;
738: }
739:
740: int
741: sscomclose(dev_t dev, int flag, int mode, struct lwp *l)
742: {
743: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
744: struct tty *tp = sc->sc_tty;
745:
746: /* XXX This is for cons.c. */
747: if (!ISSET(tp->t_state, TS_ISOPEN))
748: return 0;
749:
750: (*tp->t_linesw->l_close)(tp, flag);
751: ttyclose(tp);
752:
753: if (SSCOM_ISALIVE(sc) == 0)
754: return 0;
755:
756: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
757: /*
758: * Although we got a last close, the device may still be in
759: * use; e.g. if this was the dialout node, and there are still
760: * processes waiting for carrier on the non-dialout node.
761: */
762: sscom_shutdown(sc);
763: }
764:
765: return 0;
766: }
767:
768: int
769: sscomread(dev_t dev, struct uio *uio, int flag)
770: {
771: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
772: struct tty *tp = sc->sc_tty;
773:
774: if (SSCOM_ISALIVE(sc) == 0)
775: return EIO;
776:
777: return (*tp->t_linesw->l_read)(tp, uio, flag);
778: }
779:
780: int
781: sscomwrite(dev_t dev, struct uio *uio, int flag)
782: {
783: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
784: struct tty *tp = sc->sc_tty;
785:
786: if (SSCOM_ISALIVE(sc) == 0)
787: return EIO;
788:
789: return (*tp->t_linesw->l_write)(tp, uio, flag);
790: }
791:
792: int
793: sscompoll(dev_t dev, int events, struct lwp *l)
794: {
795: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
796: struct tty *tp = sc->sc_tty;
797:
798: if (SSCOM_ISALIVE(sc) == 0)
799: return EIO;
800:
801: return (*tp->t_linesw->l_poll)(tp, events, l);
802: }
803:
804: struct tty *
805: sscomtty(dev_t dev)
806: {
807: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
808: struct tty *tp = sc->sc_tty;
809:
810: return tp;
811: }
812:
813: int
814: sscomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
815: {
816: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(dev));
817: struct tty *tp = sc->sc_tty;
818: int error;
819: int s;
820:
821: if (SSCOM_ISALIVE(sc) == 0)
822: return EIO;
823:
824: error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
825: if (error != EPASSTHROUGH)
826: return error;
827:
828: error = ttioctl(tp, cmd, data, flag, l);
829: if (error != EPASSTHROUGH)
830: return error;
831:
832: error = 0;
833:
834: s = splserial();
835: SSCOM_LOCK(sc);
836:
837: switch (cmd) {
838: case TIOCSBRK:
839: sscom_break(sc, 1);
840: break;
841:
842: case TIOCCBRK:
843: sscom_break(sc, 0);
844: break;
845:
846: case TIOCSDTR:
847: sscom_modem(sc, 1);
848: break;
849:
850: case TIOCCDTR:
851: sscom_modem(sc, 0);
852: break;
853:
854: case TIOCGFLAGS:
855: *(int *)data = sc->sc_swflags;
856: break;
857:
858: case TIOCSFLAGS:
859: error = kauth_authorize_device_tty(l->l_cred,
860: KAUTH_DEVICE_TTY_PRIVSET, tp);
861: if (error)
862: break;
863: sc->sc_swflags = *(int *)data;
864: break;
865:
866: case TIOCMSET:
867: case TIOCMBIS:
868: case TIOCMBIC:
869: tiocm_to_sscom(sc, cmd, *(int *)data);
870: break;
871:
872: case TIOCMGET:
873: *(int *)data = sscom_to_tiocm(sc);
874: break;
875:
876: default:
877: error = EPASSTHROUGH;
878: break;
879: }
880:
881: SSCOM_UNLOCK(sc);
882: splx(s);
883:
884: if (sscom_debug)
885: sscomstatus(sc, "sscomioctl ");
886:
887: return error;
888: }
889:
890: integrate void
891: sscom_schedrx(struct sscom_softc *sc)
892: {
893:
894: sc->sc_rx_ready = 1;
895:
896: /* Wake up the poller. */
897: softint_schedule(sc->sc_si);
898: }
899:
900: static void
901: sscom_break(struct sscom_softc *sc, int onoff)
902: {
903:
904: if (onoff)
905: SET(sc->sc_ucon, UCON_SBREAK);
906: else
907: CLR(sc->sc_ucon, UCON_SBREAK);
908:
909: if (!sc->sc_heldchange) {
910: if (sc->sc_tx_busy) {
911: sc->sc_heldtbc = sc->sc_tbc;
912: sc->sc_tbc = 0;
913: sc->sc_heldchange = 1;
914: } else
915: sscom_loadchannelregs(sc);
916: }
917: }
918:
919: static void
920: sscom_modem(struct sscom_softc *sc, int onoff)
921: {
922: if (onoff)
923: SET(sc->sc_umcon, UMCON_DTR);
924: else
925: CLR(sc->sc_umcon, UMCON_DTR);
926:
927: if (!sc->sc_heldchange) {
928: if (sc->sc_tx_busy) {
929: sc->sc_heldtbc = sc->sc_tbc;
930: sc->sc_tbc = 0;
931: sc->sc_heldchange = 1;
932: } else
933: sscom_loadchannelregs(sc);
934: }
935: }
936:
937: static void
938: tiocm_to_sscom(struct sscom_softc *sc, u_long how, int ttybits)
939: {
940: u_char sscombits;
941:
942: sscombits = 0;
943: if (ISSET(ttybits, TIOCM_DTR))
944: sscombits = UMCON_DTR;
945: if (ISSET(ttybits, TIOCM_RTS))
946: SET(sscombits, UMCON_RTS);
947:
948: switch (how) {
949: case TIOCMBIC:
950: CLR(sc->sc_umcon, sscombits);
951: break;
952:
953: case TIOCMBIS:
954: SET(sc->sc_umcon, sscombits);
955: break;
956:
957: case TIOCMSET:
958: CLR(sc->sc_umcon, UMCON_DTR);
959: SET(sc->sc_umcon, sscombits);
960: break;
961: }
962:
963: if (!sc->sc_heldchange) {
964: if (sc->sc_tx_busy) {
965: sc->sc_heldtbc = sc->sc_tbc;
966: sc->sc_tbc = 0;
967: sc->sc_heldchange = 1;
968: } else
969: sscom_loadchannelregs(sc);
970: }
971: }
972:
973: static int
974: sscom_to_tiocm(struct sscom_softc *sc)
975: {
976: u_char sscombits;
977: int ttybits = 0;
978:
979: sscombits = sc->sc_umcon;
980: #if 0
981: if (ISSET(sscombits, MCR_DTR))
982: SET(ttybits, TIOCM_DTR);
983: #endif
984: if (ISSET(sscombits, UMCON_RTS))
985: SET(ttybits, TIOCM_RTS);
986:
987: sscombits = sc->sc_msts;
988: if (ISSET(sscombits, MSTS_DCD))
989: SET(ttybits, TIOCM_CD);
990: if (ISSET(sscombits, MSTS_DSR))
991: SET(ttybits, TIOCM_DSR);
992: if (ISSET(sscombits, MSTS_CTS))
993: SET(ttybits, TIOCM_CTS);
994:
995: if (sc->sc_ucon != 0)
996: SET(ttybits, TIOCM_LE);
997:
998: return ttybits;
999: }
1000:
1001: static int
1002: cflag2lcr(tcflag_t cflag)
1003: {
1004: u_char lcr = ULCON_PARITY_NONE;
1005:
1006: switch (cflag & (PARENB|PARODD)) {
1007: case PARENB|PARODD: lcr = ULCON_PARITY_ODD; break;
1008: case PARENB: lcr = ULCON_PARITY_EVEN;
1009: }
1010:
1011: switch (ISSET(cflag, CSIZE)) {
1012: case CS5:
1013: SET(lcr, ULCON_LENGTH_5);
1014: break;
1015: case CS6:
1016: SET(lcr, ULCON_LENGTH_6);
1017: break;
1018: case CS7:
1019: SET(lcr, ULCON_LENGTH_7);
1020: break;
1021: case CS8:
1022: SET(lcr, ULCON_LENGTH_8);
1023: break;
1024: }
1025: if (ISSET(cflag, CSTOPB))
1026: SET(lcr, ULCON_STOP);
1027:
1028: return lcr;
1029: }
1030:
1031: int
1032: sscomparam(struct tty *tp, struct termios *t)
1033: {
1034: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(tp->t_dev));
1035: int ospeed;
1036: u_char lcr;
1037: int s;
1038:
1039: if (SSCOM_ISALIVE(sc) == 0)
1040: return EIO;
1041:
1042: ospeed = sscomspeed(t->c_ospeed, sc->sc_frequency);
1043:
1044: /* Check requested parameters. */
1045: if (ospeed < 0)
1046: return EINVAL;
1047: if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
1048: return EINVAL;
1049:
1050: /*
1051: * For the console, always force CLOCAL and !HUPCL, so that the port
1052: * is always active.
1053: */
1054: if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
1055: ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE)) {
1056: SET(t->c_cflag, CLOCAL);
1057: CLR(t->c_cflag, HUPCL);
1058: }
1059:
1060: /*
1061: * If there were no changes, don't do anything. This avoids dropping
1062: * input and improves performance when all we did was frob things like
1063: * VMIN and VTIME.
1064: */
1065: if (tp->t_ospeed == t->c_ospeed &&
1066: tp->t_cflag == t->c_cflag)
1067: return 0;
1068:
1069: lcr = cflag2lcr(t->c_cflag);
1070:
1071: s = splserial();
1072: SSCOM_LOCK(sc);
1073:
1074: sc->sc_ulcon = lcr;
1075:
1076: /*
1077: * If we're not in a mode that assumes a connection is present, then
1078: * ignore carrier changes.
1079: */
1080: if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
1081: sc->sc_msr_dcd = 0;
1082: else
1083: sc->sc_msr_dcd = MSTS_DCD;
1084:
1085: /*
1086: * Set the flow control pins depending on the current flow control
1087: * mode.
1088: */
1089: if (ISSET(t->c_cflag, CRTSCTS)) {
1090: sc->sc_mcr_dtr = UMCON_DTR;
1091: sc->sc_mcr_rts = UMCON_RTS;
1092: sc->sc_msr_cts = MSTS_CTS;
1093: }
1094: else if (ISSET(t->c_cflag, MDMBUF)) {
1095: /*
1096: * For DTR/DCD flow control, make sure we don't toggle DTR for
1097: * carrier detection.
1098: */
1099: sc->sc_mcr_dtr = 0;
1100: sc->sc_mcr_rts = UMCON_DTR;
1101: sc->sc_msr_cts = MSTS_DCD;
1102: }
1103: else {
1104: /*
1105: * If no flow control, then always set RTS. This will make
1106: * the other side happy if it mistakenly thinks we're doing
1107: * RTS/CTS flow control.
1108: */
1109: sc->sc_mcr_dtr = UMCON_DTR | UMCON_RTS;
1110: sc->sc_mcr_rts = 0;
1111: sc->sc_msr_cts = 0;
1112: if (ISSET(sc->sc_umcon, UMCON_DTR))
1113: SET(sc->sc_umcon, UMCON_RTS);
1114: else
1115: CLR(sc->sc_umcon, UMCON_RTS);
1116: }
1117: sc->sc_msr_mask = sc->sc_msr_cts | sc->sc_msr_dcd;
1118:
1119: if (ospeed == 0)
1120: CLR(sc->sc_umcon, sc->sc_mcr_dtr);
1121: else
1122: SET(sc->sc_umcon, sc->sc_mcr_dtr);
1123:
1124: sc->sc_ubrdiv = ospeed;
1125:
1126: /* And copy to tty. */
1127: tp->t_ispeed = 0;
1128: tp->t_ospeed = t->c_ospeed;
1129: tp->t_cflag = t->c_cflag;
1130:
1131: if (!sc->sc_heldchange) {
1132: if (sc->sc_tx_busy) {
1133: sc->sc_heldtbc = sc->sc_tbc;
1134: sc->sc_tbc = 0;
1135: sc->sc_heldchange = 1;
1136: } else
1137: sscom_loadchannelregs(sc);
1138: }
1139:
1140: if (!ISSET(t->c_cflag, CHWFLOW)) {
1141: /* Disable the high water mark. */
1142: sc->sc_r_hiwat = 0;
1143: sc->sc_r_lowat = 0;
1144: if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
1145: CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1146: sscom_schedrx(sc);
1147: }
1148: if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
1149: CLR(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
1150: sscom_hwiflow(sc);
1151: }
1152: } else {
1153: sc->sc_r_hiwat = sscom_rbuf_hiwat;
1154: sc->sc_r_lowat = sscom_rbuf_lowat;
1155: }
1156:
1157: SSCOM_UNLOCK(sc);
1158: splx(s);
1159:
1160: /*
1161: * Update the tty layer's idea of the carrier bit, in case we changed
1162: * CLOCAL or MDMBUF. We don't hang up here; we only do that by
1163: * explicit request.
1164: */
1165: (void) (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msts, MSTS_DCD));
1166:
1167: if (sscom_debug)
1168: sscomstatus(sc, "sscomparam ");
1169:
1170: if (!ISSET(t->c_cflag, CHWFLOW)) {
1171: if (sc->sc_tx_stopped) {
1172: sc->sc_tx_stopped = 0;
1173: sscomstart(tp);
1174: }
1175: }
1176:
1177: return 0;
1178: }
1179:
1180: static void
1181: sscom_iflush(struct sscom_softc *sc)
1182: {
1183: bus_space_tag_t iot = sc->sc_iot;
1184: bus_space_handle_t ioh = sc->sc_ioh;
1185: int timo;
1186:
1187:
1188: timo = 50000;
1189: /* flush any pending I/O */
1190: while ( sscom_rxrdy(iot, ioh) && --timo)
1191: (void)sscom_getc(iot,ioh);
1192: #ifdef DIAGNOSTIC
1193: if (!timo)
1194: printf("%s: sscom_iflush timeout\n", sc->sc_dev.dv_xname);
1195: #endif
1196: }
1197:
1198: static void
1199: sscom_loadchannelregs(struct sscom_softc *sc)
1200: {
1201: bus_space_tag_t iot = sc->sc_iot;
1202: bus_space_handle_t ioh = sc->sc_ioh;
1203:
1204: /* XXXXX necessary? */
1205: sscom_iflush(sc);
1206:
1207: bus_space_write_2(iot, ioh, SSCOM_UCON, 0);
1208:
1209: #if 0
1210: if (ISSET(sc->sc_hwflags, COM_HW_FLOW)) {
1211: bus_space_write_1(iot, ioh, com_lcr, LCR_EERS);
1212: bus_space_write_1(iot, ioh, com_efr, sc->sc_efr);
1213: }
1214: #endif
1215:
1216: bus_space_write_2(iot, ioh, SSCOM_UBRDIV, sc->sc_ubrdiv);
1217: bus_space_write_1(iot, ioh, SSCOM_ULCON, sc->sc_ulcon);
1218: sc->set_modem_control(sc);
1219: bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
1220: }
1221:
1222: static int
1223: sscomhwiflow(struct tty *tp, int block)
1224: {
1225: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(tp->t_dev));
1226: int s;
1227:
1228: if (SSCOM_ISALIVE(sc) == 0)
1229: return 0;
1230:
1231: if (sc->sc_mcr_rts == 0)
1232: return 0;
1233:
1234: s = splserial();
1235: SSCOM_LOCK(sc);
1236:
1237: if (block) {
1238: if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1239: SET(sc->sc_rx_flags, RX_TTY_BLOCKED);
1240: sscom_hwiflow(sc);
1241: }
1242: } else {
1243: if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
1244: CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1245: sscom_schedrx(sc);
1246: }
1247: if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1248: CLR(sc->sc_rx_flags, RX_TTY_BLOCKED);
1249: sscom_hwiflow(sc);
1250: }
1251: }
1252:
1253: SSCOM_UNLOCK(sc);
1254: splx(s);
1255: return 1;
1256: }
1257:
1258: /*
1259: * (un)block input via hw flowcontrol
1260: */
1261: static void
1262: sscom_hwiflow(struct sscom_softc *sc)
1263: {
1264: if (sc->sc_mcr_rts == 0)
1265: return;
1266:
1267: if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
1268: CLR(sc->sc_umcon, sc->sc_mcr_rts);
1269: CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
1270: } else {
1271: SET(sc->sc_umcon, sc->sc_mcr_rts);
1272: SET(sc->sc_mcr_active, sc->sc_mcr_rts);
1273: }
1274: sc->set_modem_control(sc);
1275: }
1276:
1277:
1278: void
1279: sscomstart(struct tty *tp)
1280: {
1281: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(tp->t_dev));
1282: int s;
1283:
1284: if (SSCOM_ISALIVE(sc) == 0)
1285: return;
1286:
1287: s = spltty();
1288: if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
1289: goto out;
1290: if (sc->sc_tx_stopped)
1291: goto out;
1292: if (!ttypull(tp))
1293: goto out;
1294:
1295: /* Grab the first contiguous region of buffer space. */
1296: {
1297: u_char *tba;
1298: int tbc;
1299:
1300: tba = tp->t_outq.c_cf;
1301: tbc = ndqb(&tp->t_outq, 0);
1302:
1303: (void)splserial();
1304: SSCOM_LOCK(sc);
1305:
1306: sc->sc_tba = tba;
1307: sc->sc_tbc = tbc;
1308: }
1309:
1310: SET(tp->t_state, TS_BUSY);
1311: sc->sc_tx_busy = 1;
1312:
1313: /* Output the first chunk of the contiguous buffer. */
1314: sscom_output_chunk(sc);
1315:
1316: /* Enable transmit completion interrupts if necessary. */
1317: if ((sc->sc_hwflags & SSCOM_HW_TXINT) == 0)
1318: sscom_enable_txint(sc);
1319:
1320: SSCOM_UNLOCK(sc);
1321: out:
1322: splx(s);
1323: return;
1324: }
1325:
1326: /*
1327: * Stop output on a line.
1328: */
1329: void
1330: sscomstop(struct tty *tp, int flag)
1331: {
1332: struct sscom_softc *sc = device_lookup(&sscom_cd, SSCOMUNIT(tp->t_dev));
1333: int s;
1334:
1335: s = splserial();
1336: SSCOM_LOCK(sc);
1337: if (ISSET(tp->t_state, TS_BUSY)) {
1338: /* Stop transmitting at the next chunk. */
1339: sc->sc_tbc = 0;
1340: sc->sc_heldtbc = 0;
1341: if (!ISSET(tp->t_state, TS_TTSTOP))
1342: SET(tp->t_state, TS_FLUSH);
1343: }
1344: SSCOM_UNLOCK(sc);
1345: splx(s);
1346: }
1347:
1348: void
1349: sscomdiag(void *arg)
1350: {
1351: struct sscom_softc *sc = arg;
1352: int overflows, floods;
1353: int s;
1354:
1355: s = splserial();
1356: SSCOM_LOCK(sc);
1357: overflows = sc->sc_overflows;
1358: sc->sc_overflows = 0;
1359: floods = sc->sc_floods;
1360: sc->sc_floods = 0;
1361: sc->sc_errors = 0;
1362: SSCOM_UNLOCK(sc);
1363: splx(s);
1364:
1365: log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
1366: sc->sc_dev.dv_xname,
1367: overflows, overflows == 1 ? "" : "s",
1368: floods, floods == 1 ? "" : "s");
1369: }
1370:
1371: integrate void
1372: sscom_rxsoft(struct sscom_softc *sc, struct tty *tp)
1373: {
1374: int (*rint) (int, struct tty *) = tp->t_linesw->l_rint;
1375: u_char *get, *end;
1376: u_int cc, scc;
1377: u_char rsr;
1378: int code;
1379: int s;
1380:
1381: end = sc->sc_ebuf;
1382: get = sc->sc_rbget;
1383: scc = cc = sscom_rbuf_size - sc->sc_rbavail;
1384:
1385: if (cc == sscom_rbuf_size) {
1386: sc->sc_floods++;
1387: if (sc->sc_errors++ == 0)
1388: callout_reset(&sc->sc_diag_callout, 60 * hz,
1389: sscomdiag, sc);
1390: }
1391:
1392: while (cc) {
1393: code = get[0];
1394: rsr = get[1];
1395: if (rsr) {
1396: if (ISSET(rsr, UERSTAT_OVERRUN)) {
1397: sc->sc_overflows++;
1398: if (sc->sc_errors++ == 0)
1399: callout_reset(&sc->sc_diag_callout,
1400: 60 * hz, sscomdiag, sc);
1401: }
1402: if (ISSET(rsr, UERSTAT_BREAK | UERSTAT_FRAME))
1403: SET(code, TTY_FE);
1404: if (ISSET(rsr, UERSTAT_PARITY))
1405: SET(code, TTY_PE);
1406: }
1407: if ((*rint)(code, tp) == -1) {
1408: /*
1409: * The line discipline's buffer is out of space.
1410: */
1411: if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1412: /*
1413: * We're either not using flow control, or the
1414: * line discipline didn't tell us to block for
1415: * some reason. Either way, we have no way to
1416: * know when there's more space available, so
1417: * just drop the rest of the data.
1418: */
1419: get += cc << 1;
1420: if (get >= end)
1421: get -= sscom_rbuf_size << 1;
1422: cc = 0;
1423: } else {
1424: /*
1425: * Don't schedule any more receive processing
1426: * until the line discipline tells us there's
1427: * space available (through sscomhwiflow()).
1428: * Leave the rest of the data in the input
1429: * buffer.
1430: */
1431: SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1432: }
1433: break;
1434: }
1435: get += 2;
1436: if (get >= end)
1437: get = sc->sc_rbuf;
1438: cc--;
1439: }
1440:
1441: if (cc != scc) {
1442: sc->sc_rbget = get;
1443: s = splserial();
1444: SSCOM_LOCK(sc);
1445:
1446: cc = sc->sc_rbavail += scc - cc;
1447: /* Buffers should be ok again, release possible block. */
1448: if (cc >= sc->sc_r_lowat) {
1449: if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1450: CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1451: sscom_enable_rxint(sc);
1452: sc->sc_ucon |= UCON_ERRINT;
1453: bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON,
1454: sc->sc_ucon);
1455:
1456: }
1457: if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
1458: CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1459: sscom_hwiflow(sc);
1460: }
1461: }
1462: SSCOM_UNLOCK(sc);
1463: splx(s);
1464: }
1465: }
1466:
1467: integrate void
1468: sscom_txsoft(struct sscom_softc *sc, struct tty *tp)
1469: {
1470:
1471: CLR(tp->t_state, TS_BUSY);
1472: if (ISSET(tp->t_state, TS_FLUSH))
1473: CLR(tp->t_state, TS_FLUSH);
1474: else
1475: ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
1476: (*tp->t_linesw->l_start)(tp);
1477: }
1478:
1479: integrate void
1480: sscom_stsoft(struct sscom_softc *sc, struct tty *tp)
1481: {
1482: u_char msr, delta;
1483: int s;
1484:
1485: s = splserial();
1486: SSCOM_LOCK(sc);
1487: msr = sc->sc_msts;
1488: delta = sc->sc_msr_delta;
1489: sc->sc_msr_delta = 0;
1490: SSCOM_UNLOCK(sc);
1491: splx(s);
1492:
1493: if (ISSET(delta, sc->sc_msr_dcd)) {
1494: /*
1495: * Inform the tty layer that carrier detect changed.
1496: */
1497: (void) (*tp->t_linesw->l_modem)(tp, ISSET(msr, MSTS_DCD));
1498: }
1499:
1500: if (ISSET(delta, sc->sc_msr_cts)) {
1501: /* Block or unblock output according to flow control. */
1502: if (ISSET(msr, sc->sc_msr_cts)) {
1503: sc->sc_tx_stopped = 0;
1504: (*tp->t_linesw->l_start)(tp);
1505: } else {
1506: sc->sc_tx_stopped = 1;
1507: }
1508: }
1509:
1510: if (sscom_debug)
1511: sscomstatus(sc, "sscom_stsoft");
1512: }
1513:
1514: void
1515: sscomsoft(void *arg)
1516: {
1517: struct sscom_softc *sc = arg;
1518: struct tty *tp;
1519:
1520: if (SSCOM_ISALIVE(sc) == 0)
1521: return;
1522:
1523: {
1524: tp = sc->sc_tty;
1525:
1526: if (sc->sc_rx_ready) {
1527: sc->sc_rx_ready = 0;
1528: sscom_rxsoft(sc, tp);
1529: }
1530:
1531: if (sc->sc_st_check) {
1532: sc->sc_st_check = 0;
1533: sscom_stsoft(sc, tp);
1534: }
1535:
1536: if (sc->sc_tx_done) {
1537: sc->sc_tx_done = 0;
1538: sscom_txsoft(sc, tp);
1539: }
1540: }
1541: }
1542:
1543:
1544: int
1545: sscomrxintr(void *arg)
1546: {
1547: struct sscom_softc *sc = arg;
1548: bus_space_tag_t iot = sc->sc_iot;
1549: bus_space_handle_t ioh = sc->sc_ioh;
1550: u_char *put, *end;
1551: u_int cc;
1552:
1553: if (SSCOM_ISALIVE(sc) == 0)
1554: return 0;
1555:
1556: SSCOM_LOCK(sc);
1557:
1558: end = sc->sc_ebuf;
1559: put = sc->sc_rbput;
1560: cc = sc->sc_rbavail;
1561:
1562: do {
1563: u_char msts, delta;
1564: u_char uerstat;
1565: uint16_t ufstat;
1566:
1567: ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
1568:
1569: /* XXX: break interrupt with no character? */
1570:
1571: if ( (ufstat & (UFSTAT_RXCOUNT|UFSTAT_RXFULL)) &&
1572: !ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1573:
1574: while (cc > 0) {
1575: int cn_trapped = 0;
1576:
1577: /* get status and received character.
1578: read status register first */
1579: uerstat = sscom_geterr(iot, ioh);
1580: put[0] = sscom_getc(iot, ioh);
1581:
1582: if (ISSET(uerstat, UERSTAT_BREAK)) {
1583: int con_trapped = 0;
1584: cn_check_magic(sc->sc_tty->t_dev,
1585: CNC_BREAK, sscom_cnm_state);
1586: if (con_trapped)
1587: continue;
1588: #if defined(KGDB)
1589: if (ISSET(sc->sc_hwflags,
1590: SSCOM_HW_KGDB)) {
1591: kgdb_connect(1);
1592: continue;
1593: }
1594: #endif
1595: }
1596:
1597: put[1] = uerstat;
1598: cn_check_magic(sc->sc_tty->t_dev,
1599: put[0], sscom_cnm_state);
1600: if (!cn_trapped) {
1601: put += 2;
1602: if (put >= end)
1603: put = sc->sc_rbuf;
1604: cc--;
1605: }
1606:
1607: ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
1608: if ( (ufstat & (UFSTAT_RXFULL|UFSTAT_RXCOUNT)) == 0 )
1609: break;
1610: }
1611:
1612: /*
1613: * Current string of incoming characters ended because
1614: * no more data was available or we ran out of space.
1615: * Schedule a receive event if any data was received.
1616: * If we're out of space, turn off receive interrupts.
1617: */
1618: sc->sc_rbput = put;
1619: sc->sc_rbavail = cc;
1620: if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1621: sc->sc_rx_ready = 1;
1622:
1623: /*
1624: * See if we are in danger of overflowing a buffer. If
1625: * so, use hardware flow control to ease the pressure.
1626: */
1627: if (!ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED) &&
1628: cc < sc->sc_r_hiwat) {
1629: SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1630: sscom_hwiflow(sc);
1631: }
1632:
1633: /*
1634: * If we're out of space, disable receive interrupts
1635: * until the queue has drained a bit.
1636: */
1637: if (!cc) {
1638: SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1639: sscom_disable_rxint(sc);
1640: sc->sc_ucon &= ~UCON_ERRINT;
1641: bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
1642: }
1643: }
1644:
1645:
1646: msts = sc->read_modem_status(sc);
1647: delta = msts ^ sc->sc_msts;
1648: sc->sc_msts = msts;
1649:
1650: #ifdef notyet
1651: /*
1652: * Pulse-per-second (PSS) signals on edge of DCD?
1653: * Process these even if line discipline is ignoring DCD.
1654: */
1655: if (delta & sc->sc_ppsmask) {
1656: struct timeval tv;
1657: if ((msr & sc->sc_ppsmask) == sc->sc_ppsassert) {
1658: /* XXX nanotime() */
1659: microtime(&tv);
1660: TIMEVAL_TO_TIMESPEC(&tv,
1661: &sc->ppsinfo.assert_timestamp);
1662: if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
1663: timespecadd(&sc->ppsinfo.assert_timestamp,
1664: &sc->ppsparam.assert_offset,
1665: &sc->ppsinfo.assert_timestamp);
1666: }
1667:
1668: #ifdef PPS_SYNC
1669: if (sc->ppsparam.mode & PPS_HARDPPSONASSERT)
1670: hardpps(&tv, tv.tv_usec);
1671: #endif
1672: sc->ppsinfo.assert_sequence++;
1673: sc->ppsinfo.current_mode = sc->ppsparam.mode;
1674:
1675: } else if ((msr & sc->sc_ppsmask) == sc->sc_ppsclear) {
1676: /* XXX nanotime() */
1677: microtime(&tv);
1678: TIMEVAL_TO_TIMESPEC(&tv,
1679: &sc->ppsinfo.clear_timestamp);
1680: if (sc->ppsparam.mode & PPS_OFFSETCLEAR) {
1681: timespecadd(&sc->ppsinfo.clear_timestamp,
1682: &sc->ppsparam.clear_offset,
1683: &sc->ppsinfo.clear_timestamp);
1684: }
1685:
1686: #ifdef PPS_SYNC
1687: if (sc->ppsparam.mode & PPS_HARDPPSONCLEAR)
1688: hardpps(&tv, tv.tv_usec);
1689: #endif
1690: sc->ppsinfo.clear_sequence++;
1691: sc->ppsinfo.current_mode = sc->ppsparam.mode;
1692: }
1693: }
1694: #endif
1695:
1696: /*
1697: * Process normal status changes
1698: */
1699: if (ISSET(delta, sc->sc_msr_mask)) {
1700: SET(sc->sc_msr_delta, delta);
1701:
1702: /*
1703: * Stop output immediately if we lose the output
1704: * flow control signal or carrier detect.
1705: */
1706: if (ISSET(~msts, sc->sc_msr_mask)) {
1707: sc->sc_tbc = 0;
1708: sc->sc_heldtbc = 0;
1709: #ifdef SSCOM_DEBUG
1710: if (sscom_debug)
1711: sscomstatus(sc, "sscomintr ");
1712: #endif
1713: }
1714:
1715: sc->sc_st_check = 1;
1716: }
1717:
1718: /*
1719: * Done handling any receive interrupts.
1720: */
1721:
1722: /*
1723: * If we've delayed a parameter change, do it
1724: * now, and restart * output.
1725: */
1726: if ((ufstat & UFSTAT_TXCOUNT) == 0) {
1727: /* XXX: we should check transmitter empty also */
1728:
1729: if (sc->sc_heldchange) {
1730: sscom_loadchannelregs(sc);
1731: sc->sc_heldchange = 0;
1732: sc->sc_tbc = sc->sc_heldtbc;
1733: sc->sc_heldtbc = 0;
1734: }
1735: }
1736:
1737:
1738: } while (0);
1739:
1740: SSCOM_UNLOCK(sc);
1741:
1742: /* Wake up the poller. */
1743: softint_schedule(sc->sc_si);
1744:
1745: #if NRND > 0 && defined(RND_COM)
1746: rnd_add_uint32(&sc->rnd_source, iir | rsr);
1747: #endif
1748:
1749: return 1;
1750: }
1751:
1752: int
1753: sscomtxintr(void *arg)
1754: {
1755: struct sscom_softc *sc = arg;
1756: bus_space_tag_t iot = sc->sc_iot;
1757: bus_space_handle_t ioh = sc->sc_ioh;
1758: uint16_t ufstat;
1759:
1760: if (SSCOM_ISALIVE(sc) == 0)
1761: return 0;
1762:
1763: SSCOM_LOCK(sc);
1764:
1765: ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
1766:
1767: /*
1768: * If we've delayed a parameter change, do it
1769: * now, and restart * output.
1770: */
1771: if (sc->sc_heldchange && (ufstat & UFSTAT_TXCOUNT) == 0) {
1772: /* XXX: we should check transmitter empty also */
1773: sscom_loadchannelregs(sc);
1774: sc->sc_heldchange = 0;
1775: sc->sc_tbc = sc->sc_heldtbc;
1776: sc->sc_heldtbc = 0;
1777: }
1778:
1779: /*
1780: * See if data can be transmitted as well. Schedule tx
1781: * done event if no data left and tty was marked busy.
1782: */
1783: if (!ISSET(ufstat,UFSTAT_TXFULL)) {
1784: /*
1785: * Output the next chunk of the contiguous
1786: * buffer, if any.
1787: */
1788: if (sc->sc_tbc > 0) {
1789: __sscom_output_chunk(sc, ufstat);
1790: }
1791: else {
1792: /*
1793: * Disable transmit sscompletion
1794: * interrupts if necessary.
1795: */
1796: if (sc->sc_hwflags & SSCOM_HW_TXINT)
1797: sscom_disable_txint(sc);
1798: if (sc->sc_tx_busy) {
1799: sc->sc_tx_busy = 0;
1800: sc->sc_tx_done = 1;
1801: }
1802: }
1803: }
1804:
1805: SSCOM_UNLOCK(sc);
1806:
1807: /* Wake up the poller. */
1808: softint_schedule(sc->sc_si);
1809:
1810: #if NRND > 0 && defined(RND_COM)
1811: rnd_add_uint32(&sc->rnd_source, iir | rsr);
1812: #endif
1813:
1814: return 1;
1815: }
1816:
1817:
1818: #if defined(KGDB) || defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE)
1819: /*
1820: * Initialize UART for use as console or KGDB line.
1821: */
1822: static int
1823: sscom_init(bus_space_tag_t iot, const struct sscom_uart_info *config,
1824: int rate, int frequency, tcflag_t cflag, bus_space_handle_t *iohp)
1825: {
1826: bus_space_handle_t ioh;
1827: bus_addr_t iobase = config->iobase;
1828:
1829: if (bus_space_map(iot, iobase, SSCOM_SIZE, 0, &ioh))
1830: return ENOMEM; /* ??? */
1831:
1832: bus_space_write_2(iot, ioh, SSCOM_UCON, 0);
1833: bus_space_write_1(iot, ioh, SSCOM_UFCON,
1834: UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 |
1835: UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET |
1836: UFCON_FIFO_ENABLE );
1837: /* tx/rx fifo reset are auto-cleared */
1838:
1839: rate = sscomspeed(rate, frequency);
1840: bus_space_write_2(iot, ioh, SSCOM_UBRDIV, rate);
1841: bus_space_write_2(iot, ioh, SSCOM_ULCON, cflag2lcr(cflag));
1842:
1843: /* enable UART */
1844: bus_space_write_2(iot, ioh, SSCOM_UCON,
1845: UCON_TXMODE_INT|UCON_RXMODE_INT);
1846: bus_space_write_2(iot, ioh, SSCOM_UMCON, UMCON_RTS);
1847:
1848: *iohp = ioh;
1849: return 0;
1850: }
1851:
1852: #endif
1853:
1854: #if defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE)
1855: /*
1856: * Following are all routines needed for SSCOM to act as console
1857: */
1858: struct consdev sscomcons = {
1859: NULL, NULL, sscomcngetc, sscomcnputc, sscomcnpollc, NULL,
1860: NULL, NULL, NODEV, CN_NORMAL
1861: };
1862:
1863:
1864: int
1865: sscom_cnattach(bus_space_tag_t iot, const struct sscom_uart_info *config,
1866: int rate, int frequency, tcflag_t cflag)
1867: {
1868: int res;
1869:
1870: res = sscom_init(iot, config, rate, frequency, cflag, &sscomconsioh);
1871: if (res)
1872: return res;
1873:
1874: cn_tab = &sscomcons;
1875: cn_init_magic(&sscom_cnm_state);
1876: cn_set_magic("\047\001"); /* default magic is BREAK */
1877:
1878: sscomconstag = iot;
1879: sscomconsunit = config->unit;
1880: sscomconsrate = rate;
1881: sscomconscflag = cflag;
1882:
1883: return 0;
1884: }
1885:
1886: void
1887: sscom_cndetach(void)
1888: {
1889: bus_space_unmap(sscomconstag, sscomconsioh, SSCOM_SIZE);
1890: sscomconstag = NULL;
1891:
1892: cn_tab = NULL;
1893: }
1894:
1895: /*
1896: * The read-ahead code is so that you can detect pending in-band
1897: * cn_magic in polled mode while doing output rather than having to
1898: * wait until the kernel decides it needs input.
1899: */
1900:
1901: #define MAX_READAHEAD 20
1902: static int sscom_readahead[MAX_READAHEAD];
1903: static int sscom_readaheadcount = 0;
1904:
1905: int
1906: sscomcngetc(dev_t dev)
1907: {
1908: int s = splserial();
1909: u_char stat, c;
1910:
1911: /* got a character from reading things earlier */
1912: if (sscom_readaheadcount > 0) {
1913: int i;
1914:
1915: c = sscom_readahead[0];
1916: for (i = 1; i < sscom_readaheadcount; i++) {
1917: sscom_readahead[i-1] = sscom_readahead[i];
1918: }
1919: sscom_readaheadcount--;
1920: splx(s);
1921: return c;
1922: }
1923:
1924: /* block until a character becomes available */
1925: while (!sscom_rxrdy(sscomconstag, sscomconsioh))
1926: ;
1927:
1928: c = sscom_getc(sscomconstag, sscomconsioh);
1929: stat = sscom_geterr(sscomconstag, sscomconsioh);
1930: {
1931: int cn_trapped = 0; /* unused */
1932: #ifdef DDB
1933: extern int db_active;
1934: if (!db_active)
1935: #endif
1936: cn_check_magic(dev, c, sscom_cnm_state);
1937: }
1938: splx(s);
1939: return c;
1940: }
1941:
1942: /*
1943: * Console kernel output character routine.
1944: */
1945: void
1946: sscomcnputc(dev_t dev, int c)
1947: {
1948: int s = splserial();
1949: int timo;
1950:
1951: int cin, stat;
1952: if (sscom_readaheadcount < MAX_READAHEAD &&
1953: sscom_rxrdy(sscomconstag, sscomconsioh)) {
1954:
1955: int cn_trapped = 0;
1956: cin = sscom_getc(sscomconstag, sscomconsioh);
1957: stat = sscom_geterr(sscomconstag, sscomconsioh);
1958: cn_check_magic(dev, cin, sscom_cnm_state);
1959: sscom_readahead[sscom_readaheadcount++] = cin;
1960: }
1961:
1962: /* wait for any pending transmission to finish */
1963: timo = 150000;
1964: while (ISSET(bus_space_read_2(sscomconstag, sscomconsioh, SSCOM_UFSTAT),
1965: UFSTAT_TXFULL) && --timo)
1966: continue;
1967:
1968: bus_space_write_1(sscomconstag, sscomconsioh, SSCOM_UTXH, c);
1969: SSCOM_BARRIER(sscomconstag, sscomconsioh, BR | BW);
1970:
1971: #if 0
1972: /* wait for this transmission to complete */
1973: timo = 1500000;
1974: while (!ISSET(bus_space_read_1(sscomconstag, sscomconsioh, SSCOM_UTRSTAT),
1975: UTRSTAT_TXEMPTY) && --timo)
1976: continue;
1977: #endif
1978: splx(s);
1979: }
1980:
1981: void
1982: sscomcnpollc(dev_t dev, int on)
1983: {
1984:
1985: }
1986:
1987: #endif /* SSCOM0CONSOLE||SSCOM1CONSOLE */
1988:
1989: #ifdef KGDB
1990: int
1991: sscom_kgdb_attach(bus_space_tag_t iot, const struct sscom_uart_info *config,
1992: int rate, int frequency, tcflag_t cflag)
1993: {
1994: int res;
1995:
1996: if (iot == sscomconstag && config->unit == sscomconsunit) {
1997: printf( "console==kgdb_port (%d): kgdb disabled\n", sscomconsunit);
1998: return EBUSY; /* cannot share with console */
1999: }
2000:
2001: res = sscom_init(iot, config, rate, frequency, cflag, &sscom_kgdb_ioh);
2002: if (res)
2003: return res;
2004:
2005: kgdb_attach(sscom_kgdb_getc, sscom_kgdb_putc, NULL);
2006: kgdb_dev = 123; /* unneeded, only to satisfy some tests */
2007:
2008: sscom_kgdb_iot = iot;
2009: sscom_kgdb_unit = config->unit;
2010:
2011: return 0;
2012: }
2013:
2014: /* ARGSUSED */
2015: int
2016: sscom_kgdb_getc(void *arg)
2017: {
2018: int c, stat;
2019:
2020: /* block until a character becomes available */
2021: while (!sscom_rxrdy(sscom_kgdb_iot, sscom_kgdb_ioh))
2022: ;
2023:
2024: c = sscom_getc(sscom_kgdb_iot, sscom_kgdb_ioh);
2025: stat = sscom_geterr(sscom_kgdb_iot, sscom_kgdb_ioh);
2026:
2027: return c;
2028: }
2029:
2030: /* ARGSUSED */
2031: void
2032: sscom_kgdb_putc(void *arg, int c)
2033: {
2034: int timo;
2035:
2036: /* wait for any pending transmission to finish */
2037: timo = 150000;
2038: while (ISSET(bus_space_read_2(sscom_kgdb_iot, sscom_kgdb_ioh,
2039: SSCOM_UFSTAT), UFSTAT_TXFULL) && --timo)
2040: continue;
2041:
2042: bus_space_write_1(sscom_kgdb_iot, sscom_kgdb_ioh, SSCOM_UTXH, c);
2043: SSCOM_BARRIER(sscom_kgdb_iot, sscom_kgdb_ioh, BR | BW);
2044:
2045: #if 0
2046: /* wait for this transmission to complete */
2047: timo = 1500000;
2048: while (!ISSET(bus_space_read_1(sscom_kgdb_iot, sscom_kgdb_ioh,
2049: SSCOM_UTRSTAT), UTRSTAT_TXEMPTY) && --timo)
2050: continue;
2051: #endif
2052: }
2053: #endif /* KGDB */
2054:
2055: /* helper function to identify the sscom ports used by
2056: console or KGDB (and not yet autoconf attached) */
2057: int
2058: sscom_is_console(bus_space_tag_t iot, int unit,
2059: bus_space_handle_t *ioh)
2060: {
2061: bus_space_handle_t help;
2062:
2063: if (!sscomconsattached &&
2064: iot == sscomconstag && unit == sscomconsunit)
2065: help = sscomconsioh;
2066: #ifdef KGDB
2067: else if (!sscom_kgdb_attached &&
2068: iot == sscom_kgdb_iot && unit == sscom_kgdb_unit)
2069: help = sscom_kgdb_ioh;
2070: #endif
2071: else
2072: return 0;
2073:
2074: if (ioh)
2075: *ioh = help;
2076: return 1;
2077: }
CVSweb