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