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