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