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