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