|
|
1.1 root 1: /*
2: * Copyright (c) 1988 University of Utah.
3: * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4: * All rights reserved.
5: *
6: * This code is derived from software contributed to Berkeley by
7: * the Systems Programming Group of the University of Utah Computer
8: * Science Department.
9: *
10: * Redistribution is only permitted until one year after the first shipment
11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
12: * binary forms are permitted provided that: (1) source distributions retain
13: * this entire copyright notice and comment, and (2) distributions including
14: * binaries display the following acknowledgement: This product includes
15: * software developed by the University of California, Berkeley and its
16: * contributors'' in the documentation or other materials provided with the
17: * distribution and in all advertising materials mentioning features or use
18: * of this software. Neither the name of the University nor the names of
19: * its contributors may be used to endorse or promote products derived from
20: * this software without specific prior written permission.
21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24: *
25: * from: $Hdr: dcm.c 1.17 89/10/01$
26: *
27: * @(#)dcm.c 7.8 (Berkeley) 6/30/90
28: */
29:
30: /*
31: * TODO:
32: * Timeouts
33: * Test console/kgdb support.
34: */
35:
36: #include "dcm.h"
37: #if NDCM > 0
38: /*
39: * 98642/MUX
40: */
41: #include "param.h"
42: #include "systm.h"
43: #include "ioctl.h"
44: #include "tty.h"
45: #include "user.h"
46: #include "conf.h"
47: #include "file.h"
48: #include "uio.h"
49: #include "kernel.h"
50: #include "syslog.h"
51: #include "time.h"
52:
53: #include "device.h"
54: #include "dcmreg.h"
55: #include "machine/cpu.h"
56: #include "machine/isr.h"
57:
58: #ifndef DEFAULT_BAUD_RATE
59: #define DEFAULT_BAUD_RATE 9600
60: #endif
61:
62: int ttrstrt();
63: int dcmprobe(), dcmstart(), dcmintr(), dcmparam();
64:
65: struct driver dcmdriver = {
66: dcmprobe, "dcm",
67: };
68:
69: #define NDCMLINE (NDCM*4)
70:
71: struct tty dcm_tty[NDCMLINE];
72: char mcndlast[NDCMLINE]; /* XXX last modem status for line */
73: int ndcm = NDCMLINE;
74:
75: int dcm_active;
76: int dcmsoftCAR[NDCM];
77: struct dcmdevice *dcm_addr[NDCM];
78: struct isr dcmisr[NDCM];
79:
80: struct speedtab dcmspeedtab[] = {
81: 0, BR_0,
82: 50, BR_50,
83: 75, BR_75,
84: 110, BR_110,
85: 134, BR_134,
86: 150, BR_150,
87: 300, BR_300,
88: 600, BR_600,
89: 1200, BR_1200,
90: 1800, BR_1800,
91: 2400, BR_2400,
92: 4800, BR_4800,
93: 9600, BR_9600,
94: 19200, BR_19200,
95: 38400, BR_38400,
96: -1, -1
97: };
98:
99: /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
100: #define DCM_USPERCH(s) (10000000 / (s))
101:
102: /*
103: * Per board interrupt scheme. 16.7ms is the polling interrupt rate
104: * (16.7ms is about 550 buad, 38.4k is 72 chars in 16.7ms).
105: */
106: #define DIS_TIMER 0
107: #define DIS_PERCHAR 1
108: #define DIS_RESET 2
109:
110: int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
111: int dcminterval = 5; /* interval (secs) between checks */
112: struct dcmischeme {
113: int dis_perchar; /* non-zero if interrupting per char */
114: long dis_time; /* last time examined */
115: int dis_intr; /* recv interrupts during last interval */
116: int dis_char; /* characters read during last interval */
117: } dcmischeme[NDCM];
118:
119: /*
120: * Console support
121: */
122: int dcmconsole = -1;
123: int dcmdefaultrate = DEFAULT_BAUD_RATE;
124: int dcmconbrdbusy = 0;
125: extern struct tty *constty;
126:
127: #ifdef KGDB
128: /*
129: * Kernel GDB support
130: */
131: extern int kgdb_dev;
132: extern int kgdb_rate;
133: extern int kgdb_debug_init;
134: #endif
135:
136: /* #define IOSTATS */
137:
138: #ifdef DEBUG
139: int dcmdebug = 0x00;
140: #define DDB_SIOERR 0x01
141: #define DDB_PARAM 0x02
142: #define DDB_INPUT 0x04
143: #define DDB_OUTPUT 0x08
144: #define DDB_INTR 0x10
145: #define DDB_IOCTL 0x20
146: #define DDB_INTSCHM 0x40
147: #define DDB_MODEM 0x80
148: #define DDB_OPENCLOSE 0x100
149: #endif
150:
151: #ifdef IOSTATS
152: #define DCMRBSIZE 94
153: #define DCMXBSIZE 24
154:
155: struct dcmstats {
156: long xints; /* # of xmit ints */
157: long xchars; /* # of xmit chars */
158: long xempty; /* times outq is empty in dcmstart */
159: long xrestarts; /* times completed while xmitting */
160: long rints; /* # of recv ints */
161: long rchars; /* # of recv chars */
162: long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
163: long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
164: } dcmstats[NDCM];
165: #endif
166:
167: #define UNIT(x) minor(x)
168: #define BOARD(x) (((x) >> 2) & 0x3f)
169: #define PORT(x) ((x) & 3)
170: #define MKUNIT(b,p) (((b) << 2) | (p))
171:
172: dcmprobe(hd)
173: register struct hp_device *hd;
174: {
175: register struct dcmdevice *dcm;
176: register int i;
177: register int timo = 0;
178: int s, brd, isconsole;
179:
180: dcm = (struct dcmdevice *)hd->hp_addr;
181: if ((dcm->dcm_rsid & 0x1f) != DCMID)
182: return (0);
183: brd = hd->hp_unit;
184: isconsole = (brd == BOARD(dcmconsole));
185: /*
186: * XXX selected console device (CONSUNIT) as determined by
187: * dcmcnprobe does not agree with logical numbering imposed
188: * by the config file (i.e. lowest address DCM is not unit
189: * CONSUNIT). Don't recognize this card.
190: */
191: if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)])
192: return(0);
193:
194: /*
195: * Empirically derived self-test magic
196: */
197: s = spltty();
198: dcm->dcm_rsid = DCMRS;
199: DELAY(50000); /* 5000 is not long enough */
200: dcm->dcm_rsid = 0;
201: dcm->dcm_ic = IC_IE;
202: dcm->dcm_cr = CR_SELFT;
203: while ((dcm->dcm_ic & IC_IR) == 0)
204: if (++timo == 20000)
205: return(0);
206: DELAY(50000) /* XXX why is this needed ???? */
207: while ((dcm->dcm_iir & IIR_SELFT) == 0)
208: if (++timo == 400000)
209: return(0);
210: DELAY(50000) /* XXX why is this needed ???? */
211: if (dcm->dcm_stcon != ST_OK) {
212: if (!isconsole)
213: printf("dcm%d: self test failed: %x\n",
214: brd, dcm->dcm_stcon);
215: return(0);
216: }
217: dcm->dcm_ic = IC_ID;
218: splx(s);
219:
220: hd->hp_ipl = DCMIPL(dcm->dcm_ic);
221: dcm_addr[brd] = dcm;
222: dcm_active |= 1 << brd;
223: dcmsoftCAR[brd] = hd->hp_flags;
224: dcmisr[brd].isr_ipl = hd->hp_ipl;
225: dcmisr[brd].isr_arg = brd;
226: dcmisr[brd].isr_intr = dcmintr;
227: isrlink(&dcmisr[brd]);
228: #ifdef KGDB
229: if (major(kgdb_dev) == 2 && BOARD(kgdb_dev) == brd) {
230: if (dcmconsole == UNIT(kgdb_dev))
231: kgdb_dev = -1; /* can't debug over console port */
232: else {
233: (void) dcminit(kgdb_dev, kgdb_rate);
234: if (kgdb_debug_init) {
235: printf("dcm%d: kgdb waiting...",
236: UNIT(kgdb_dev));
237: /* trap into kgdb */
238: asm("trap #15;");
239: printf("connected.\n");
240: } else
241: printf("dcm%d: kgdb enabled\n",
242: UNIT(kgdb_dev));
243: }
244: }
245: #endif
246: if (dcmistype == DIS_TIMER)
247: dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
248: else
249: dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
250: dcm->dcm_mdmmsk = MI_CD|MI_CTS; /* DCD (modem) and CTS (flow ctrl) */
251: dcm->dcm_ic = IC_IE; /* turn all interrupts on */
252: /*
253: * Need to reset baud rate, etc. of next print so reset dcmconsole.
254: * Also make sure console is always "hardwired"
255: */
256: if (isconsole) {
257: dcmconsole = -1;
258: dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
259: }
260: return (1);
261: }
262:
263: dcmopen(dev, flag)
264: dev_t dev;
265: {
266: register struct tty *tp;
267: register int unit, brd;
268: int error = 0;
269:
270: unit = UNIT(dev);
271: brd = BOARD(unit);
272: if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0)
273: return (ENXIO);
274: #ifdef KGDB
275: if (unit == UNIT(kgdb_dev))
276: return (EBUSY);
277: #endif
278: tp = &dcm_tty[unit];
279: tp->t_oproc = dcmstart;
280: tp->t_param = dcmparam;
281: tp->t_dev = dev;
282: if ((tp->t_state & TS_ISOPEN) == 0) {
283: tp->t_state |= TS_WOPEN;
284: ttychars(tp);
285: tp->t_iflag = TTYDEF_IFLAG;
286: tp->t_oflag = TTYDEF_OFLAG;
287: tp->t_cflag = TTYDEF_CFLAG;
288: tp->t_lflag = TTYDEF_LFLAG;
289: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
290: (void) dcmparam(tp, &tp->t_termios);
291: ttsetwater(tp);
292: } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
293: return (EBUSY);
294: if (PORT(unit) == 0) /* enable port 0 */
295: (void) dcmmctl(dev, MO_ON, DMSET);
296: if (dcmsoftCAR[brd] & (1 << PORT(unit)))
297: tp->t_state |= TS_CARR_ON;
298: else if (PORT(unit)) /* Only port 0 has modem control */
299: tp->t_state |= TS_CARR_ON;
300: else if (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)
301: tp->t_state |= TS_CARR_ON;
302: (void) spltty();
303: while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
304: (tp->t_state & TS_CARR_ON) == 0) {
305: tp->t_state |= TS_WOPEN;
306: if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
307: ttopen, 0))
308: break;
309: }
310: (void) spl0();
311: #ifdef DEBUG
312: if (dcmdebug & DDB_OPENCLOSE)
313: printf("dcmopen: u %x st %x fl %x\n",
314: unit, tp->t_state, tp->t_flags);
315: #endif
316: if (error == 0)
317: error = (*linesw[tp->t_line].l_open)(dev, tp);
318: return (error);
319: }
320:
321: /*ARGSUSED*/
322: dcmclose(dev, flag)
323: dev_t dev;
324: {
325: register struct tty *tp;
326: int unit;
327:
328: unit = UNIT(dev);
329: tp = &dcm_tty[unit];
330: (*linesw[tp->t_line].l_close)(tp);
331: if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
332: (tp->t_state&TS_ISOPEN) == 0)
333: (void) dcmmctl(dev, MO_OFF, DMSET);
334: #ifdef DEBUG
335: if (dcmdebug & DDB_OPENCLOSE)
336: printf("dcmclose: u %x st %x fl %x\n",
337: unit, tp->t_state, tp->t_flags);
338: #endif
339: ttyclose(tp);
340: return(0);
341: }
342:
343: dcmread(dev, uio, flag)
344: dev_t dev;
345: struct uio *uio;
346: {
347: register struct tty *tp;
348:
349: tp = &dcm_tty[UNIT(dev)];
350: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
351: }
352:
353: dcmwrite(dev, uio, flag)
354: dev_t dev;
355: struct uio *uio;
356: {
357: int unit = UNIT(dev);
358: register struct tty *tp;
359:
360: tp = &dcm_tty[unit];
361: /*
362: * XXX we disallow virtual consoles if the physical console is
363: * a serial port. This is in case there is a display attached that
364: * is not the console. In that situation we don't need/want the X
365: * server taking over the console.
366: */
367: if (constty && unit == dcmconsole)
368: constty = NULL;
369: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
370: }
371:
372: dcmintr(brd)
373: register int brd;
374: {
375: register struct dcmdevice *dcm = dcm_addr[brd];
376: register struct dcmischeme *dis;
377: int i, code, pcnd[4], mcnd, delta;
378:
379: /*
380: * Do all guarded register accesses right off to minimize
381: * block out of hardware.
382: */
383: SEM_LOCK(dcm);
384: if ((dcm->dcm_ic & IC_IR) == 0) {
385: SEM_UNLOCK(dcm);
386: return(0);
387: }
388: for (i = 0; i < 4; i++) {
389: pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
390: dcm->dcm_icrtab[i].dcm_data = 0;
391: }
392: mcnd = dcm->dcm_mdmin;
393: code = dcm->dcm_iir & IIR_MASK;
394: dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */
395: SEM_UNLOCK(dcm);
396:
397: #ifdef DEBUG
398: if (dcmdebug & DDB_INTR)
399: printf("dcmintr(%d): iir %x p0 %x p1 %x p2 %x p3 %x m %x\n",
400: brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3], mcnd);
401: #endif
402: if (code & IIR_TIMEO)
403: dcmrint(brd, dcm);
404: if (code & IIR_PORT0)
405: dcmpint(MKUNIT(brd, 0), pcnd[0], dcm);
406: if (code & IIR_PORT1)
407: dcmpint(MKUNIT(brd, 1), pcnd[1], dcm);
408: if (code & IIR_PORT2)
409: dcmpint(MKUNIT(brd, 2), pcnd[2], dcm);
410: if (code & IIR_PORT3)
411: dcmpint(MKUNIT(brd, 3), pcnd[3], dcm);
412: if (code & IIR_MODM)
413: dcmmint(MKUNIT(brd, 0), mcnd, dcm); /* XXX always port 0 */
414:
415: dis = &dcmischeme[brd];
416: /*
417: * Chalk up a receiver interrupt if the timer running or one of
418: * the ports reports a special character interrupt.
419: */
420: if ((code & IIR_TIMEO) ||
421: ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
422: dis->dis_intr++;
423: /*
424: * See if it is time to check/change the interrupt rate.
425: */
426: if (dcmistype < 0 &&
427: (delta = time.tv_sec - dis->dis_time) >= dcminterval) {
428: /*
429: * If currently per-character and averaged over 70 interrupts
430: * per-second (66 is threshold of 600 baud) in last interval,
431: * switch to timer mode.
432: *
433: * XXX decay counts ala load average to avoid spikes?
434: */
435: if (dis->dis_perchar && dis->dis_intr > 70 * delta)
436: dcmsetischeme(brd, DIS_TIMER);
437: /*
438: * If currently using timer and had more interrupts than
439: * received characters in the last interval, switch back
440: * to per-character. Note that after changing to per-char
441: * we must process any characters already in the queue
442: * since they may have arrived before the bitmap was setup.
443: *
444: * XXX decay counts?
445: */
446: else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
447: dcmsetischeme(brd, DIS_PERCHAR);
448: dcmrint(brd, dcm);
449: }
450: dis->dis_intr = dis->dis_char = 0;
451: dis->dis_time = time.tv_sec;
452: }
453: return(1);
454: }
455:
456: /*
457: * Port interrupt. Can be two things:
458: * First, it might be a special character (exception interrupt);
459: * Second, it may be a buffer empty (transmit interrupt);
460: */
461: dcmpint(unit, code, dcm)
462: int unit, code;
463: struct dcmdevice *dcm;
464: {
465: struct tty *tp = &dcm_tty[unit];
466:
467: if (code & IT_SPEC)
468: dcmreadbuf(unit, dcm, tp);
469: if (code & IT_TX)
470: dcmxint(unit, dcm, tp);
471: }
472:
473: dcmrint(brd, dcm)
474: int brd;
475: register struct dcmdevice *dcm;
476: {
477: register int i, unit;
478: register struct tty *tp;
479:
480: unit = MKUNIT(brd, 0);
481: tp = &dcm_tty[unit];
482: for (i = 0; i < 4; i++, tp++, unit++)
483: dcmreadbuf(unit, dcm, tp);
484: }
485:
486: dcmreadbuf(unit, dcm, tp)
487: int unit;
488: register struct dcmdevice *dcm;
489: register struct tty *tp;
490: {
491: int port = PORT(unit);
492: register struct dcmpreg *pp = dcm_preg(dcm, port);
493: register struct dcmrfifo *fifo;
494: register int c, stat;
495: register unsigned head;
496: int nch = 0;
497: #ifdef IOSTATS
498: struct dcmstats *dsp = &dcmstats[BOARD(unit)];
499:
500: dsp->rints++;
501: #endif
502: if ((tp->t_state & TS_ISOPEN) == 0) {
503: #ifdef KGDB
504: if (unit == UNIT(kgdb_dev) &&
505: (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
506: dcm->dcm_rfifos[3-port][head>>1].data_char == '!') {
507: pp->r_head = (head + 2) & RX_MASK;
508: printf("kgdb trap from dcm%d\n", unit);
509: /* trap into kgdb */
510: asm("trap #15;");
511: return;
512: }
513: #endif
514: pp->r_head = pp->r_tail & RX_MASK;
515: return;
516: }
517:
518: head = pp->r_head & RX_MASK;
519: fifo = &dcm->dcm_rfifos[3-port][head>>1];
520: /*
521: * XXX upper bound on how many chars we will take in one swallow?
522: */
523: while (head != (pp->r_tail & RX_MASK)) {
524: /*
525: * Get character/status and update head pointer as fast
526: * as possible to make room for more characters.
527: */
528: c = fifo->data_char;
529: stat = fifo->data_stat;
530: head = (head + 2) & RX_MASK;
531: pp->r_head = head;
532: fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
533: nch++;
534:
535: #ifdef DEBUG
536: if (dcmdebug & DDB_INPUT)
537: printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n",
538: unit, c&0xFF, c, stat&0xFF,
539: tp->t_flags, head, pp->r_tail);
540: #endif
541: /*
542: * Check for and handle errors
543: */
544: if (stat & RD_MASK) {
545: #ifdef DEBUG
546: if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
547: printf("dcmreadbuf(%d): err: c%x('%c') s%x\n",
548: unit, stat, c&0xFF, c);
549: #endif
550: if (stat & (RD_BD | RD_FE))
551: c |= TTY_FE;
552: else if (stat & RD_PE)
553: c |= TTY_PE;
554: else if (stat & RD_OVF)
555: log(LOG_WARNING,
556: "dcm%d: silo overflow\n", unit);
557: else if (stat & RD_OE)
558: log(LOG_WARNING,
559: "dcm%d: uart overflow\n", unit);
560: }
561: (*linesw[tp->t_line].l_rint)(c, tp);
562: }
563: dcmischeme[BOARD(unit)].dis_char += nch;
564: #ifdef IOSTATS
565: dsp->rchars += nch;
566: if (nch <= DCMRBSIZE)
567: dsp->rsilo[nch]++;
568: else
569: dsp->rsilo[DCMRBSIZE+1]++;
570: #endif
571: }
572:
573: dcmxint(unit, dcm, tp)
574: int unit;
575: struct dcmdevice *dcm;
576: register struct tty *tp;
577: {
578: tp->t_state &= ~TS_BUSY;
579: if (tp->t_state & TS_FLUSH)
580: tp->t_state &= ~TS_FLUSH;
581: if (tp->t_line)
582: (*linesw[tp->t_line].l_start)(tp);
583: else
584: dcmstart(tp);
585: }
586:
587: dcmmint(unit, mcnd, dcm)
588: register int unit;
589: register struct dcmdevice *dcm;
590: int mcnd;
591: {
592: register struct tty *tp;
593: int delta;
594:
595: #ifdef DEBUG
596: if (dcmdebug & DDB_MODEM)
597: printf("dcmmint: unit %x mcnd %x mcndlast\n",
598: unit, mcnd, mcndlast[unit]);
599: #endif
600: tp = &dcm_tty[unit];
601: delta = mcnd ^ mcndlast[unit];
602: mcndlast[unit] = mcnd;
603: if ((delta & MI_CD) &&
604: (dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) {
605: if (mcnd & MI_CD)
606: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
607: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
608: dcm->dcm_mdmout &= ~(MO_DTR|MO_RTS);
609: SEM_LOCK(dcm);
610: dcm->dcm_cr |= CR_MODM;
611: SEM_UNLOCK(dcm);
612: DELAY(10); /* time to change lines */
613: }
614: } else if ((delta & MI_CTS) &&
615: (tp->t_state & TS_ISOPEN) && (tp->t_flags & CRTSCTS)) {
616: if (mcnd & MI_CTS) {
617: tp->t_state &= ~TS_TTSTOP;
618: ttstart(tp);
619: } else
620: tp->t_state |= TS_TTSTOP; /* inline dcmstop */
621: }
622: }
623:
624: dcmioctl(dev, cmd, data, flag)
625: dev_t dev;
626: caddr_t data;
627: {
628: register struct tty *tp;
629: register int unit = UNIT(dev);
630: register struct dcmdevice *dcm;
631: register int port;
632: int error, s;
633:
634: #ifdef DEBUG
635: if (dcmdebug & DDB_IOCTL)
636: printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
637: unit, cmd, *data, flag);
638: #endif
639: tp = &dcm_tty[unit];
640: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
641: if (error >= 0)
642: return (error);
643: error = ttioctl(tp, cmd, data, flag);
644: if (error >= 0)
645: return (error);
646:
647: port = PORT(unit);
648: dcm = dcm_addr[BOARD(unit)];
649: switch (cmd) {
650: case TIOCSBRK:
651: /*
652: * Wait for transmitter buffer to empty
653: */
654: s = spltty();
655: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
656: DELAY(DCM_USPERCH(tp->t_ospeed));
657: SEM_LOCK(dcm);
658: dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
659: dcm->dcm_cr |= (1 << port); /* start break */
660: SEM_UNLOCK(dcm);
661: splx(s);
662: break;
663:
664: case TIOCCBRK:
665: SEM_LOCK(dcm);
666: dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
667: dcm->dcm_cr |= (1 << port); /* end break */
668: SEM_UNLOCK(dcm);
669: break;
670:
671: case TIOCSDTR:
672: (void) dcmmctl(dev, MO_ON, DMBIS);
673: break;
674:
675: case TIOCCDTR:
676: (void) dcmmctl(dev, MO_ON, DMBIC);
677: break;
678:
679: case TIOCMSET:
680: (void) dcmmctl(dev, *(int *)data, DMSET);
681: break;
682:
683: case TIOCMBIS:
684: (void) dcmmctl(dev, *(int *)data, DMBIS);
685: break;
686:
687: case TIOCMBIC:
688: (void) dcmmctl(dev, *(int *)data, DMBIC);
689: break;
690:
691: case TIOCMGET:
692: *(int *)data = dcmmctl(dev, 0, DMGET);
693: break;
694:
695: default:
696: return (ENOTTY);
697: }
698: return (0);
699: }
700:
701: dcmparam(tp, t)
702: register struct tty *tp;
703: register struct termios *t;
704: {
705: register struct dcmdevice *dcm;
706: register int port, mode, cflag = t->c_cflag;
707: int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
708:
709: /* check requested parameters */
710: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
711: return(EINVAL);
712: /* and copy to tty */
713: tp->t_ispeed = t->c_ispeed;
714: tp->t_ospeed = t->c_ospeed;
715: tp->t_cflag = cflag;
716: if (ospeed == 0) {
717: (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET);
718: return(0);
719: }
720:
721: mode = 0;
722: switch (cflag&CSIZE) {
723: case CS5:
724: mode = LC_5BITS; break;
725: case CS6:
726: mode = LC_6BITS; break;
727: case CS7:
728: mode = LC_7BITS; break;
729: case CS8:
730: mode = LC_8BITS; break;
731: }
732: if (cflag&PARENB) {
733: if (cflag&PARODD)
734: mode |= LC_PODD;
735: else
736: mode |= LC_PEVEN;
737: }
738: if (cflag&CSTOPB)
739: mode |= LC_2STOP;
740: else
741: mode |= LC_1STOP;
742: #ifdef DEBUG
743: if (dcmdebug & DDB_PARAM)
744: printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n",
745: UNIT(tp->t_dev), cflag, mode, tp->t_ospeed,
746: DCM_USPERCH(tp->t_ospeed));
747: #endif
748:
749: port = PORT(tp->t_dev);
750: dcm = dcm_addr[BOARD(tp->t_dev)];
751: /*
752: * Wait for transmitter buffer to empty.
753: */
754: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
755: DELAY(DCM_USPERCH(tp->t_ospeed));
756: /*
757: * Make changes known to hardware.
758: */
759: dcm->dcm_data[port].dcm_baud = ospeed;
760: dcm->dcm_data[port].dcm_conf = mode;
761: SEM_LOCK(dcm);
762: dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
763: dcm->dcm_cr |= (1 << port);
764: SEM_UNLOCK(dcm);
765: /*
766: * Delay for config change to take place. Weighted by buad.
767: * XXX why do we do this?
768: */
769: DELAY(16 * DCM_USPERCH(tp->t_ospeed));
770: return(0);
771: }
772:
773: dcmstart(tp)
774: register struct tty *tp;
775: {
776: register struct dcmdevice *dcm;
777: register struct dcmpreg *pp;
778: register struct dcmtfifo *fifo;
779: register char *bp;
780: register unsigned tail, next;
781: register int port, nch;
782: unsigned head;
783: char buf[16];
784: int s;
785: #ifdef IOSTATS
786: struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)];
787: int tch = 0;
788: #endif
789:
790: s = spltty();
791: #ifdef IOSTATS
792: dsp->xints++;
793: #endif
794: #ifdef DEBUG
795: if (dcmdebug & DDB_OUTPUT)
796: printf("dcmstart(%d): state %x flags %x outcc %d\n",
797: UNIT(tp->t_dev), tp->t_state, tp->t_flags,
798: tp->t_outq.c_cc);
799: #endif
800: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
801: goto out;
802: if (tp->t_outq.c_cc <= tp->t_lowat) {
803: if (tp->t_state&TS_ASLEEP) {
804: tp->t_state &= ~TS_ASLEEP;
805: wakeup((caddr_t)&tp->t_outq);
806: }
807: if (tp->t_wsel) {
808: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
809: tp->t_wsel = 0;
810: tp->t_state &= ~TS_WCOLL;
811: }
812: }
813: if (tp->t_outq.c_cc == 0) {
814: #ifdef IOSTATS
815: dsp->xempty++;
816: #endif
817: goto out;
818: }
819:
820: dcm = dcm_addr[BOARD(tp->t_dev)];
821: port = PORT(tp->t_dev);
822: pp = dcm_preg(dcm, port);
823: tail = pp->t_tail & TX_MASK;
824: next = (tail + 1) & TX_MASK;
825: head = pp->t_head & TX_MASK;
826: if (head == next)
827: goto out;
828: fifo = &dcm->dcm_tfifos[3-port][tail];
829: again:
830: nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
831: #ifdef IOSTATS
832: tch += nch;
833: #endif
834: #ifdef DEBUG
835: if (dcmdebug & DDB_OUTPUT)
836: printf("\thead %x tail %x nch %d\n", head, tail, nch);
837: #endif
838: /*
839: * Loop transmitting all the characters we can.
840: */
841: for (bp = buf; --nch >= 0; bp++) {
842: fifo->data_char = *bp;
843: pp->t_tail = next;
844: /*
845: * If this is the first character,
846: * get the hardware moving right now.
847: */
848: if (bp == buf) {
849: tp->t_state |= TS_BUSY;
850: SEM_LOCK(dcm);
851: dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
852: dcm->dcm_cr |= (1 << port);
853: SEM_UNLOCK(dcm);
854: }
855: tail = next;
856: fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
857: next = (next + 1) & TX_MASK;
858: }
859: /*
860: * Head changed while we were loading the buffer,
861: * go back and load some more if we can.
862: */
863: if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
864: #ifdef IOSTATS
865: dsp->xrestarts++;
866: #endif
867: head = pp->t_head & TX_MASK;
868: goto again;
869: }
870: /*
871: * Kick it one last time in case it finished while we were
872: * loading the last bunch.
873: */
874: if (bp > &buf[1]) {
875: tp->t_state |= TS_BUSY;
876: SEM_LOCK(dcm);
877: dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
878: dcm->dcm_cr |= (1 << port);
879: SEM_UNLOCK(dcm);
880: }
881: #ifdef DEBUG
882: if (dcmdebug & DDB_INTR)
883: printf("dcmstart(%d): head %x tail %x outqcc %d\n",
884: UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc);
885: #endif
886: out:
887: #ifdef IOSTATS
888: dsp->xchars += tch;
889: if (tch <= DCMXBSIZE)
890: dsp->xsilo[tch]++;
891: else
892: dsp->xsilo[DCMXBSIZE+1]++;
893: #endif
894: splx(s);
895: }
896:
897: /*
898: * Stop output on a line.
899: */
900: dcmstop(tp, flag)
901: register struct tty *tp;
902: {
903: int s;
904:
905: s = spltty();
906: if (tp->t_state & TS_BUSY) {
907: /* XXX is there some way to safely stop transmission? */
908: if ((tp->t_state&TS_TTSTOP) == 0)
909: tp->t_state |= TS_FLUSH;
910: }
911: splx(s);
912: }
913:
914: /* Modem control */
915:
916: dcmmctl(dev, bits, how)
917: dev_t dev;
918: int bits, how;
919: {
920: register struct dcmdevice *dcm;
921: int s, hit = 0;
922:
923: /*
924: * Only port 0 has modem control lines.
925: * XXX ok for now but needs to changed for the 8 port board.
926: */
927: if (PORT(UNIT(dev)) != 0)
928: return(bits);
929:
930: dcm = dcm_addr[BOARD(UNIT(dev))];
931: s = spltty();
932: switch (how) {
933:
934: case DMSET:
935: dcm->dcm_mdmout = bits;
936: hit++;
937: break;
938:
939: case DMBIS:
940: dcm->dcm_mdmout |= bits;
941: hit++;
942: break;
943:
944: case DMBIC:
945: dcm->dcm_mdmout &= ~bits;
946: hit++;
947: break;
948:
949: case DMGET:
950: bits = dcm->dcm_mdmin;
951: break;
952: }
953: if (hit) {
954: SEM_LOCK(dcm);
955: dcm->dcm_cr |= CR_MODM;
956: SEM_UNLOCK(dcm);
957: DELAY(10); /* delay until done */
958: (void) splx(s);
959: }
960: return(bits);
961: }
962:
963: /*
964: * Set board to either interrupt per-character or at a fixed interval.
965: */
966: dcmsetischeme(brd, flags)
967: int brd, flags;
968: {
969: register struct dcmdevice *dcm = dcm_addr[brd];
970: register struct dcmischeme *dis = &dcmischeme[brd];
971: register int i;
972: u_char mask;
973: int perchar = flags & DIS_PERCHAR;
974:
975: #ifdef DEBUG
976: if (dcmdebug & DDB_INTSCHM)
977: printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",
978: brd, perchar, dis->dis_perchar,
979: dis->dis_intr, dis->dis_char);
980: if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
981: printf("dcmsetischeme(%d): redundent request %d\n",
982: brd, perchar);
983: return;
984: }
985: #endif
986: /*
987: * If perchar is non-zero, we enable interrupts on all characters
988: * otherwise we disable perchar interrupts and use periodic
989: * polling interrupts.
990: */
991: dis->dis_perchar = perchar;
992: mask = perchar ? 0xf : 0x0;
993: for (i = 0; i < 256; i++)
994: dcm->dcm_bmap[i].data_data = mask;
995: /*
996: * Don't slow down tandem mode, interrupt on flow control
997: * chars for any port on the board.
998: */
999: if (!perchar) {
1000: register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)];
1001: int c;
1002:
1003: for (i = 0; i < 4; i++, tp++) {
1004: if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
1005: dcm->dcm_bmap[c].data_data |= (1 << i);
1006: if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
1007: dcm->dcm_bmap[c].data_data |= (1 << i);
1008: }
1009: }
1010: /*
1011: * Board starts with timer disabled so if first call is to
1012: * set perchar mode then we don't want to toggle the timer.
1013: */
1014: if (flags == (DIS_RESET|DIS_PERCHAR))
1015: return;
1016: /*
1017: * Toggle card 16.7ms interrupts (we first make sure that card
1018: * has cleared the bit so it will see the toggle).
1019: */
1020: while (dcm->dcm_cr & CR_TIMER)
1021: ;
1022: SEM_LOCK(dcm);
1023: dcm->dcm_cr |= CR_TIMER;
1024: SEM_UNLOCK(dcm);
1025: }
1026:
1027: /*
1028: * Following are all routines needed for DCM to act as console
1029: */
1030: #include "machine/cons.h"
1031:
1032: dcmcnprobe(cp)
1033: struct consdev *cp;
1034: {
1035: register struct hp_hw *hw;
1036: int unit, i;
1037: extern int dcmopen();
1038:
1039: /*
1040: * Implicitly assigns the lowest select code DCM card found to be
1041: * logical unit 0 (actually CONUNIT). If your config file does
1042: * anything different, you're screwed.
1043: */
1044: for (hw = sc_table; hw->hw_type; hw++)
1045: if (hw->hw_type == COMMDCM && !badaddr((short *)hw->hw_addr))
1046: break;
1047: if (hw->hw_type != COMMDCM) {
1048: cp->cn_pri = CN_DEAD;
1049: return;
1050: }
1051: unit = CONUNIT;
1052: dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_addr;
1053:
1054: /* locate the major number */
1055: for (i = 0; i < nchrdev; i++)
1056: if (cdevsw[i].d_open == dcmopen)
1057: break;
1058:
1059: /* initialize required fields */
1060: cp->cn_dev = makedev(i, unit);
1061: cp->cn_tp = &dcm_tty[unit];
1062: switch (dcm_addr[BOARD(unit)]->dcm_rsid) {
1063: case DCMID:
1064: cp->cn_pri = CN_NORMAL;
1065: break;
1066: case DCMID|DCMCON:
1067: cp->cn_pri = CN_REMOTE;
1068: break;
1069: default:
1070: cp->cn_pri = CN_DEAD;
1071: break;
1072: }
1073: }
1074:
1075: dcmcninit(cp)
1076: struct consdev *cp;
1077: {
1078: dcminit(cp->cn_dev, dcmdefaultrate);
1079: dcmconsole = UNIT(cp->cn_dev);
1080: }
1081:
1082: dcminit(dev, rate)
1083: dev_t dev;
1084: int rate;
1085: {
1086: register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1087: int s, mode, port;
1088:
1089: port = PORT(dev);
1090: mode = LC_8BITS | LC_1STOP;
1091: s = splhigh();
1092: /*
1093: * Wait for transmitter buffer to empty.
1094: */
1095: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1096: DELAY(DCM_USPERCH(rate));
1097: /*
1098: * Make changes known to hardware.
1099: */
1100: dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1101: dcm->dcm_data[port].dcm_conf = mode;
1102: SEM_LOCK(dcm);
1103: dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1104: dcm->dcm_cr |= (1 << port);
1105: SEM_UNLOCK(dcm);
1106: /*
1107: * Delay for config change to take place. Weighted by buad.
1108: * XXX why do we do this?
1109: */
1110: DELAY(16 * DCM_USPERCH(rate));
1111: splx(s);
1112: }
1113:
1114: dcmcngetc(dev)
1115: dev_t dev;
1116: {
1117: register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1118: register struct dcmrfifo *fifo;
1119: register struct dcmpreg *pp;
1120: register unsigned head;
1121: int s, c, stat, port;
1122:
1123: port = PORT(dev);
1124: pp = dcm_preg(dcm, port);
1125: s = splhigh();
1126: head = pp->r_head & RX_MASK;
1127: fifo = &dcm->dcm_rfifos[3-port][head>>1];
1128: while (head == (pp->r_tail & RX_MASK))
1129: ;
1130: /*
1131: * If board interrupts are enabled, just let our received char
1132: * interrupt through in case some other port on the board was
1133: * busy. Otherwise we must clear the interrupt.
1134: */
1135: SEM_LOCK(dcm);
1136: if ((dcm->dcm_ic & IC_IE) == 0)
1137: stat = dcm->dcm_iir;
1138: SEM_UNLOCK(dcm);
1139: c = fifo->data_char;
1140: stat = fifo->data_stat;
1141: pp->r_head = (head + 2) & RX_MASK;
1142: splx(s);
1143: return(c);
1144: }
1145:
1146: /*
1147: * Console kernel output character routine.
1148: */
1149: dcmcnputc(dev, c)
1150: dev_t dev;
1151: int c;
1152: {
1153: register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1154: register struct dcmpreg *pp;
1155: unsigned tail;
1156: int s, port, stat;
1157:
1158: port = PORT(dev);
1159: pp = dcm_preg(dcm, port);
1160: s = splhigh();
1161: #ifdef KGDB
1162: if (dev != kgdb_dev)
1163: #endif
1164: if (dcmconsole == -1) {
1165: (void) dcminit(dev, dcmdefaultrate);
1166: dcmconsole = UNIT(dev);
1167: }
1168: tail = pp->t_tail & TX_MASK;
1169: while (tail != (pp->t_head & TX_MASK))
1170: ;
1171: dcm->dcm_tfifos[3-port][tail].data_char = c;
1172: pp->t_tail = tail = (tail + 1) & TX_MASK;
1173: SEM_LOCK(dcm);
1174: dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1175: dcm->dcm_cr |= (1 << port);
1176: SEM_UNLOCK(dcm);
1177: while (tail != (pp->t_head & TX_MASK))
1178: ;
1179: /*
1180: * If board interrupts are enabled, just let our completion
1181: * interrupt through in case some other port on the board
1182: * was busy. Otherwise we must clear the interrupt.
1183: */
1184: if ((dcm->dcm_ic & IC_IE) == 0) {
1185: SEM_LOCK(dcm);
1186: stat = dcm->dcm_iir;
1187: SEM_UNLOCK(dcm);
1188: }
1189: splx(s);
1190: }
1191: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.