Annotation of src/sys/arch/pc532/dev/scn.c, Revision 1.66
1.66 ! chs 1: /* $NetBSD: scn.c,v 1.65 2005/09/06 21:40:38 kleink Exp $ */
1.62 agc 2:
3: /*
4: * Copyright (c) 1991, 1992, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Portions of this software were developed by the Computer Systems
8: * Engineering group at Lawrence Berkeley Laboratory under DARPA
9: * contract BG 91-66 and contributed to Berkeley.
10: *
11: * All advertising materials mentioning features or use of this software
12: * must display the following acknowledgement:
13: * This product includes software developed by the University of
14: * California, Lawrence Berkeley Laboratory.
15: *
16: * Redistribution and use in source and binary forms, with or without
17: * modification, are permitted provided that the following conditions
18: * are met:
19: * 1. Redistributions of source code must retain the above copyright
20: * notice, this list of conditions and the following disclaimer.
21: * 2. Redistributions in binary form must reproduce the above copyright
22: * notice, this list of conditions and the following disclaimer in the
23: * documentation and/or other materials provided with the distribution.
24: * 3. Neither the name of the University nor the names of its contributors
25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
39: *
40: * from: @(#)com.c 7.5 (Berkeley) 5/16/91
41: */
1.12 cgd 42:
1.19 phil 43: /*
1.36 matthias 44: * Copyright (c) 1996, 1997 Philip L. Budne.
1.30 matthias 45: * Copyright (c) 1993 Philip A. Nelson.
46: *
47: * Portions of this software were developed by the Computer Systems
48: * Engineering group at Lawrence Berkeley Laboratory under DARPA
49: * contract BG 91-66 and contributed to Berkeley.
50: *
51: * All advertising materials mentioning features or use of this software
52: * must display the following acknowledgement:
53: * This product includes software developed by the University of
54: * California, Lawrence Berkeley Laboratory.
1.1 phil 55: *
56: * Redistribution and use in source and binary forms, with or without
57: * modification, are permitted provided that the following conditions
58: * are met:
59: * 1. Redistributions of source code must retain the above copyright
60: * notice, this list of conditions and the following disclaimer.
61: * 2. Redistributions in binary form must reproduce the above copyright
62: * notice, this list of conditions and the following disclaimer in the
63: * documentation and/or other materials provided with the distribution.
64: * 3. All advertising materials mentioning features or use of this software
65: * must display the following acknowledgement:
66: * This product includes software developed by the University of
67: * California, Berkeley and its contributors.
68: * 4. Neither the name of the University nor the names of its contributors
69: * may be used to endorse or promote products derived from this software
70: * without specific prior written permission.
71: *
72: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
73: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
74: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
76: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
77: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
78: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
79: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
80: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
81: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82: * SUCH DAMAGE.
83: *
1.30 matthias 84: * from: @(#)com.c 7.5 (Berkeley) 5/16/91
1.1 phil 85: */
1.61 lukem 86:
87: #include <sys/cdefs.h>
1.66 ! chs 88: __KERNEL_RCSID(0, "$NetBSD: scn.c,v 1.65 2005/09/06 21:40:38 kleink Exp $");
1.1 phil 89:
1.43 jonathan 90: #include "opt_ddb.h"
1.48 lukem 91: #include "opt_kgdb.h"
1.60 thorpej 92: #include "opt_cpu30mhz.h"
1.1 phil 93: #include "scn.h"
94:
1.11 phil 95: #include <sys/param.h>
96: #include <sys/systm.h>
97: #include <sys/ioctl.h>
98: #include <sys/select.h>
99: #include <sys/tty.h>
100: #include <sys/proc.h>
101: #include <sys/user.h>
102: #include <sys/file.h>
103: #include <sys/uio.h>
104: #include <sys/kernel.h>
105: #include <sys/syslog.h>
106: #include <sys/types.h>
1.13 phil 107: #include <sys/device.h>
1.31 matthias 108: #include <sys/malloc.h>
1.54 gehenna 109: #include <sys/conf.h>
1.37 matthias 110: #ifdef KGDB
111: #include <sys/kgdb.h>
112: #endif
1.11 phil 113:
114: #include <dev/cons.h>
115:
1.33 matthias 116: #include <machine/autoconf.h>
1.1 phil 117:
118: #include "scnreg.h"
1.30 matthias 119: #include "scnvar.h"
120:
1.33 matthias 121: static const char scnints[4] = {IR_TTY0, IR_TTY1, IR_TTY2, IR_TTY3};
122: static const char rxints[4] = {IR_TTY0RDY, IR_TTY1RDY, IR_TTY2RDY, IR_TTY3RDY};
1.32 matthias 123:
124: int scnprobe __P((struct device *, struct cfdata *, void *));
1.30 matthias 125: void scnattach __P((struct device *, struct device *, void *));
126: int scnparam __P((struct tty *, struct termios *));
127: void scnstart __P((struct tty *));
1.44 matthias 128: void scncnprobe __P((struct consdev *));
1.30 matthias 129: void scncninit __P((struct consdev *));
1.64 chs 130: int scncngetc __P((void *));
131: void scncnputc __P((void *, int));
1.30 matthias 132: void scncnpollc __P((dev_t, int));
133: int scninit __P((dev_t, int));
134: void scncnreinit __P((void *));
1.32 matthias 135: int scnhwiflow __P((struct tty *, int));
1.30 matthias 136:
1.56 thorpej 137: CFATTACH_DECL(scn, sizeof(struct scn_softc),
138: scnprobe, scnattach, NULL, NULL);
1.58 simonb 139:
140: extern struct cfdriver scn_cd;
1.41 thorpej 141:
1.54 gehenna 142: dev_type_open(scnopen);
143: dev_type_close(scnclose);
144: dev_type_read(scnread);
145: dev_type_write(scnwrite);
146: dev_type_ioctl(scnioctl);
147: dev_type_stop(scnstop);
148: dev_type_tty(scntty);
149: dev_type_poll(scnpoll);
150:
151: const struct cdevsw scn_cdevsw = {
152: scnopen, scnclose, scnread, scnwrite, scnioctl,
1.57 jdolecek 153: scnstop, scntty, scnpoll, nommap, ttykqfilter, D_TTY
1.54 gehenna 154: };
155:
1.30 matthias 156: #ifndef CONSOLE_SPEED
157: #define CONSOLE_SPEED TTYDEF_SPEED
158: #endif
159:
160: #ifndef SCNDEF_CFLAG
161: #define SCNDEF_CFLAG TTYDEF_CFLAG
162: #endif
163:
1.31 matthias 164: #ifdef CPU30MHZ
1.34 matthias 165: #define RECOVER() __asm __volatile("bispsrw 0x800" : : : "cc")
1.31 matthias 166: #else
167: #define RECOVER()
168: #endif
169:
1.30 matthias 170: int scndefaultrate = TTYDEF_SPEED;
171: int scnconsrate = CONSOLE_SPEED;
172:
173: #define SOFTC(UNIT) scn_cd.cd_devs[(UNIT)]
1.64 chs 174: #define SCN_ADDR2DUART(addr) (((addr) >> 4) & 3)
175: #define SCN_ADDR2CHAN(addr) (((addr) >> 3) & 1)
176: #define SCN_ISCONSOLE(addr) \
177: (SCN_ADDR2DUART(addr) == SCN_CONSDUART && (SCN_ADDR2CHAN(addr) == SCN_CONSCHAN))
1.30 matthias 178:
1.31 matthias 179: static void scnintr __P((void *));
1.32 matthias 180: static void scnrxintr __P((void *));
1.64 chs 181: static int scn_rxintr __P((struct scn_softc *));
1.30 matthias 182: static void scnsoft __P((void *));
1.36 matthias 183: static void scn_setchip __P((struct scn_softc *sc));
184: static int scniter __P((int *, int, int*, int*, struct chan *, int));
1.64 chs 185: static int scn_config __P((int, int, int, int, u_char, u_char));
1.37 matthias 186: static void scn_rxenable __P((struct scn_softc *));
187: static void scn_rxdisable __P((struct scn_softc *));
188: static void dcd_int __P((struct scn_softc *, struct tty *, u_char));
1.66 ! chs 189: static void scnoverrun __P((int, long *, const char *));
1.37 matthias 190: static unsigned char opbits __P((struct scn_softc *, int));
1.30 matthias 191:
1.35 matthias 192: static int scnsir = -1; /* s/w intr number */
193: #define setsoftscn() softintr(scnsir)
194:
195: #ifdef SCN_TIMING
1.30 matthias 196: /*
197: * Keep timing info on latency of software interrupt used by
1.31 matthias 198: * the ringbuf code to empty ring buffer.
1.30 matthias 199: * "getinfo" program reads data from /dev/kemm.
200: */
201: static struct timeval tstart;
202: #define NJITTER 100
203: int scn_njitter = NJITTER;
204: int scn_jitter[NJITTER];
205: #endif
1.16 phil 206:
1.35 matthias 207: #define SCN_CLOCK 3686400 /* input clock */
1.1 phil 208:
1.36 matthias 209: /* speed table groups ACR[7] */
210: #define GRP_A 0
211: #define GRP_B ACR_BRG
212:
213: /* combo of MR0[2:0] and ACR[7] */
214: #define MODE0A MR0_MODE_0
215: #define MODE0B (MR0_MODE_0|ACR_BRG)
216: #define MODE1A MR0_MODE_1
217: #define MODE1B (MR0_MODE_1|ACR_BRG)
218: #define MODE2A MR0_MODE_2
219: #define MODE2B (MR0_MODE_2|ACR_BRG)
220:
221: #define ANYMODE -1
222: #define DEFMODE(C92) MODE0A /* use MODE4A if 26c92? */
223:
224: /* speed code for Counter/Timer (all modes, groups) */
225: #define USE_CT 0xd
226:
1.30 matthias 227: /*
1.36 matthias 228: * Rate table, ordered by speed, then mode.
229: * NOTE: ordering of modes must be done carefully!
1.30 matthias 230: */
1.36 matthias 231: struct tabent {
232: int32_t speed;
233: int16_t code;
234: int16_t mode;
235: } table[] = {
236: { 50, 0x0, MODE0A },
237: { 75, 0x0, MODE0B },
238: { 110, 0x1, MODE0A },
239: { 110, 0x1, MODE0B },
240: { 110, 0x1, MODE1A },
241: { 110, 0x1, MODE1B },
242: { 134, 0x2, MODE0A }, /* 134.5 */
243: { 134, 0x2, MODE0B }, /* 134.5 */
244: { 134, 0x2, MODE1A }, /* 134.5 */
245: { 134, 0x2, MODE1B }, /* 134.5 */
246: { 150, 0x3, MODE0A },
247: { 150, 0x3, MODE0A },
248: { 200, 0x3, MODE0A },
249: { 300, 0x4, MODE0A },
250: { 300, 0x4, MODE0B },
251: { 300, 0x0, MODE1A },
252: { 450, 0x0, MODE1B },
253: { 600, 0x5, MODE0A },
254: { 600, 0x5, MODE0B },
255: { 880, 0x1, MODE2A },
256: { 880, 0x1, MODE2B },
257: { 900, 0x3, MODE1B },
258: { 1050, 0x7, MODE0A },
259: { 1050, 0x7, MODE1A },
260: { 1076, 0x2, MODE2A },
261: { 1076, 0x2, MODE2B },
262: { 1200, 0x6, MODE0A },
263: { 1200, 0x6, MODE0B },
264: { 1200, 0x3, MODE1A },
265: { 1800, 0xa, MODE0B },
266: { 1800, 0x4, MODE1A },
267: { 1800, 0x4, MODE1B },
268: { 2000, 0x7, MODE0B },
269: { 2000, 0x7, MODE1B },
270: { 2400, 0x8, MODE0A },
271: { 2400, 0x8, MODE0B },
272: { 3600, 0x5, MODE1A },
273: { 3600, 0x5, MODE1B },
274: { 4800, 0x9, MODE2A },
275: { 4800, 0x9, MODE2B },
276: { 4800, 0x9, MODE0A },
277: { 4800, 0x9, MODE0B },
278: { 7200, 0xa, MODE0A },
279: { 7200, 0x0, MODE2B },
280: { 7200, 0x6, MODE1A },
281: { 7200, 0x6, MODE1B },
282: { 9600, 0xb, MODE2A },
283: { 9600, 0xb, MODE2B },
284: { 9600, 0xb, MODE0A },
285: { 9600, 0xb, MODE0B },
286: { 9600, 0xd, MODE1A }, /* use C/T as entre' to mode1 */
287: { 9600, 0xd, MODE1B }, /* use C/T as entre' to mode1 */
288: { 14400, 0x3, MODE2B },
289: { 14400, 0x8, MODE1A },
290: { 14400, 0x8, MODE1B },
291: { 19200, 0x3, MODE2A },
292: { 19200, 0xc, MODE2B },
293: { 19200, 0xc, MODE0B },
294: { 19200, 0xd, MODE1A }, /* use C/T as entre' to mode1 */
295: { 19200, 0xd, MODE1B }, /* use C/T as entre' to mode1 */
296: { 28800, 0x4, MODE2A },
297: { 28800, 0x4, MODE2B },
298: { 28800, 0x9, MODE1A },
299: { 28800, 0x9, MODE1B },
300: { 38400, 0xc, MODE2A },
301: { 38400, 0xc, MODE0A },
302: { 57600, 0x5, MODE2A },
303: { 57600, 0x5, MODE2B },
304: { 57600, 0xb, MODE1A },
305: { 57600, 0xb, MODE1B },
306: { 115200, 0x6, MODE2A },
307: { 115200, 0x6, MODE2B },
308: { 115200, 0xc, MODE1B },
309: { 230400, 0xc, MODE1A }
310: };
311: #define TABENTRIES (sizeof(table)/sizeof(table[0]))
1.26 thorpej 312:
1.30 matthias 313: /*
1.36 matthias 314: * boolean for speed codes which are identical in both A/B BRG groups
315: * in all modes
1.30 matthias 316: */
1.36 matthias 317: static u_char bothgroups[16] = {
318: 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1
319: };
1.1 phil 320:
1.30 matthias 321: /*
1.36 matthias 322: * Manually constructed divisors table
323: * for minimum error (from some of Dave Rand's code)
1.30 matthias 324: */
1.36 matthias 325: const struct {
326: u_int16_t speed;
327: u_int16_t div;
328: } divs[] = {
329: { 50, 2303 }, /* 2304 is exact?? */
330: { 110, 1047 }, /* Should be 1047.27 */
331: { 134, 857 }, /* Should be 856.505576 */
332: { 1050, 110 }, /* Should be 109.7142857 */
333: { 2000, 57 } /* Should be 57.6 */
1.30 matthias 334: };
1.36 matthias 335: #define DIVS (sizeof(divs)/sizeof(divs[0]))
1.32 matthias 336:
1.30 matthias 337: /*
338: * minor unit bit decode:
339: * CxxxUUU
340: *
341: * C - carrier
342: * 0 - delay open until carrier high
343: * 1 - allow open with carrier low
344: * UUU - unit 0-7
345: */
1.1 phil 346:
1.30 matthias 347: #define DEV_UNIT(x) (minor(x) & 0x7)
348: #define DEV_DIALOUT(x) (minor(x) & 0x80)
1.1 phil 349:
1.30 matthias 350: extern struct tty *constty;
1.40 phil 351:
1.64 chs 352: #define SCN_MAXDUART 4
353: static struct duart scn_duart[SCN_MAXDUART];
1.1 phil 354:
355: #ifdef KGDB
356: extern int kgdb_dev;
357: extern int kgdb_rate;
358: extern int kgdb_debug_init;
359: #endif
1.64 chs 360:
361: #define SCN_MAP_ADDR(addr) \
362: ((addr) - SCN_FIRST_ADR + SCN_FIRST_MAP_ADR)
363:
1.36 matthias 364: /* RS-232 configuration routines */
365:
366: /*
367: * set chip parameters, or mark for delayed change.
368: * called at spltty() or on TxEMPTY interrupt.
369: *
370: * Reads current values to avoid glitches from redundant sets.
371: * Perhaps should save last value set to avoid read/write? NOTE:
372: * Would still need to do read if write not needed to advance MR
373: * pointer.
374: *
375: * new 2/97 -plb
376: */
377:
378: static void
379: scn_setchip(sc)
380: struct scn_softc *sc;
381: {
382: struct duart *dp;
383: u_char acr, csr, mr1, mr2;
384: int chan;
385:
386: if (sc->sc_tty && (sc->sc_tty->t_state & TS_BUSY)) {
387: sc->sc_heldchanges = 1;
388: return;
389: }
390:
1.64 chs 391: chan = sc->sc_channel;
1.36 matthias 392: dp = sc->sc_duart;
393: if (dp->type == SC26C92) {
394: u_char nmr0a, mr0a;
1.1 phil 395:
1.39 matthias 396: /* input rate high enough so 64 bit time watchdog not
397: * onerous? */
1.36 matthias 398: if (dp->chan[chan].ispeed >= 1200) {
1.39 matthias 399: /* set FIFO threshold at 6 for other
400: * thresholds we could have to set MR1_FFULL
401: */
1.36 matthias 402: dp->chan[chan].mr0 |= MR0_RXWD | MR0_RXINT;
403: } else {
404: dp->chan[chan].mr0 &= ~(MR0_RXWD | MR0_RXINT);
405: }
406:
407: /* select BRG mode (MR0A only) */
408: nmr0a = dp->chan[0].mr0 | (dp->mode & MR0_MODE);
409:
410: dp->base[CH_CR] = CR_CMD_MR0;
411: RECOVER();
412:
413: mr0a = dp->base[CH_MR];
414: if (mr0a != nmr0a) {
415: dp->base[CH_CR] = CR_CMD_MR0;
416: RECOVER();
417: dp->base[CH_MR] = nmr0a;
418: }
419:
420: if (chan) { /* channel B? */
421: u_char mr0b;
422:
423: sc->sc_chbase[CH_CR] = CR_CMD_MR0;
424: RECOVER();
425: mr0b = dp->base[CH_MR];
426:
427: if (dp->chan[chan].mr0 != mr0b) {
428: sc->sc_chbase[CH_CR] = CR_CMD_MR0;
429: RECOVER();
430: sc->sc_chbase[CH_MR] = dp->chan[chan].mr0;
431: }
432: }
433: } else {
434: sc->sc_chbase[CH_CR] = CR_CMD_MR1;
435: RECOVER();
436: }
437:
438: mr1 = sc->sc_chbase[CH_MR];
439: mr2 = sc->sc_chbase[CH_MR];
440: if (mr1 != dp->chan[chan].new_mr1 ||
441: mr2 != dp->chan[chan].new_mr2) {
442: sc->sc_chbase[CH_CR] = CR_CMD_MR1;
443: RECOVER();
444: sc->sc_chbase[CH_MR] = dp->chan[chan].new_mr1;
445: sc->sc_chbase[CH_MR] = dp->chan[chan].new_mr2;
446: }
447:
448: acr = dp->acr | (dp->mode & ACR_BRG);
449: dp->base[DU_ACR] = acr; /* write-only reg! */
450:
451: /* set speed codes */
452: csr = (dp->chan[chan].icode<<4) | dp->chan[chan].ocode;
453: if (sc->sc_chbase[CH_CSR] != csr) {
454: sc->sc_chbase[CH_CSR] = csr;
455: }
456:
457: /* see if counter/timer in use */
458: if (dp->counter &&
459: (dp->chan[0].icode == USE_CT || dp->chan[0].ocode == USE_CT ||
460: dp->chan[1].icode == USE_CT || dp->chan[1].ocode == USE_CT)) {
461:
462: /* program counter/timer only if necessary */
463: if (dp->counter != dp->ocounter) {
464: u_int16_t div;
465: #ifdef DIVS
466: int i;
467:
468: /* look for precalculated rate, for minimum error */
469: for (i = 0; i < DIVS && divs[i].speed <= dp->counter; i++) {
470: if (divs[i].speed == dp->counter) {
471: div = divs[i].div;
472: goto found;
473: }
474: }
1.30 matthias 475: #endif
1.1 phil 476:
1.36 matthias 477: /* not found in table; calculate a value (rounding up) */
478: div = ((long)SCN_CLOCK/16/2 + dp->counter/2) / dp->counter;
479:
480: found:
481: /* halt before loading? may ALWAYS glitch?
482: * reload race may only sometimes glitch??
483: */
484: dp->base[DU_CTUR] = div >> 8;
485: dp->base[DU_CTLR] = div & 255;
486: if (dp->ocounter == 0) {
487: /* not previously used? */
488: u_char temp;
489: /* start C/T running */
490: temp = dp->base[DU_CSTRT];
491: }
492: dp->ocounter = dp->counter;
493: }
494: } else {
495: /* counter not in use; mark as free */
496: dp->counter = 0;
497: }
498: sc->sc_heldchanges = 0;
1.30 matthias 499:
500: /*
1.36 matthias 501: * delay a tiny bit to try and avoid tx glitching.
502: * I know we're at spltty(), but this is much better than the
503: * old version used DELAY((96000 / out_speed) * 10000)
504: * -plb
1.30 matthias 505: */
1.36 matthias 506: DELAY(10);
507: }
508:
509: /*
510: * iterator function for speeds.
511: * (could be called "findnextcode")
512: * Returns sequence of possible speed codes for a given rate.
513: * should set index to zero before first call.
514: *
515: * Could be implemented as a "checkspeed()" function called
516: * to evaluate table entries, BUT this allows more variety in
517: * use of C/T with fewer table entries.
518: */
519:
520: static int
521: scniter(index, wanted, counter, mode, other, c92)
522: int *index; /* IN/OUT: index */
523: int wanted; /* IN: speed wanted */
524: int *counter; /* IN/OUT: counter/timer rate */
525: int *mode; /* IN/OUT: mode */
526: struct chan *other; /* IN: other channel, or NULL */
527: int c92; /* IN: true for 26C92 */
528: {
529: while (*index < TABENTRIES) {
530: struct tabent *tp;
531:
532: tp = table + (*index)++;
533: if (tp->speed != wanted)
534: continue;
535:
536: /* if not a 26C92 only look at MODE0 entries */
537: if (!c92 && (tp->mode & MR0_MODE) != MR0_MODE_0)
538: continue;
539:
540: /*
541: * check mode;
542: * OK if this table entry for current mode, or mode not
543: * yet set, or other channel's rates are available in both
544: * A and B groups.
545: */
546:
547: if (tp->mode == *mode || *mode == ANYMODE ||
548: (other != NULL && (tp->mode & MR0_MODE) == (*mode & MR0_MODE) &&
549: bothgroups[other->icode] && bothgroups[other->ocode])) {
550: /*
551: * for future table entries specifying
552: * use of counter/timer
553: */
554: if (tp->code == USE_CT) {
555: if (*counter != wanted && *counter != 0)
556: continue; /* counter busy */
557: *counter = wanted;
558: }
559: *mode = tp->mode;
560: return tp->code;
561: }
562: }
1.1 phil 563:
1.36 matthias 564: /* here after returning all applicable table entries */
565: /* XXX return sequence of USE_CT with all possible modes?? */
566: if ((*index)++ == TABENTRIES) {
567: /* Max C/T rate (even on 26C92?) is 57600 */
568: if (wanted <= 57600 && (*counter == wanted || *counter == 0)) {
569: *counter = wanted;
570: return USE_CT;
571: }
572: }
573:
574: return -1; /* FAIL */
1.30 matthias 575: }
1.36 matthias 576:
577: /*
578: * calculate configuration
579: * rewritten 2/97 -plb
580: */
1.30 matthias 581: static int
1.64 chs 582: scn_config(unit, chan, ispeed, ospeed, mr1, mr2)
1.36 matthias 583: int unit;
1.64 chs 584: int chan;
1.36 matthias 585: int ispeed; /* input speed in bps */
586: int ospeed; /* output speed in bps */
587: u_char mr1; /* new bits for MR1 */
588: u_char mr2; /* new bits for MR2 */
1.30 matthias 589: {
1.64 chs 590: struct scn_softc *sc;
1.36 matthias 591: struct duart *dp;
1.64 chs 592: int other; /* opposite of chan */
1.36 matthias 593: int mode;
594: int counter;
595: int i, o; /* input, output iterator indexes */
596: int ic, oc; /* input, output codes */
597: struct chan *ocp; /* other duart channel */
598: struct tty *otp; /* other channel tty struct */
599: int c92; /* true if duart is sc26c92 */
1.32 matthias 600: int s;
1.30 matthias 601:
602: /* Set up softc pointer. */
603: if (unit >= scn_cd.cd_ndevs)
604: return ENXIO;
605: sc = SOFTC(unit);
1.64 chs 606: chan = sc->sc_channel;
1.36 matthias 607: other = chan ^ 1;
608: dp = sc->sc_duart;
609: ocp = &dp->chan[other];
1.64 chs 610: otp = ocp->tty;
1.36 matthias 611: c92 = (dp->type == SC26C92);
612:
1.30 matthias 613: /*
1.36 matthias 614: * Right now the first combination that works is used.
615: * Perhaps it should search entire solution space for "best"
616: * combination. For example, use heuristic weighting of mode
617: * preferences, and use of counter timer?
618: *
619: * For example right now with 2681/2692 when default rate is
620: * 9600 and other channel is closed setting 19200 will pick
621: * mode 0a and use counter/timer. Better solution might be
622: * mode 0b, leaving counter/timer free!
623: *
624: * When other channel is open might want to prefer
625: * leaving counter timer free, or not flipping A/B group?
626: */
627: if (otp && (otp->t_state & TS_ISOPEN)) {
1.64 chs 628:
1.36 matthias 629: /*
630: * Other channel open;
631: * Find speed codes compatible with current mode/counter.
632: */
633:
634: i = 0;
635: for (;;) {
636: mode = dp->mode;
637: counter = dp->counter;
1.30 matthias 638:
1.36 matthias 639: /* NOTE: pass other chan pointer to allow group flipping */
640: ic = scniter(&i, ispeed, &counter, &mode, ocp, c92);
641: if (ic == -1)
642: break;
643:
644: o = 0;
645: if ((oc = scniter(&o, ospeed, &counter,
646: &mode, NULL, c92)) != -1) {
1.30 matthias 647: /*
1.36 matthias 648: * take first match
649: *
650: * Perhaps calculate heuristic "score",
651: * save score,codes,mode,counter if score
652: * better than previous best?
1.30 matthias 653: */
1.36 matthias 654: goto gotit;
655: }
656: }
657: /* XXX try looping for ospeed? */
658: } else {
659: /* other channel closed */
660: int oo, oi; /* other input, output iterators */
661: int oic, ooc; /* other input, output codes */
662:
663: /*
664: * Here when other channel closed. Finds first
665: * combination that will allow other channel to be opened
666: * (with defaults) and fits our needs.
667: */
668: oi = 0;
669: for (;;) {
670: mode = ANYMODE;
671: counter = 0;
672:
673: oic = scniter(&oi, ocp->ispeed, &counter, &mode, NULL, c92);
674: if (oic == -1)
675: break;
676:
677: oo = 0;
678: while ((ooc = scniter(&oo, ocp->ospeed, &counter,
679: &mode, NULL, c92)) != -1) {
680: i = 0;
681: while ((ic = scniter(&i, ispeed, &counter,
682: &mode, NULL, c92)) != -1) {
683: o = 0;
684: if ((oc = scniter(&o, ospeed, &counter,
685: &mode, NULL, c92)) != -1) {
686: /*
687: * take first match
688: *
689: * Perhaps calculate heuristic
690: * "score", save
691: * score,codes,mode,counter
692: * if score better than
693: * previous best?
694: */
695: s = spltty();
696: dp->chan[other].icode = oic;
697: dp->chan[other].ocode = ooc;
698: goto gotit2;
699: }
700: }
1.30 matthias 701: }
702: }
703: }
1.46 matthias 704: return EINVAL;
1.36 matthias 705:
706: gotit:
1.30 matthias 707: s = spltty();
1.36 matthias 708: gotit2:
709: dp->chan[chan].new_mr1 = mr1;
710: dp->chan[chan].new_mr2 = mr2;
711: dp->chan[chan].ispeed = ispeed;
712: dp->chan[chan].ospeed = ospeed;
713: dp->chan[chan].icode = ic;
714: dp->chan[chan].ocode = oc;
715: if (mode == ANYMODE) /* no mode selected?? */
716: mode = DEFMODE(c92);
717: dp->mode = mode;
718: dp->counter = counter;
719:
720: scn_setchip(sc); /* set chip now, if possible */
1.30 matthias 721: splx(s);
722: return (0);
1.1 phil 723: }
1.64 chs 724:
1.30 matthias 725: int
726: scnprobe(parent, cf, aux)
727: struct device *parent;
1.32 matthias 728: struct cfdata *cf;
729: void *aux;
1.33 matthias 730: {
731: struct confargs *ca = aux;
1.64 chs 732: volatile u_char *ch_base;
1.32 matthias 733: int mr1;
1.31 matthias 734:
735: /* Now some black magic that should detect a scc26x2 channel. */
1.64 chs 736: ca->ca_addr = SCN_MAP_ADDR(cf->cf_loc[MAINBUSCF_ADDR]);
737: ch_base = (volatile u_char *)ca->ca_addr;
1.31 matthias 738: ch_base[CH_CR] = CR_CMD_RESET_ERR;
739: RECOVER();
740: ch_base[CH_CR] = CR_CMD_RESET_BRK;
741: RECOVER();
742: ch_base[CH_CR] = CR_CMD_MR1;
743: RECOVER();
744: mr1 = ch_base[CH_MR] ^ 0x80;
745: ch_base[CH_CR] = CR_CMD_MR1;
746: RECOVER();
747: ch_base[CH_MR] = mr1;
748: ch_base[CH_CR] = CR_CMD_MR1;
749: RECOVER();
750: if (ch_base[CH_MR] != mr1)
751: return(0);
752: if (ch_base[CH_MR] == mr1)
753: return(0);
1.33 matthias 754:
1.64 chs 755: ca->ca_irq = cf->cf_loc[MAINBUSCF_IRQ];
1.33 matthias 756:
1.31 matthias 757: return(1);
1.30 matthias 758: }
759:
760: /*
761: * No need to make scn_rx{en,dis}able too efficient,
762: * they're only called on setup, open & close!
763: */
764: static __inline void
765: scn_rxenable(sc)
766: struct scn_softc *sc;
767: {
1.36 matthias 768: struct duart *dp;
1.32 matthias 769: int channel;
1.30 matthias 770:
1.36 matthias 771: dp = sc->sc_duart;
1.64 chs 772: channel = sc->sc_channel;
1.30 matthias 773:
774: /* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
775: if (channel == 0)
1.36 matthias 776: dp->opcr |= OPCR_OP4_RXRDYA;
1.30 matthias 777: else
1.36 matthias 778: dp->opcr |= OPCR_OP5_RXRDYB;
779: dp->base[DU_OPCR] = dp->opcr;
1.30 matthias 780: }
1.1 phil 781:
1.30 matthias 782: static __inline void
783: scn_rxdisable(sc)
784: struct scn_softc *sc;
785: {
1.36 matthias 786: struct duart *dp;
1.32 matthias 787: int channel;
1.30 matthias 788:
1.36 matthias 789: dp = sc->sc_duart;
1.64 chs 790: channel = sc->sc_channel;
1.30 matthias 791:
792: /* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
793: if (channel == 0)
1.36 matthias 794: dp->opcr &= ~OPCR_OP4_RXRDYA;
1.30 matthias 795: else
1.36 matthias 796: dp->opcr &= ~OPCR_OP5_RXRDYB;
797: dp->base[DU_OPCR] = dp->opcr;
1.1 phil 798: }
799:
1.13 phil 800: void
1.16 phil 801: scnattach(parent, self, aux)
1.30 matthias 802: struct device *parent;
803: struct device *self;
804: void *aux;
805: {
1.33 matthias 806: struct confargs *ca = aux;
1.64 chs 807: struct scn_softc *sc;
808: struct duart *duart;
809: volatile u_char *ch_base;
810: volatile u_char *duart_base;
1.32 matthias 811: int channel;
812: int speed;
1.33 matthias 813: int s;
1.64 chs 814: int maj;
1.33 matthias 815: u_char unit;
1.64 chs 816: u_char duartno;
1.33 matthias 817: u_char delim = ':';
1.64 chs 818: u_char mr1, mr2;
1.37 matthias 819: enum scntype scntype = SCNUNK;
1.66 ! chs 820: const char *duart_type = "Unknown";
1.59 simonb 821: char *intrname;
1.64 chs 822: boolean_t console, first;
1.30 matthias 823:
824: sc = (void *) self;
1.64 chs 825: unit = self->dv_unit;
1.30 matthias 826:
1.64 chs 827: duartno = SCN_ADDR2DUART(ca->ca_addr); /* get chip number */
828: channel = SCN_ADDR2CHAN(ca->ca_addr); /* get channel on chip */
829:
830: duart = sc->sc_duart = &scn_duart[duartno];
831: duart->chan[channel].sc = sc;
832: first = (duart->base == NULL);
1.30 matthias 833:
834: /* pick up "flags" (SCN_xxx) from config file */
835: if (self->dv_cfdata) /* paranoia */
1.36 matthias 836: sc->sc_swflags = ca->ca_flags;
1.30 matthias 837: else
1.36 matthias 838: sc->sc_swflags = 0;
1.30 matthias 839:
1.64 chs 840: console = SCN_ISCONSOLE(ca->ca_addr);
841: if (console) {
842: sc->sc_isconsole = 1;
1.36 matthias 843: sc->sc_swflags |= SCN_SW_SOFTCAR; /* ignore carrier */
1.64 chs 844: }
1.30 matthias 845:
1.64 chs 846: ch_base = (volatile u_char *)ca->ca_addr;
847: duart_base = (volatile u_char *)(ca->ca_addr & ~0xf);
1.30 matthias 848:
1.64 chs 849: if (first) {
1.32 matthias 850: /* Probe DUART type */
851: s = spltty();
1.64 chs 852: if (console) {
1.32 matthias 853: ch_base[CH_CR] = CR_DIS_TX;
854: delay(5 * 10000);
855: }
856: ch_base[CH_CR] = CR_CMD_MR1;
857: RECOVER();
858: mr1 = ch_base[CH_MR];
859: mr2 = ch_base[CH_MR];
860: ch_base[CH_CR] = CR_CMD_MR1;
861: RECOVER();
862: ch_base[CH_MR] = 1;
863: ch_base[CH_MR] = 0;
864: ch_base[CH_CR] = CR_CMD_MR1;
865: RECOVER();
866: if (ch_base[CH_MR] == 1) {
867: /* MR 2 selected */
868: ch_base[CH_CR] = CR_CMD_MR0;
869: RECOVER();
870: /* if 2681, MR2 still selected */
871: ch_base[CH_MR] = 1;
872: ch_base[CH_CR] = CR_CMD_MR1;
873: RECOVER();
874: ch_base[CH_MR] = 0; /* MR1 */
875: ch_base[CH_MR] = 0; /* MR2 */
876: ch_base[CH_CR] = CR_CMD_MR0;
877: RECOVER();
878: /* if 2681, MR2 still selected */
879: if((ch_base[CH_MR] & 1) == 1) {
1.33 matthias 880: duart_type = "sc26c92";
1.36 matthias 881: scntype = SC26C92;
1.32 matthias 882: } else {
1.36 matthias 883: /* 2681 treats as MR1 Select */
884: ch_base[CH_CR] = CR_CMD_RTS_OFF;
1.32 matthias 885: RECOVER();
886: ch_base[CH_MR] = 1;
887: ch_base[CH_MR] = 0;
888: ch_base[CH_CR] = CR_CMD_RTS_OFF;
889: RECOVER();
890: if (ch_base[CH_MR] == 1) {
1.33 matthias 891: duart_type = "scn2681";
1.36 matthias 892: scntype = SCN2681;
1.32 matthias 893: } else {
1.36 matthias 894: duart_type = "scn2692";
895: scntype = SCN2692;
1.32 matthias 896: }
897: }
898: }
899:
900: /* If a 2681, the CR_CMD_MR0 is interpreted as a TX_RESET */
1.64 chs 901: if (console) {
1.32 matthias 902: ch_base[CH_CR] = CR_ENA_TX;
903: RECOVER();
904: }
905: ch_base[CH_CR] = CR_CMD_MR1;
906: RECOVER();
907: ch_base[CH_MR] = mr1;
908: ch_base[CH_MR] = mr2;
909: splx(s);
1.36 matthias 910:
1.30 matthias 911: /* Arg 0 is special, so we must pass "unit + 1" */
1.59 simonb 912: intrname = malloc(sizeof("scnXX"), M_DEVBUF, M_NOWAIT);
913: snprintf(intrname, sizeof("scnXX"), "scn%d", unit);
1.64 chs 914: intr_establish(scnints[duartno], scnintr, duart, intrname, IPL_TTY,
915: IPL_ZERO, LOW_LEVEL);
1.32 matthias 916:
1.33 matthias 917: printf("%c %s", delim, duart_type);
918: delim = ',';
1.30 matthias 919:
920: /*
921: * IPL_ZERO is the right priority for the rx interrupt.
922: * Only splhigh() should disable rxints.
923: */
1.59 simonb 924: intrname = malloc(sizeof("scnXXrx"), M_DEVBUF, M_NOWAIT);
925: snprintf(intrname, 8, "scn%drx", unit);
1.64 chs 926: intr_establish(ca->ca_irq >> 4, scnrxintr, duart, intrname, IPL_ZERO,
927: IPL_RTTY, LOW_LEVEL);
928:
929: duart->base = duart_base;
930: duart->type = scntype;
1.30 matthias 931: }
1.64 chs 932: /* Record channel, uart */
933: sc->sc_channel = channel;
1.36 matthias 934: sc->sc_chbase = ch_base;
1.30 matthias 935:
936: /* Initialize modem/interrupt bit masks */
937: if (channel == 0) {
938: sc->sc_op_rts = OP_RTSA;
939: sc->sc_op_dtr = OP_DTRA;
940: sc->sc_ip_cts = IP_CTSA;
941: sc->sc_ip_dcd = IP_DCDA;
942:
943: sc->sc_tx_int = INT_TXA;
944: } else {
945: sc->sc_op_rts = OP_RTSB;
946: sc->sc_op_dtr = OP_DTRB;
947: sc->sc_ip_cts = IP_CTSB;
948: sc->sc_ip_dcd = IP_DCDB;
949:
950: sc->sc_tx_int = INT_TXB;
951: }
952:
1.36 matthias 953: /* Initialize counters */
954: sc->sc_framing_errors = 0;
955: sc->sc_fifo_overruns = 0;
956: sc->sc_parity_errors = 0;
957: sc->sc_breaks = 0;
1.30 matthias 958:
1.64 chs 959: if (console) {
1.30 matthias 960: DELAY(5 * 10000); /* Let the output go out.... */
961: }
1.64 chs 962:
1.30 matthias 963: /*
964: * Set up the hardware to a base state, in particular:
965: * o reset transmitter and receiver
966: * o set speeds and configurations
967: * o receiver interrupts only (RxRDY and BREAK)
968: */
969:
970: s = spltty();
971: /* RTS off... */
972: SCN_OP_BIC(sc, sc->sc_op_rts); /* "istop" */
973:
974: ch_base[CH_CR] = CR_DIS_RX | CR_DIS_TX;
1.31 matthias 975: RECOVER();
1.30 matthias 976: ch_base[CH_CR] = CR_CMD_RESET_RX;
1.31 matthias 977: RECOVER();
1.30 matthias 978: ch_base[CH_CR] = CR_CMD_RESET_TX;
1.31 matthias 979: RECOVER();
1.30 matthias 980: ch_base[CH_CR] = CR_CMD_RESET_ERR;
1.31 matthias 981: RECOVER();
1.30 matthias 982: ch_base[CH_CR] = CR_CMD_RESET_BRK;
1.31 matthias 983: RECOVER();
1.30 matthias 984: ch_base[CH_CR] = CR_CMD_MR1;
1.31 matthias 985: RECOVER();
1.30 matthias 986:
987: /* No receiver control of RTS. */
988: ch_base[CH_MR] = 0;
989: ch_base[CH_MR] = 0;
990:
991: /* Initialize the uart structure if this is channel A. */
1.64 chs 992: if (first) {
1.30 matthias 993: /* Disable all interrupts. */
1.64 chs 994: duart_base[DU_IMR] = duart->imr = 0;
1.30 matthias 995:
996: /* Output port config */
1.64 chs 997: duart_base[DU_OPCR] = duart->opcr = 0;
1.30 matthias 998:
999: /* Speeds... */
1.64 chs 1000: duart->mode = 0;
1001:
1.36 matthias 1002: /*
1003: * Set initial speed to an illegal code that can be changed to
1004: * any other baud.
1005: */
1.64 chs 1006: duart->chan[0].icode = duart->chan[0].ocode = 0x2f;
1007: duart->chan[1].icode = duart->chan[1].ocode = 0x2f;
1008: duart->chan[0].ispeed = duart->chan[0].ospeed = 0;
1009: duart->chan[1].ispeed = duart->chan[1].ospeed = 0;
1010:
1011: duart->acr = 0;
1012: duart->acr |= ACR_CT_TCLK1; /* timer mode 1x clk */
1013: }
1014:
1015: if (channel == 0) {
1016: duart->acr |= ACR_DELTA_DCDA; /* Set CD int */
1.30 matthias 1017: } else {
1.64 chs 1018: duart->acr |= ACR_DELTA_DCDB; /* Set CD int */
1.30 matthias 1019: }
1.1 phil 1020:
1.30 matthias 1021: if (scnsir == -1) {
1022: /* software intr: calls tty code, hence IPL_TTY */
1.32 matthias 1023: scnsir = intr_establish(SOFTINT, scnsoft, NULL,
1024: "softscn", IPL_TTY, IPL_TTY, 0);
1.30 matthias 1025: }
1.1 phil 1026:
1.64 chs 1027: duart_base[DU_ACR] = (duart->mode & ACR_BRG) | duart->acr;
1.1 phil 1028:
1.64 chs 1029: if (console)
1.30 matthias 1030: speed = scnconsrate;
1031: else
1032: speed = scndefaultrate;
1033:
1.64 chs 1034: scn_config(unit, channel, speed, speed, MR1_PNONE | MR1_CS8, MR2_STOP1);
1035: if (console) {
1.54 gehenna 1036: maj = cdevsw_lookup_major(&scn_cdevsw);
1037: shutdownhook_establish(scncnreinit, (void *)makedev(maj, unit));
1.37 matthias 1038: /* Make sure console can do scncngetc */
1.64 chs 1039: duart_base[DU_OPSET] = channel ? (OP_RTSB | OP_DTRB) :
1040: (OP_RTSA | OP_DTRA);
1.37 matthias 1041: }
1.30 matthias 1042:
1043: /* Turn on the receiver and transmitters */
1044: ch_base[CH_CR] = CR_ENA_RX | CR_ENA_TX;
1045:
1046: /* Set up the interrupts. */
1.64 chs 1047: duart->imr |= INT_IP;
1.30 matthias 1048: scn_rxdisable(sc);
1049: splx(s);
1050:
1.36 matthias 1051: if (sc->sc_swflags) {
1052: printf("%c flags %d", delim, sc->sc_swflags);
1.33 matthias 1053: delim = ',';
1054: }
1.46 matthias 1055:
1.1 phil 1056: #ifdef KGDB
1.54 gehenna 1057: if (kgdb_dev == makedev(cdevsw_lookup_major(&scn_cdevsw), unit)) {
1.64 chs 1058: if (console)
1.36 matthias 1059: kgdb_dev = NODEV; /* can't debug over console port */
1.1 phil 1060: else {
1.30 matthias 1061: scninit(kgdb_dev, kgdb_rate);
1062: scn_rxenable(sc);
1.64 chs 1063: scn->sc_iskgdb = 1;
1064: kgdb_attach(scncngetc, scncnputc, kgdb_dev);
1.1 phil 1065: if (kgdb_debug_init) {
1.33 matthias 1066: printf("%c ", delim);
1.1 phil 1067: kgdb_connect(1);
1068: } else
1.33 matthias 1069: printf("%c kgdb enabled", delim);
1070: delim = ',';
1.1 phil 1071: }
1072: }
1073: #endif
1.30 matthias 1074: printf("\n");
1.1 phil 1075: }
1076:
1077: /* ARGSUSED */
1.30 matthias 1078: int
1079: scnopen(dev, flag, mode, p)
1.32 matthias 1080: dev_t dev;
1081: int flag;
1082: int mode;
1.30 matthias 1083: struct proc *p;
1.1 phil 1084: {
1.64 chs 1085: struct tty *tp;
1086: int unit = DEV_UNIT(dev);
1087: struct scn_softc *sc;
1.32 matthias 1088: int error = 0;
1089: int hwset = 0;
1090: int s;
1.7 phil 1091:
1.26 thorpej 1092: if (unit >= scn_cd.cd_ndevs)
1.16 phil 1093: return ENXIO;
1.30 matthias 1094: sc = SOFTC(unit);
1.16 phil 1095: if (!sc)
1096: return ENXIO;
1.7 phil 1097:
1.30 matthias 1098: s = spltty();
1.64 chs 1099: tp = sc->sc_tty;
1100: if (!tp) {
1101: tp = ttymalloc();
1102: sc->sc_tty = sc->sc_duart->chan[sc->sc_channel].tty = tp;
1.30 matthias 1103: tty_attach(tp);
1.64 chs 1104: }
1.16 phil 1105:
1.1 phil 1106: tp->t_oproc = scnstart;
1107: tp->t_param = scnparam;
1.32 matthias 1108: tp->t_hwiflow = scnhwiflow;
1.1 phil 1109: tp->t_dev = dev;
1.32 matthias 1110:
1.42 matthias 1111: if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
1.1 phil 1112: ttychars(tp);
1.7 phil 1113: tp->t_iflag = TTYDEF_IFLAG;
1114: tp->t_oflag = TTYDEF_OFLAG;
1.30 matthias 1115: tp->t_cflag = SCNDEF_CFLAG;
1.32 matthias 1116:
1117: sc->sc_rx_blocked = 0;
1118:
1.36 matthias 1119: if (sc->sc_swflags & SCN_SW_CLOCAL)
1.7 phil 1120: tp->t_cflag |= CLOCAL;
1.36 matthias 1121: if (sc->sc_swflags & SCN_SW_CRTSCTS)
1.30 matthias 1122: tp->t_cflag |= CCTS_OFLOW | CRTS_IFLOW;
1.7 phil 1123: tp->t_lflag = TTYDEF_LFLAG;
1.64 chs 1124: if (sc->sc_isconsole)
1.30 matthias 1125: tp->t_ispeed = tp->t_ospeed = scnconsrate;
1126: else
1127: tp->t_ispeed = tp->t_ospeed = scndefaultrate;
1.1 phil 1128: scnparam(tp, &tp->t_termios);
1129: ttsetwater(tp);
1130:
1131: /* Turn on DTR and RTS. */
1.30 matthias 1132: SCN_OP_BIS(sc, sc->sc_op_rts | sc->sc_op_dtr);
1133:
1.49 wiz 1134: /* enable receiver interrupts */
1.30 matthias 1135: scn_rxenable(sc);
1.32 matthias 1136: hwset = 1;
1.7 phil 1137:
1.30 matthias 1138: /* set carrier state; */
1.36 matthias 1139: if ((sc->sc_swflags & SCN_SW_SOFTCAR) || /* check ttyflags */
1140: SCN_DCD(sc) || /* check h/w */
1.30 matthias 1141: DEV_DIALOUT(dev))
1142: tp->t_state |= TS_CARR_ON;
1143: else
1144: tp->t_state &= ~TS_CARR_ON;
1.36 matthias 1145: } else {
1.65 kleink 1146: if (tp->t_state & TS_XCLUDE &&
1147: suser(p->p_ucred, &p->p_acflag) != 0) {
1.30 matthias 1148: splx(s);
1149: return (EBUSY);
1.36 matthias 1150: } else {
1.30 matthias 1151: if (DEV_DIALOUT(dev) && !SCN_DIALOUT(sc)) {
1152: /* dialout attempt while someone dialed in */
1153: splx(s);
1154: return (EBUSY);
1155: }
1.36 matthias 1156: }
1157: }
1.30 matthias 1158: if (DEV_DIALOUT(dev)) {
1159: /* dialout open and no one dialed in (see above) */
1160: SCN_SETDIALOUT(sc); /* mark line as dialed out */
1.1 phil 1161: }
1.30 matthias 1162: if (flag & O_NONBLOCK) {
1163: /* Non-blocking open
1164: *
1165: * If non-dialout open, and currenly opened for dialout you
1166: * lose.
1167: */
1168: if (!DEV_DIALOUT(dev) && SCN_DIALOUT(sc)) {
1169: splx(s);
1170: return EBUSY;
1171: }
1172: } else {
1173: /* Blocking open
1174: *
1175: * This used to be more compact (while loop with lots of nots)
1176: * but it was incomprehensible.
1.46 matthias 1177: *
1.30 matthias 1178: * "getty" is the classic case of a program that waits here...
1179: */
1180: for (;;) {
1181: if (SCN_DIALOUT(sc)) {
1182: /* Currently opened for dialout. */
1183: if (DEV_DIALOUT(dev))
1184: /* No need to wait if dialout open */
1185: break;
1186: /*
1187: * "getty" falls thru and waits while line
1188: * dialed out.
1189: */
1190: } else {
1191: /* Not currently opened for dialout. */
1192: if ((tp->t_cflag & CLOCAL) || /* "local" line? */
1193: (tp->t_state & TS_CARR_ON)) /* or carrier up */
1194: break; /* no (more) waiting */
1.36 matthias 1195: /*
1196: *"getty" on modem falls thru and waits for
1197: * carrier up
1198: */
1.30 matthias 1199: }
1200: error = ttysleep(tp, (caddr_t) & tp->t_rawq,
1.7 phil 1201: TTIPRI | PCATCH, ttopen, 0);
1202: if (error) {
1.30 matthias 1203: /* XXX should turn off chip if we're the only
1204: * waiter */
1205:
1206: /* XXX drop RTS too? -plb */
1207: /* XXX dialout state??? -plb */
1208: SCN_OP_BIC(sc, sc->sc_op_dtr);
1209: splx(s);
1.7 phil 1210: return error;
1211: }
1212: }
1.30 matthias 1213: }
1214: splx(s);
1215:
1.45 eeh 1216: error = (*tp->t_linesw->l_open) (dev, tp);
1.32 matthias 1217: if (error && hwset) {
1218: scn_rxdisable(sc);
1.30 matthias 1219: SCN_OP_BIC(sc, sc->sc_op_rts | sc->sc_op_dtr);
1220: }
1221: return (error);
1.1 phil 1222: }
1.30 matthias 1223:
1224:
1.1 phil 1225: /*ARGSUSED*/
1.30 matthias 1226: int
1.1 phil 1227: scnclose(dev, flag, mode, p)
1.32 matthias 1228: dev_t dev;
1229: int flag;
1230: int mode;
1.1 phil 1231: struct proc *p;
1232: {
1.64 chs 1233: int unit = DEV_UNIT(dev);
1234: struct scn_softc *sc = SOFTC(unit);
1235: struct tty *tp = sc->sc_tty;
1.1 phil 1236:
1.32 matthias 1237: if ((tp->t_state & TS_ISOPEN) == 0)
1.36 matthias 1238: return 0;
1.32 matthias 1239:
1.45 eeh 1240: (*tp->t_linesw->l_close) (tp, flag);
1.30 matthias 1241:
1.1 phil 1242: #ifdef KGDB
1243: /* do not disable interrupts if debugging */
1.54 gehenna 1244: if (kgdb_dev != makedev(cdevsw_lookup_major(&scn_cdevsw), unit))
1.1 phil 1245: #endif
1.30 matthias 1246: if ((tp->t_state & TS_ISOPEN) == 0) {
1247: scn_rxdisable(sc);
1248: }
1.36 matthias 1249: if ((tp->t_cflag & HUPCL) && (sc->sc_swflags & SCN_SW_SOFTCAR) == 0) {
1.30 matthias 1250: SCN_OP_BIC(sc, sc->sc_op_dtr);
1251: /* hold low for 1 second */
1252: (void) tsleep((caddr_t)sc, TTIPRI, ttclos, hz);
1.1 phil 1253: }
1.30 matthias 1254: SCN_CLRDIALOUT(sc);
1.5 phil 1255: ttyclose(tp);
1.30 matthias 1256:
1.6 phil 1257: #if 0
1.30 matthias 1258: if ((tp->t_state & TS_ISOPEN) == 0) {
1.6 phil 1259: ttyfree(tp);
1.36 matthias 1260: sc->sc_tty = (struct tty *) NULL;
1.6 phil 1261: }
1.5 phil 1262: #endif
1.30 matthias 1263:
1264: return (0);
1.1 phil 1265: }
1.30 matthias 1266:
1267: int
1.1 phil 1268: scnread(dev, uio, flag)
1.32 matthias 1269: dev_t dev;
1.1 phil 1270: struct uio *uio;
1.32 matthias 1271: int flag;
1.1 phil 1272: {
1.64 chs 1273: struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1274: struct tty *tp = sc->sc_tty;
1.1 phil 1275:
1.45 eeh 1276: return ((*tp->t_linesw->l_read) (tp, uio, flag));
1.1 phil 1277: }
1.30 matthias 1278:
1279: int
1.1 phil 1280: scnwrite(dev, uio, flag)
1.32 matthias 1281: dev_t dev;
1.1 phil 1282: struct uio *uio;
1.32 matthias 1283: int flag;
1.1 phil 1284: {
1.64 chs 1285: struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1286: struct tty *tp = sc->sc_tty;
1.1 phil 1287:
1.45 eeh 1288: return ((*tp->t_linesw->l_write) (tp, uio, flag));
1.47 scw 1289: }
1290:
1291: int
1292: scnpoll(dev, events, p)
1293: dev_t dev;
1294: int events;
1295: struct proc *p;
1296: {
1.64 chs 1297: struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1298: struct tty *tp = sc->sc_tty;
1.63 simonb 1299:
1.47 scw 1300: return ((*tp->t_linesw->l_poll)(tp, events, p));
1.1 phil 1301: }
1302:
1.16 phil 1303: struct tty *
1304: scntty(dev)
1.32 matthias 1305: dev_t dev;
1.16 phil 1306: {
1.64 chs 1307: struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1.16 phil 1308:
1.36 matthias 1309: return sc->sc_tty;
1.16 phil 1310: }
1311:
1.30 matthias 1312: /* Worker routines for interrupt processing */
1313: static __inline void
1314: dcd_int(sc, tp, new)
1315: struct scn_softc *sc;
1316: struct tty *tp;
1.32 matthias 1317: u_char new;
1.8 phil 1318: {
1.36 matthias 1319: if (sc->sc_swflags & SCN_SW_SOFTCAR)
1.30 matthias 1320: return;
1321:
1322: #if 0
1323: printf("scn%d: dcd_int ip %x SCN_DCD %x new %x ipcr %x\n",
1324: sc->unit,
1.36 matthias 1325: sc->sc_duart->base[DU_IP],
1.30 matthias 1326: SCN_DCD(sc),
1327: new,
1.36 matthias 1328: sc->sc_duart->base[DU_IPCR]
1.30 matthias 1329: );
1330: #endif
1331:
1332: /* XXX set some flag to have some lower (soft) int call line discipline? */
1.46 matthias 1333: if (!(*tp->t_linesw->l_modem) (tp, new == 0? 1: 0)) {
1.36 matthias 1334: SCN_OP_BIC(sc, sc->sc_op_rts | sc->sc_op_dtr);
1.32 matthias 1335: }
1.30 matthias 1336: }
1337:
1338: /*
1339: * Print out a ring or fifo overrun error message.
1340: */
1341: static void
1342: scnoverrun(unit, ptime, what)
1.32 matthias 1343: int unit;
1344: long *ptime;
1.66 ! chs 1345: const char *what;
1.30 matthias 1346: {
1347: if (*ptime != time.tv_sec) {
1348: *ptime = time.tv_sec;
1349: log(LOG_WARNING, "scn%d: %s overrun\n", unit, what);
1350: }
1.8 phil 1351: }
1352:
1.32 matthias 1353: /*
1354: * Try to block or unblock input using hardware flow-control.
1355: * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
1356: * if this function returns non-zero, the TS_TBLOCK flag will
1357: * be set or cleared according to the "stop" arg passed.
1358: */
1359: int
1360: scnhwiflow(tp, stop)
1361: struct tty *tp;
1362: int stop;
1363: {
1364: int unit = DEV_UNIT(tp->t_dev);
1365: struct scn_softc *sc = SOFTC(unit);
1.64 chs 1366: int s;
1.32 matthias 1367:
1.64 chs 1368: s = splrtty();
1.32 matthias 1369: if (!stop) {
1370: if (sc->sc_rbput - sc->sc_rbget - 1) {
1371: setsoftscn();
1372: }
1373: }
1374: splx(s);
1375: return 1;
1376: }
1377:
1.30 matthias 1378: static void
1.31 matthias 1379: scnintr(arg)
1380: void *arg;
1381: {
1.64 chs 1382: struct duart *duart = arg;
1383: struct scn_softc *sc0 = duart->chan[0].sc;
1384: struct scn_softc *sc1 = duart->chan[1].sc;
1.30 matthias 1385:
1.64 chs 1386: struct tty *tp0 = sc0->sc_tty;
1387: struct tty *tp1 = sc1->sc_tty;
1.30 matthias 1388:
1.32 matthias 1389: char rs_work;
1390: u_char rs_stat;
1391: u_char rs_ipcr;
1.30 matthias 1392:
1393: do {
1394: /* Loop to pick up ALL pending interrupts for device. */
1395: rs_work = FALSE;
1396: rs_stat = duart->base[DU_ISR];
1397:
1398: /* channel a */
1399: if (tp0 != NULL) {
1400: if ((rs_stat & INT_TXA) && (tp0->t_state & TS_BUSY)) {
1401: /* output char done. */
1402: tp0->t_state &= ~(TS_BUSY | TS_FLUSH);
1403:
1404: /* disable tx ints */
1.64 chs 1405: duart->imr &= ~sc0->sc_tx_int;
1406: duart->base[DU_IMR] = duart->imr;
1.1 phil 1407:
1.36 matthias 1408: if (sc0->sc_heldchanges) {
1409: scn_setchip(sc0);
1410: }
1.16 phil 1411:
1.46 matthias 1412: (*tp0->t_linesw->l_start) (tp0);
1.30 matthias 1413: rs_work = TRUE;
1414: }
1415: }
1416: /* channel b */
1417: if (tp1 != NULL) {
1418: if ((rs_stat & INT_TXB) && (tp1->t_state & TS_BUSY)) {
1419: /* output char done. */
1420: tp1->t_state &= ~(TS_BUSY | TS_FLUSH);
1421:
1422: /* disable tx ints */
1.64 chs 1423: duart->imr &= ~sc1->sc_tx_int;
1424: duart->base[DU_IMR] = duart->imr;
1.16 phil 1425:
1.36 matthias 1426: if (sc1->sc_heldchanges) {
1427: scn_setchip(sc1);
1428: }
1.1 phil 1429:
1.46 matthias 1430: (*tp1->t_linesw->l_start) (tp1);
1.30 matthias 1431: rs_work = TRUE;
1432: }
1433: }
1434: if (rs_stat & INT_IP) {
1435: rs_work = TRUE;
1436: rs_ipcr = duart->base[DU_IPCR];
1.1 phil 1437:
1.31 matthias 1438: if (rs_ipcr & IPCR_DELTA_DCDA && tp0 != NULL) {
1.30 matthias 1439: dcd_int(sc0, tp0, rs_ipcr & IPCR_DCDA);
1440: }
1.31 matthias 1441: if (rs_ipcr & IPCR_DELTA_DCDB && tp1 != NULL) {
1.30 matthias 1442: dcd_int(sc1, tp1, rs_ipcr & IPCR_DCDB);
1443: }
1444: }
1445: } while (rs_work);
1446: }
1.1 phil 1447:
1.30 matthias 1448: /*
1449: * Handle rxrdy/ffull interrupt: QUICKLY poll both channels (checking
1450: * status first) and stash data in a ring buffer. Ring buffer scheme
1451: * borowed from sparc/zs.c requires NO interlock on data!
1452: *
1453: * This interrupt should NOT be included in spltty() mask since it
1454: * invokes NO tty code! The whole point is to allow tty input as much
1455: * of the time as possible, while deferring "heavy" character
1456: * processing until later.
1457: *
1458: * see scn.hw.README and scnsoft() for more info.
1459: *
1460: * THIS ROUTINE SHOULD BE KEPT AS CLEAN AS POSSIBLE!!
1461: * IT'S A CANDIDATE FOR RECODING IN ASSEMBLER!!
1462: */
1.36 matthias 1463: static __inline int
1.64 chs 1464: scn_rxintr(struct scn_softc *sc)
1.32 matthias 1465: {
1.64 chs 1466: char sr;
1467: int i, n;
1.32 matthias 1468: int work;
1.1 phil 1469:
1.32 matthias 1470: work = 0;
1471: i = sc->sc_rbput;
1472: while (work <= 10) {
1473: #define SCN_GETCH(SC) \
1.36 matthias 1474: sr = (SC)->sc_chbase[CH_SR]; \
1.32 matthias 1475: if ((sr & SR_RX_RDY) == 0) \
1476: break; \
1477: if (sr & (SR_PARITY | SR_FRAME | SR_BREAK | SR_OVERRUN)) \
1478: goto exception; \
1479: work++; \
1.36 matthias 1480: (SC)->sc_rbuf[i++ & SCN_RING_MASK] = (SC)->sc_chbase[CH_DAT]
1.32 matthias 1481:
1482: SCN_GETCH(sc); SCN_GETCH(sc); SCN_GETCH(sc);
1.36 matthias 1483: /* XXX more here if 26C92? -plb */
1.32 matthias 1484: continue;
1485: exception:
1.30 matthias 1486: #if defined(DDB)
1.64 chs 1487: if (sc->sc_isconsole && (sr & SR_BREAK)) {
1.32 matthias 1488: Debugger();
1.36 matthias 1489: sr = sc->sc_chbase[CH_SR];
1.32 matthias 1490: }
1.30 matthias 1491: #endif
1492: #if defined(KGDB)
1.64 chs 1493: if (sc->sc_iskgdb && (sr & SR_RX_RDY)) {
1.32 matthias 1494: kgdb_connect(1);
1.36 matthias 1495: sr = sc->sc_chbase[CH_SR];
1.32 matthias 1496: }
1.30 matthias 1497: #endif
1498: work++;
1.36 matthias 1499: sc->sc_rbuf[i++ & SCN_RING_MASK] = (sr << 8) | sc->sc_chbase[CH_DAT];
1500: sc->sc_chbase[CH_CR] = CR_CMD_RESET_ERR; /* resets break? */
1.31 matthias 1501: RECOVER();
1.30 matthias 1502: }
1.32 matthias 1503: /*
1504: * If ring is getting too full, try to block input.
1505: */
1506: n = i - sc->sc_rbget;
1507: if (sc->sc_rbhiwat && (n > sc->sc_rbhiwat)) {
1508: /* If not CRTSCTS sc_rbhiwat is such that this
1.39 matthias 1509: * never happens.
1510: * Clear RTS
1.32 matthias 1511: */
1.39 matthias 1512: SCN_OP_BIC(sc, sc->sc_op_rts);
1.32 matthias 1513: sc->sc_rx_blocked = 1;
1514: }
1515: sc->sc_rbput = i;
1516:
1517: return work;
1518: }
1519:
1520: static void
1521: scnrxintr(arg)
1522: void *arg;
1523: {
1.64 chs 1524: struct duart *duart = arg;
1.32 matthias 1525: int work = 0;
1.1 phil 1526:
1.64 chs 1527: work += scn_rxintr(duart->chan[0].sc);
1528: work += scn_rxintr(duart->chan[1].sc);
1.30 matthias 1529: if (work > 0) {
1530: setsoftscn(); /* trigger s/w intr */
1531: #ifdef SCN_TIMING
1532: microtime(&tstart);
1533: #endif
1.1 phil 1534: }
1535: }
1536:
1.30 matthias 1537: /*
1538: * Here on soft interrupt (at spltty) to empty ring buffers.
1539: *
1.49 wiz 1540: * Dave's original scheme was to use the DUART receiver timeout
1.30 matthias 1541: * interrupt. This requires 2692's (which my board doesn't have), and
1542: * I also liked the idea of using the C/T to generate alternate and/or
1543: * arbitrary bauds. -plb
1544: *
1545: * The ringbuffer code comes from Chris Torek's SPARC 44bsd zs driver
1546: * (hence the LBL notice on top of this file), DOES NOT require
1547: * interlocking with interrupt levels!
1548: *
1.50 wiz 1549: * The 44bsd sparc/zs driver reads the ring buffer from a separate
1.30 matthias 1550: * zssoftint, while the SunOS 4.x zs driver appears to use
1551: * timeout()'s. timeouts seem to be too slow to deal with high data
1552: * rates. I know, I tried them.
1553: * -plb.
1554: */
1555: static void
1556: scnsoft(arg)
1.32 matthias 1557: void *arg;
1.30 matthias 1558: {
1.64 chs 1559: int s, unit;
1.30 matthias 1560: #ifdef SCN_TIMING
1561: struct timeval tend;
1562: u_long t;
1563:
1564: microtime(&tend);
1565: t = (tend.tv_sec - tstart.tv_sec) * 1000000 + (tend.tv_usec - tstart.tv_usec);
1566: t = (t + tick / 20) / (tick / 10);
1567: if (t >= NJITTER - 1) {
1568: t = NJITTER - 1;
1569: }
1570: scn_jitter[t]++;
1.1 phil 1571: #endif
1.16 phil 1572:
1.30 matthias 1573: for (unit = 0; unit < scn_cd.cd_ndevs; unit++) {
1.64 chs 1574: struct scn_softc *sc;
1575: struct tty *tp;
1576: int n, get;
1.16 phil 1577:
1.30 matthias 1578: sc = SOFTC(unit);
1.36 matthias 1579: if (sc == NULL) {
1.34 matthias 1580: continue;
1.36 matthias 1581: }
1582: tp = sc->sc_tty;
1.30 matthias 1583: #ifdef KGDB
1584: if (tp == NULL) {
1585: sc->sc_rbget = sc->sc_rbput;
1586: continue;
1587: }
1588: #endif
1.32 matthias 1589: if (tp == NULL || tp->t_state & TS_TBLOCK) {
1590: continue;
1591: }
1592:
1593:
1.30 matthias 1594: get = sc->sc_rbget;
1.1 phil 1595:
1.30 matthias 1596: /* NOTE: fetch from rbput is atomic */
1597: while (get != (n = sc->sc_rbput)) {
1598: /*
1.36 matthias 1599: * Compute the number of interrupts in the receive ring.
1600: * If the count is overlarge, we lost some events, and
1601: * must advance to the first valid one. It may get
1602: * overwritten if more data are arriving, but this is
1603: * too expensive to check and gains nothing (we already
1604: * lost out; all we can do at this point is trade one
1605: * kind of loss for another).
1606: */
1.30 matthias 1607: n -= get;
1608: if (n > SCN_RING_SIZE) {
1609: scnoverrun(unit, &sc->sc_rotime, "ring");
1610: get += n - SCN_RING_SIZE;
1611: n = SCN_RING_SIZE;
1.36 matthias 1612: sc->sc_ring_overruns++;
1.30 matthias 1613: }
1614: while (--n >= 0) {
1.64 chs 1615: int c, sr;
1.1 phil 1616:
1.32 matthias 1617: if (tp->t_state & TS_TBLOCK) {
1618: sc->sc_rbget = get;
1619: goto done;
1620: }
1.30 matthias 1621: /* Race to keep ahead of incoming interrupts. */
1622: c = sc->sc_rbuf[get++ & SCN_RING_MASK];
1.1 phil 1623:
1.30 matthias 1624: sr = c >> 8; /* extract status */
1625: c &= 0xff; /* leave just character */
1.19 phil 1626:
1.30 matthias 1627: if (sr & SR_OVERRUN) {
1628: scnoverrun(unit, &sc->sc_fotime, "fifo");
1.36 matthias 1629: sc->sc_fifo_overruns++;
1.30 matthias 1630: }
1.36 matthias 1631: if (sr & SR_PARITY) {
1.30 matthias 1632: c |= TTY_PE;
1.36 matthias 1633: sc->sc_parity_errors++;
1634: }
1635: if (sr & SR_FRAME) {
1.30 matthias 1636: c |= TTY_FE;
1.36 matthias 1637: sc->sc_framing_errors++;
1638: }
1.30 matthias 1639: if (sr & SR_BREAK) {
1640: #if 0
1641: /*
1642: * See DDB_CHECK() comments in
1643: * scnrxintr()
1644: */
1.64 chs 1645: if (sc->sc_isconsole)
1.30 matthias 1646: Debugger();
1.21 phil 1647: #endif
1.30 matthias 1648: c = TTY_FE | 0;
1.36 matthias 1649: sc->sc_breaks++;
1.21 phil 1650: }
1.45 eeh 1651: (*tp->t_linesw->l_rint) (c, tp);
1.32 matthias 1652:
1653: if (sc->sc_rx_blocked && n < SCN_RING_THRESH) {
1.64 chs 1654: s = splrtty();
1.32 matthias 1655: sc->sc_rx_blocked = 0;
1.39 matthias 1656: SCN_OP_BIS(sc, sc->sc_op_rts);
1.32 matthias 1657: splx(s);
1658: }
1.46 matthias 1659:
1.19 phil 1660: }
1.30 matthias 1661: sc->sc_rbget = get;
1.19 phil 1662: }
1.53 simonb 1663: done: ;
1.1 phil 1664: }
1665: }
1666:
1.30 matthias 1667: /* Convert TIOCM_xxx bits to output port bits. */
1668: static unsigned char
1669: opbits(sc, tioc_bits)
1670: struct scn_softc *sc;
1.32 matthias 1671: int tioc_bits;
1.30 matthias 1672: {
1673: return ((((tioc_bits) & TIOCM_DTR) ? sc->sc_op_dtr : 0) |
1674: (((tioc_bits) & TIOCM_RTS) ? sc->sc_op_rts : 0));
1675: }
1.1 phil 1676:
1.30 matthias 1677: int
1.3 phil 1678: scnioctl(dev, cmd, data, flag, p)
1.32 matthias 1679: dev_t dev;
1.37 matthias 1680: u_long cmd;
1.30 matthias 1681: caddr_t data;
1.32 matthias 1682: int flag;
1.3 phil 1683: struct proc *p;
1.1 phil 1684: {
1.64 chs 1685: int unit = DEV_UNIT(dev);
1686: struct scn_softc *sc = SOFTC(unit);
1687: struct tty *tp = sc->sc_tty;
1688: int error;
1.5 phil 1689:
1.45 eeh 1690: error = (*tp->t_linesw->l_ioctl) (tp, cmd, data, flag, p);
1.52 atatat 1691: if (error != EPASSTHROUGH)
1.1 phil 1692: return (error);
1.52 atatat 1693:
1.3 phil 1694: error = ttioctl(tp, cmd, data, flag, p);
1.52 atatat 1695: if (error != EPASSTHROUGH)
1.1 phil 1696: return (error);
1697:
1698: switch (cmd) {
1699: case TIOCSBRK:
1.36 matthias 1700: sc->sc_chbase[CH_CR] = CR_CMD_START_BRK;
1.1 phil 1701: break;
1702:
1703: case TIOCCBRK:
1.36 matthias 1704: sc->sc_chbase[CH_CR] = CR_CMD_STOP_BRK;
1.1 phil 1705: break;
1706:
1707: case TIOCSDTR:
1.30 matthias 1708: SCN_OP_BIS(sc, sc->sc_op_dtr | sc->sc_op_rts);
1.1 phil 1709: break;
1710:
1711: case TIOCCDTR:
1.30 matthias 1712: SCN_OP_BIC(sc, sc->sc_op_dtr | sc->sc_op_rts);
1.1 phil 1713: break;
1714:
1.30 matthias 1715: case TIOCMSET: {
1716: int s;
1717: unsigned char sbits, cbits;
1718:
1719: /* set bits */
1720: sbits = opbits(sc, *(int *) data);
1721:
1722: /* get bits to clear */
1723: cbits = ~sbits & (sc->sc_op_dtr | sc->sc_op_rts);
1724:
1725: s = spltty();
1726: if (sbits) {
1727: SCN_OP_BIS(sc, sbits);
1728: }
1729: if (cbits) {
1730: SCN_OP_BIC(sc, cbits);
1731: }
1732: splx(s);
1733: break;
1734: }
1.1 phil 1735:
1736: case TIOCMBIS:
1.30 matthias 1737: SCN_OP_BIS(sc, opbits(sc, *(int *) data));
1.1 phil 1738: break;
1739:
1740: case TIOCMBIC:
1.30 matthias 1741: SCN_OP_BIC(sc, opbits(sc, *(int *) data));
1.1 phil 1742: break;
1743:
1.30 matthias 1744: case TIOCMGET: {
1745: int bits;
1746: unsigned char ip, op;
1747:
1748: /* s = spltty(); */
1.36 matthias 1749: ip = sc->sc_duart->base[DU_IP];
1.30 matthias 1750: /*
1751: * XXX sigh; cannot get op current state!! even if
1752: * maintained in private, RTS is done in h/w!!
1753: */
1754: op = 0;
1755: /* splx(s); */
1756:
1757: bits = 0;
1758: if (ip & sc->sc_ip_dcd)
1759: bits |= TIOCM_CD;
1760: if (ip & sc->sc_ip_cts)
1761: bits |= TIOCM_CTS;
1762:
1763: #if 0
1764: if (op & sc->sc_op_dtr)
1765: bits |= TIOCM_DTR;
1766: if (op & sc->sc_op_rts)
1767: bits |= TIOCM_RTS;
1768: #endif
1769:
1770: *(int *) data = bits;
1771: break;
1772: }
1773:
1774: case TIOCGFLAGS:{
1775: int bits = 0;
1.1 phil 1776:
1.36 matthias 1777: if (sc->sc_swflags & SCN_SW_SOFTCAR)
1.30 matthias 1778: bits |= TIOCFLAG_SOFTCAR;
1.36 matthias 1779: if (sc->sc_swflags & SCN_SW_CLOCAL)
1.30 matthias 1780: bits |= TIOCFLAG_CLOCAL;
1.36 matthias 1781: if (sc->sc_swflags & SCN_SW_CRTSCTS)
1.30 matthias 1782: bits |= TIOCFLAG_CRTSCTS;
1.36 matthias 1783: if (sc->sc_swflags & SCN_SW_MDMBUF)
1.30 matthias 1784: bits |= TIOCFLAG_MDMBUF;
1.8 phil 1785:
1.30 matthias 1786: *(int *) data = bits;
1787: break;
1788: }
1789: case TIOCSFLAGS:{
1790: int userbits, driverbits = 0;
1.8 phil 1791:
1.30 matthias 1792: error = suser(p->p_ucred, &p->p_acflag);
1793: if (error != 0)
1794: return (EPERM);
1795:
1796: userbits = *(int *) data;
1797: if (userbits & TIOCFLAG_SOFTCAR)
1798: driverbits |= SCN_SW_SOFTCAR;
1799: if (userbits & TIOCFLAG_CLOCAL)
1800: driverbits |= SCN_SW_CLOCAL;
1801: if (userbits & TIOCFLAG_CRTSCTS)
1802: driverbits |= SCN_SW_CRTSCTS;
1803: if (userbits & TIOCFLAG_MDMBUF)
1804: driverbits |= SCN_SW_MDMBUF;
1805:
1.36 matthias 1806: sc->sc_swflags = driverbits;
1.8 phil 1807:
1.30 matthias 1808: break;
1809: }
1.8 phil 1810:
1.1 phil 1811: default:
1.52 atatat 1812: return (EPASSTHROUGH);
1.1 phil 1813: }
1814: return (0);
1815: }
1816:
1.30 matthias 1817: int
1.1 phil 1818: scnparam(tp, t)
1.30 matthias 1819: struct tty *tp;
1820: struct termios *t;
1.1 phil 1821: {
1.32 matthias 1822: int cflag = t->c_cflag;
1823: int unit = DEV_UNIT(tp->t_dev);
1824: char mr1, mr2;
1825: int error;
1.30 matthias 1826: struct scn_softc *sc = SOFTC(unit);
1827:
1828: /* Is this a hang up? */
1829: if (t->c_ospeed == B0) {
1830: SCN_OP_BIC(sc, sc->sc_op_dtr);
1831: /* leave DTR down. see comment in scnclose() -plb */
1832: return (0);
1833: }
1834: mr1 = mr2 = 0;
1835:
1836: /* Parity? */
1837: if (cflag & PARENB) {
1838: if ((cflag & PARODD) == 0)
1839: mr1 |= MR1_PEVEN;
1840: else
1841: mr1 |= MR1_PODD;
1842: } else
1843: mr1 |= MR1_PNONE;
1844:
1845: /* Stop bits. */
1846: if (cflag & CSTOPB)
1847: mr2 |= MR2_STOP2;
1.1 phil 1848: else
1.30 matthias 1849: mr2 |= MR2_STOP1;
1850:
1851: /* Data bits. */
1852: switch (cflag & CSIZE) {
1853: case CS5:
1.36 matthias 1854: mr1 |= MR1_CS5;
1.30 matthias 1855: break;
1856: case CS6:
1.36 matthias 1857: mr1 |= MR1_CS6;
1.30 matthias 1858: break;
1859: case CS7:
1.36 matthias 1860: mr1 |= MR1_CS7;
1.30 matthias 1861: break;
1862: case CS8:
1863: default:
1.36 matthias 1864: mr1 |= MR1_CS8;
1.30 matthias 1865: break;
1866: }
1.1 phil 1867:
1.30 matthias 1868: if (cflag & CCTS_OFLOW)
1869: mr2 |= MR2_TXCTS;
1.1 phil 1870:
1.32 matthias 1871: if (cflag & CRTS_IFLOW) {
1.39 matthias 1872: mr1 |= MR1_RXRTS;
1.32 matthias 1873: sc->sc_rbhiwat = SCN_RING_HIWAT;
1874: } else {
1875: sc->sc_rbhiwat = 0;
1876: }
1.30 matthias 1877:
1.64 chs 1878: error = scn_config(unit, sc->sc_channel, t->c_ispeed, t->c_ospeed, mr1, mr2);
1.30 matthias 1879:
1880: /* If successful, copy to tty */
1881: if (!error) {
1882: tp->t_ispeed = t->c_ispeed;
1883: tp->t_ospeed = t->c_ospeed;
1884: tp->t_cflag = cflag;
1885: }
1886: return (error);
1.1 phil 1887: }
1.3 phil 1888:
1.30 matthias 1889: void
1.1 phil 1890: scnstart(tp)
1.30 matthias 1891: struct tty *tp;
1.1 phil 1892: {
1.32 matthias 1893: int s, c;
1894: int unit = DEV_UNIT(tp->t_dev);
1.30 matthias 1895: struct scn_softc *sc = SOFTC(unit);
1896:
1.1 phil 1897: s = spltty();
1.30 matthias 1898: if (tp->t_state & (TS_BUSY | TS_TTSTOP))
1.1 phil 1899: goto out;
1.30 matthias 1900: if (tp->t_outq.c_cc <= tp->t_lowat) {
1901: if (tp->t_state & TS_ASLEEP) {
1902: tp->t_state &= ~TS_ASLEEP;
1903: wakeup((caddr_t) & tp->t_outq);
1904: }
1905: if (tp->t_outq.c_cc == 0) /* plb 11/8/95 - from
1906: * isa/com.c */
1907: goto out;
1908: selwakeup(&tp->t_wsel);
1909: }
1.7 phil 1910: tp->t_state |= TS_BUSY;
1.39 matthias 1911:
1912: while (sc->sc_chbase[CH_SR] & SR_TX_RDY) {
1913: if ((c = getc(&tp->t_outq)) == -1)
1914: break;
1.36 matthias 1915: sc->sc_chbase[CH_DAT] = c;
1.39 matthias 1916: }
1917: sc->sc_duart->base[DU_IMR] = (sc->sc_duart->imr |= sc->sc_tx_int);
1.30 matthias 1918:
1.1 phil 1919: out:
1920: splx(s);
1921: }
1.30 matthias 1922:
1.1 phil 1923: /*
1924: * Stop output on a line.
1925: */
1926: /*ARGSUSED*/
1.27 mycroft 1927: void
1.1 phil 1928: scnstop(tp, flag)
1.30 matthias 1929: struct tty *tp;
1.32 matthias 1930: int flag;
1.1 phil 1931: {
1.64 chs 1932: int s;
1.1 phil 1933:
1.64 chs 1934: s = spltty();
1.1 phil 1935: if (tp->t_state & TS_BUSY) {
1.30 matthias 1936: if ((tp->t_state & TS_TTSTOP) == 0)
1.1 phil 1937: tp->t_state |= TS_FLUSH;
1938: }
1939: splx(s);
1940: }
1.30 matthias 1941:
1.1 phil 1942: /*
1.30 matthias 1943: * Following are all routines needed for SCN to act as console.
1.1 phil 1944: */
1.30 matthias 1945: #ifdef VERYLOWDEBUG
1946: /* So the kernel can write in unmapped mode! */
1947: extern int _mapped;
1948: #define SCN_BASE (_mapped ? SCN_FIRST_MAP_ADR : SCN_FIRST_ADR)
1949: #else
1950: #define SCN_BASE (SCN_FIRST_MAP_ADR)
1951: #endif
1952:
1.64 chs 1953: #define DUADDR() (u_char *)(SCN_BASE + SCN_CONSDUART * DUART_SZ)
1954: #define CHADDR() (u_char *)(SCN_BASE + \
1955: (SCN_CONSDUART * 2 + SCN_CONSCHAN) * CH_SZ)
1.1 phil 1956:
1.44 matthias 1957: void
1.1 phil 1958: scncnprobe(cp)
1959: struct consdev *cp;
1960: {
1961: /* initialize required fields */
1.54 gehenna 1962: cp->cn_dev = makedev(cdevsw_lookup_major(&scn_cdevsw), SCN_CONSOLE);
1.1 phil 1963: cp->cn_pri = CN_NORMAL;
1964: }
1965:
1.30 matthias 1966: void
1967: scncnreinit(v)
1.32 matthias 1968: void *v;
1.1 phil 1969: {
1.64 chs 1970: volatile u_char *du_base = DUADDR();
1.1 phil 1971:
1.64 chs 1972: du_base[DU_OPSET] = SCN_CONSCHAN ? (OP_RTSB | OP_DTRB) : (OP_RTSA | OP_DTRA);
1.1 phil 1973: }
1974:
1.30 matthias 1975: void
1976: scncninit(cp)
1977: struct consdev *cp;
1.1 phil 1978: {
1.30 matthias 1979: scninit(cp->cn_dev, scnconsrate);
1.1 phil 1980: }
1981:
1.30 matthias 1982: /* Used by scncninit and kgdb startup. */
1.1 phil 1983: int
1.30 matthias 1984: scninit(dev, rate)
1.32 matthias 1985: dev_t dev;
1986: int rate;
1.30 matthias 1987: {
1.64 chs 1988: volatile u_char *du_base = DUADDR();
1.32 matthias 1989: int unit = DEV_UNIT(dev);
1.30 matthias 1990:
1.64 chs 1991: du_base[DU_OPSET] = SCN_CONSCHAN ? (OP_RTSB | OP_DTRB) : (OP_RTSA | OP_DTRA);
1992: scn_config(unit, SCN_CONSCHAN, rate, rate, MR1_PNONE | MR1_CS8, MR2_STOP1);
1.30 matthias 1993: return (0);
1.1 phil 1994: }
1.5 phil 1995:
1996: /*
1997: * Console kernel input character routine.
1998: */
1.30 matthias 1999: int
1.64 chs 2000: scncngetc(void *arg)
1.30 matthias 2001: {
1.64 chs 2002: volatile u_char *ch_base = CHADDR();
1.32 matthias 2003: char c;
1.64 chs 2004: int s;
1.30 matthias 2005:
1.64 chs 2006: s = spltty();
2007:
2008: while ((ch_base[CH_SR] & SR_RX_RDY) == 0)
2009: ;
1.30 matthias 2010: c = ch_base[CH_DAT];
2011:
2012: splx(s);
2013: return c;
2014: }
1.5 phil 2015:
1.30 matthias 2016: /* The pc532 does not turn off console polling. */
2017: void
2018: scncnpollc(dev, on)
1.32 matthias 2019: dev_t dev;
2020: int on;
1.5 phil 2021: {
1.15 phil 2022: }
2023:
1.5 phil 2024: /*
2025: * Console kernel output character routine.
2026: */
1.30 matthias 2027: void
1.64 chs 2028: scncnputc(void *arg, int c)
1.30 matthias 2029: {
1.64 chs 2030: volatile u_char *ch_base = CHADDR();
2031: volatile u_char *du_base = DUADDR();
2032: int s;
2033:
2034: s = spltty();
1.30 matthias 2035:
2036: if (c == '\n')
1.64 chs 2037: scncnputc(arg, '\r');
1.30 matthias 2038:
1.64 chs 2039: while ((ch_base[CH_SR] & SR_TX_RDY) == 0)
2040: ;
1.30 matthias 2041: ch_base[CH_DAT] = c;
1.64 chs 2042: while ((ch_base[CH_SR] & SR_TX_RDY) == 0)
2043: ;
1.30 matthias 2044: du_base[DU_ISR];
1.5 phil 2045:
1.30 matthias 2046: splx(s);
1.5 phil 2047: }
CVSweb <webmaster@jp.NetBSD.org>