4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / sys / pmax / dev / dc.c
CommitLineData
6c1a1c86 1/*-
86090d31
KB
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
12d43ee5
KM
4 *
5 * This code is derived from software contributed to Berkeley by
6c1a1c86 6 * Ralph Campbell and Rick Macklem.
12d43ee5
KM
7 *
8 * %sccs.include.redist.c%
9 *
86090d31 10 * @(#)dc.c 8.1 (Berkeley) %G%
6c1a1c86
RC
11 */
12
13/*
12d43ee5
KM
14 * devDC7085.c --
15 *
16 * This file contains machine-dependent routines that handle the
17 * output queue for the serial lines.
18 *
19 * Copyright (C) 1989 Digital Equipment Corporation.
20 * Permission to use, copy, modify, and distribute this software and
21 * its documentation for any purpose and without fee is hereby granted,
22 * provided that the above copyright notice appears in all copies.
23 * Digital Equipment Corporation makes no representations about the
24 * suitability of this software for any purpose. It is provided "as is"
25 * without express or implied warranty.
26 *
27 * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devDC7085.c,
28 * v 1.4 89/08/29 11:55:30 nelson Exp $ SPRITE (DECWRL)";
29 */
30
6c1a1c86 31#include <dc.h>
12d43ee5
KM
32#if NDC > 0
33/*
34 * DC7085 (DZ-11 look alike) Driver
35 */
38a01dbe
KB
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/ioctl.h>
39#include <sys/tty.h>
40#include <sys/proc.h>
41#include <sys/map.h>
42#include <sys/buf.h>
43#include <sys/conf.h>
44#include <sys/file.h>
45#include <sys/uio.h>
46#include <sys/kernel.h>
47#include <sys/syslog.h>
12d43ee5 48
38a01dbe 49#include <machine/dc7085cons.h>
6c1a1c86
RC
50#include <machine/pmioctl.h>
51
52#include <pmax/pmax/pmaxtype.h>
53#include <pmax/pmax/cons.h>
12d43ee5 54
707603c0
KB
55#include <pmax/dev/device.h>
56#include <pmax/dev/pdma.h>
6c1a1c86
RC
57#include <pmax/dev/fbreg.h>
58
59extern int pmax_boardtype;
60extern struct consdev cn_tab;
12d43ee5
KM
61
62/*
63 * Driver information for auto-configuration stuff.
64 */
65int dcprobe();
84722262 66void dcintr();
12d43ee5 67struct driver dcdriver = {
84722262 68 "dc", dcprobe, 0, 0, dcintr,
12d43ee5
KM
69};
70
71#define NDCLINE (NDC*4)
72
6c1a1c86
RC
73void dcstart __P((struct tty *));
74void dcxint __P((struct tty *));
75void dcPutc __P((dev_t, int));
76void dcscan __P((void *));
2c940704 77extern void ttrstrt __P((void *));
6c1a1c86
RC
78int dcGetc __P((dev_t));
79int dcparam __P((struct tty *, struct termios *));
12d43ee5
KM
80
81struct tty dc_tty[NDCLINE];
82int dc_cnt = NDCLINE;
60160479
RC
83void (*dcDivertXInput)(); /* X windows keyboard input routine */
84void (*dcMouseEvent)(); /* X windows mouse motion event routine */
85void (*dcMouseButtons)(); /* X windows mouse buttons event routine */
12d43ee5
KM
86#ifdef DEBUG
87int debugChar;
88#endif
89
90/*
91 * Software copy of brk register since it isn't readable
92 */
93int dc_brk[NDC];
94char dcsoftCAR[NDC]; /* mask of dc's with carrier on (DSR) */
95
96/*
97 * The DC7085 doesn't interrupt on carrier transitions, so
98 * we have to use a timer to watch it.
99 */
100int dc_timer; /* true if timer started */
101
102/*
103 * Pdma structures for fast output code
104 */
105struct pdma dcpdma[NDCLINE];
106
107struct speedtab dcspeedtab[] = {
108 0, 0,
109 50, LPR_B50,
110 75, LPR_B75,
111 110, LPR_B110,
112 134, LPR_B134,
113 150, LPR_B150,
114 300, LPR_B300,
115 600, LPR_B600,
116 1200, LPR_B1200,
117 1800, LPR_B1800,
118 2400, LPR_B2400,
119 4800, LPR_B4800,
120 9600, LPR_B9600,
84722262 121 19200, LPR_B19200,
12d43ee5
KM
122 -1, -1
123};
124
125#ifndef PORTSELECTOR
126#define ISPEED TTYDEF_SPEED
127#define LFLAG TTYDEF_LFLAG
128#else
129#define ISPEED B4800
130#define LFLAG (TTYDEF_LFLAG & ~ECHO)
131#endif
132
12d43ee5
KM
133/*
134 * Test to see if device is present.
135 * Return true if found and initialized ok.
136 */
137dcprobe(cp)
138 register struct pmax_ctlr *cp;
139{
140 register dcregs *dcaddr;
141 register struct pdma *pdp;
142 register struct tty *tp;
143 register int cntr;
6c1a1c86 144 int s;
12d43ee5
KM
145
146 if (cp->pmax_unit >= NDC)
147 return (0);
148 if (badaddr(cp->pmax_addr, 2))
149 return (0);
150
a7971d31
RC
151 /*
152 * For a remote console, wait a while for previous output to
153 * complete.
154 */
155 if (major(cn_tab.cn_dev) == DCDEV && cp->pmax_unit == 0 &&
156 cn_tab.cn_screen == 0)
157 DELAY(10000);
158
12d43ee5
KM
159 /* reset chip */
160 dcaddr = (dcregs *)cp->pmax_addr;
161 dcaddr->dc_csr = CSR_CLR;
162 MachEmptyWriteBuffer();
163 while (dcaddr->dc_csr & CSR_CLR)
164 ;
165 dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE;
166
167 /* init pseudo DMA structures */
168 pdp = &dcpdma[cp->pmax_unit * 4];
169 tp = &dc_tty[cp->pmax_unit * 4];
170 for (cntr = 0; cntr < 4; cntr++) {
6c1a1c86 171 pdp->p_addr = (void *)dcaddr;
12d43ee5
KM
172 pdp->p_arg = (int)tp;
173 pdp->p_fcn = dcxint;
174 tp->t_addr = (caddr_t)pdp;
175 pdp++, tp++;
176 }
177 dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB;
178
179 if (dc_timer == 0) {
180 dc_timer = 1;
57373dbf 181 timeout(dcscan, (void *)0, hz);
12d43ee5 182 }
12d43ee5 183
6c1a1c86
RC
184 /*
185 * Special handling for consoles.
186 */
187 if (cp->pmax_unit == 0) {
188 if (cn_tab.cn_screen) {
189 s = spltty();
190 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
191 LPR_B4800 | DCKBD_PORT;
3c5e0ae7 192 MachEmptyWriteBuffer();
6c1a1c86
RC
193 dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
194 LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
195 MachEmptyWriteBuffer();
a7971d31 196 DELAY(1000);
6c1a1c86
RC
197 KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc);
198 MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc);
199 splx(s);
200 } else if (major(cn_tab.cn_dev) == DCDEV) {
201 s = spltty();
202 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
203 LPR_B9600 | minor(cn_tab.cn_dev);
204 MachEmptyWriteBuffer();
a7971d31 205 DELAY(1000);
6c1a1c86
RC
206 cn_tab.cn_disabled = 0;
207 splx(s);
208 }
12d43ee5 209 }
a7971d31
RC
210 printf("dc%d at nexus0 csr 0x%x priority %d\n",
211 cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
12d43ee5
KM
212 return (1);
213}
214
c74d1258 215dcopen(dev, flag, mode, p)
12d43ee5 216 dev_t dev;
c74d1258
RC
217 int flag, mode;
218 struct proc *p;
12d43ee5
KM
219{
220 register struct tty *tp;
221 register int unit;
222 int s, error = 0;
12d43ee5
KM
223
224 unit = minor(dev);
6c1a1c86 225 if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0)
12d43ee5
KM
226 return (ENXIO);
227 tp = &dc_tty[unit];
228 tp->t_addr = (caddr_t)&dcpdma[unit];
229 tp->t_oproc = dcstart;
230 tp->t_param = dcparam;
231 tp->t_dev = dev;
232 if ((tp->t_state & TS_ISOPEN) == 0) {
233 tp->t_state |= TS_WOPEN;
234 ttychars(tp);
235#ifndef PORTSELECTOR
236 if (tp->t_ispeed == 0) {
237#endif
238 tp->t_iflag = TTYDEF_IFLAG;
239 tp->t_oflag = TTYDEF_OFLAG;
240 tp->t_cflag = TTYDEF_CFLAG;
241 tp->t_lflag = LFLAG;
242 tp->t_ispeed = tp->t_ospeed = ISPEED;
243#ifdef PORTSELECTOR
244 tp->t_cflag |= HUPCL;
245#else
246 }
247#endif
248 (void) dcparam(tp, &tp->t_termios);
249 ttsetwater(tp);
250 } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
251 return (EBUSY);
252 (void) dcmctl(dev, DML_DTR, DMSET);
253 s = spltty();
254 while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
255 !(tp->t_state & TS_CARR_ON)) {
256 tp->t_state |= TS_WOPEN;
257 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
258 ttopen, 0))
259 break;
260 }
261 splx(s);
262 if (error)
263 return (error);
264 return ((*linesw[tp->t_line].l_open)(dev, tp));
265}
266
267/*ARGSUSED*/
c74d1258 268dcclose(dev, flag, mode, p)
12d43ee5 269 dev_t dev;
c74d1258
RC
270 int flag, mode;
271 struct proc *p;
12d43ee5
KM
272{
273 register struct tty *tp;
274 register int unit, bit;
275
276 unit = minor(dev);
277 tp = &dc_tty[unit];
278 bit = 1 << ((unit & 03) + 8);
279 if (dc_brk[unit >> 2] & bit) {
280 dc_brk[unit >> 2] &= ~bit;
281 ttyoutput(0, tp);
282 }
c74d1258 283 (*linesw[tp->t_line].l_close)(tp, flag);
12d43ee5
KM
284 if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
285 !(tp->t_state & TS_ISOPEN))
286 (void) dcmctl(dev, 0, DMSET);
287 return (ttyclose(tp));
288}
289
290dcread(dev, uio, flag)
291 dev_t dev;
292 struct uio *uio;
293{
294 register struct tty *tp;
295
296 tp = &dc_tty[minor(dev)];
297 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
298}
299
300dcwrite(dev, uio, flag)
301 dev_t dev;
302 struct uio *uio;
303{
304 register struct tty *tp;
305
306 tp = &dc_tty[minor(dev)];
307 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
308}
309
12d43ee5 310/*ARGSUSED*/
c74d1258 311dcioctl(dev, cmd, data, flag, p)
12d43ee5 312 dev_t dev;
6c1a1c86 313 int cmd;
12d43ee5 314 caddr_t data;
c74d1258
RC
315 int flag;
316 struct proc *p;
12d43ee5
KM
317{
318 register struct tty *tp;
319 register int unit = minor(dev);
320 register int dc = unit >> 2;
321 int error;
322
323 tp = &dc_tty[unit];
c74d1258 324 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
12d43ee5
KM
325 if (error >= 0)
326 return (error);
327 error = ttioctl(tp, cmd, data, flag);
328 if (error >= 0)
329 return (error);
330
331 switch (cmd) {
332
333 case TIOCSBRK:
334 dc_brk[dc] |= 1 << ((unit & 03) + 8);
335 ttyoutput(0, tp);
336 break;
337
338 case TIOCCBRK:
339 dc_brk[dc] &= ~(1 << ((unit & 03) + 8));
340 ttyoutput(0, tp);
341 break;
342
343 case TIOCSDTR:
344 (void) dcmctl(dev, DML_DTR|DML_RTS, DMBIS);
345 break;
346
347 case TIOCCDTR:
348 (void) dcmctl(dev, DML_DTR|DML_RTS, DMBIC);
349 break;
350
351 case TIOCMSET:
352 (void) dcmctl(dev, *(int *)data, DMSET);
353 break;
354
355 case TIOCMBIS:
356 (void) dcmctl(dev, *(int *)data, DMBIS);
357 break;
358
359 case TIOCMBIC:
360 (void) dcmctl(dev, *(int *)data, DMBIC);
361 break;
362
363 case TIOCMGET:
364 *(int *)data = dcmctl(dev, 0, DMGET);
365 break;
366
367 default:
368 return (ENOTTY);
369 }
370 return (0);
371}
372
373dcparam(tp, t)
374 register struct tty *tp;
375 register struct termios *t;
376{
377 register dcregs *dcaddr;
378 register int lpr;
379 register int cflag = t->c_cflag;
380 int unit = minor(tp->t_dev);
381 int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab);
382
383 /* check requested parameters */
384 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
6c1a1c86
RC
385 (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 ||
386 (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200))
12d43ee5
KM
387 return (EINVAL);
388 /* and copy to tty */
389 tp->t_ispeed = t->c_ispeed;
390 tp->t_ospeed = t->c_ospeed;
391 tp->t_cflag = cflag;
392
6c1a1c86
RC
393 dcaddr = (dcregs *)dcpdma[unit].p_addr;
394
395 /*
396 * Handle console cases specially.
397 */
398 if (cn_tab.cn_screen) {
399 if (unit == DCKBD_PORT) {
400 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
401 LPR_B4800 | DCKBD_PORT;
402 MachEmptyWriteBuffer();
403 return (0);
404 } else if (unit == DCMOUSE_PORT) {
405 dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
406 LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
407 MachEmptyWriteBuffer();
408 return (0);
409 }
410 } else if (tp->t_dev == cn_tab.cn_dev) {
411 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
412 LPR_B9600 | unit;
12d43ee5
KM
413 MachEmptyWriteBuffer();
414 return (0);
415 }
416 if (ospeed == 0) {
417 (void) dcmctl(unit, 0, DMSET); /* hang up line */
418 return (0);
419 }
420 lpr = LPR_RXENAB | ospeed | (unit & 03);
421 if ((cflag & CSIZE) == CS7)
422 lpr |= LPR_7_BIT_CHAR;
423 else
424 lpr |= LPR_8_BIT_CHAR;
425 if (cflag & PARENB)
426 lpr |= LPR_PARENB;
427 if (cflag & PARODD)
428 lpr |= LPR_OPAR;
429 if (cflag & CSTOPB)
430 lpr |= LPR_2_STOP;
431 dcaddr->dc_lpr = lpr;
432 MachEmptyWriteBuffer();
3c5e0ae7 433 DELAY(10);
12d43ee5
KM
434 return (0);
435}
436
84722262
RC
437/*
438 * Check for interrupts from all devices.
439 */
440void
441dcintr(unit)
442 register int unit;
443{
444 register dcregs *dcaddr;
445 register unsigned csr;
446
447 unit <<= 2;
6c1a1c86 448 dcaddr = (dcregs *)dcpdma[unit].p_addr;
84722262
RC
449 while ((csr = dcaddr->dc_csr) & (CSR_RDONE | CSR_TRDY)) {
450 if (csr & CSR_RDONE)
451 dcrint(unit);
452 if (csr & CSR_TRDY)
453 dcxint(&dc_tty[unit + ((csr >> 8) & 03)]);
454 }
455}
456
457dcrint(unit)
458 register int unit;
459{
460 register dcregs *dcaddr;
461 register struct tty *tp;
462 register int c, cc;
463 register struct tty *tp0;
464 int overrun = 0;
465
6c1a1c86 466 dcaddr = (dcregs *)dcpdma[unit].p_addr;
84722262
RC
467 tp0 = &dc_tty[unit];
468 while ((c = dcaddr->dc_rbuf) < 0) { /* char present */
469 cc = c & 0xff;
470 tp = tp0 + ((c >> 8) & 03);
471 if ((c & RBUF_OERR) && overrun == 0) {
472 log(LOG_WARNING, "dc%d,%d: silo overflow\n", unit >> 2,
473 (c >> 8) & 03);
474 overrun = 1;
475 }
476 /* the keyboard requires special translation */
6c1a1c86 477 if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
84722262
RC
478#ifdef KADB
479 if (cc == LK_DO) {
480 spl0();
481 kdbpanic();
482 return;
483 }
484#endif
485#ifdef DEBUG
486 debugChar = cc;
487#endif
488 if (dcDivertXInput) {
60160479 489 (*dcDivertXInput)(cc);
84722262
RC
490 return;
491 }
6c1a1c86 492 if ((cc = kbdMapChar(cc)) < 0)
84722262 493 return;
6c1a1c86 494 } else if (tp == &dc_tty[DCMOUSE_PORT] && dcMouseButtons) {
60160479 495 register MouseReport *mrp;
84722262
RC
496 static MouseReport currentRep;
497
60160479
RC
498 mrp = &currentRep;
499 mrp->byteCount++;
84722262
RC
500 if (cc & MOUSE_START_FRAME) {
501 /*
502 * The first mouse report byte (button state).
503 */
60160479
RC
504 mrp->state = cc;
505 if (mrp->byteCount > 1)
506 mrp->byteCount = 1;
507 } else if (mrp->byteCount == 2) {
84722262
RC
508 /*
509 * The second mouse report byte (delta x).
510 */
60160479
RC
511 mrp->dx = cc;
512 } else if (mrp->byteCount == 3) {
84722262
RC
513 /*
514 * The final mouse report byte (delta y).
515 */
60160479
RC
516 mrp->dy = cc;
517 mrp->byteCount = 0;
518 if (mrp->dx != 0 || mrp->dy != 0) {
84722262
RC
519 /*
520 * If the mouse moved,
521 * post a motion event.
522 */
60160479 523 (*dcMouseEvent)(mrp);
84722262 524 }
60160479 525 (*dcMouseButtons)(mrp);
84722262
RC
526 }
527 return;
528 }
529 if (!(tp->t_state & TS_ISOPEN)) {
530 wakeup((caddr_t)&tp->t_rawq);
531#ifdef PORTSELECTOR
532 if (!(tp->t_state & TS_WOPEN))
533#endif
534 return;
535 }
536 if (c & RBUF_FERR)
537 cc |= TTY_FE;
538 if (c & RBUF_PERR)
539 cc |= TTY_PE;
540 (*linesw[tp->t_line].l_rint)(cc, tp);
541 }
542 DELAY(10);
543}
544
024ed1ef 545void
12d43ee5
KM
546dcxint(tp)
547 register struct tty *tp;
548{
549 register struct pdma *dp;
550 register dcregs *dcaddr;
551
552 dp = (struct pdma *)tp->t_addr;
553 if (dp->p_mem < dp->p_end) {
6c1a1c86 554 dcaddr = (dcregs *)dp->p_addr;
12d43ee5
KM
555 dcaddr->dc_tdr = dc_brk[(tp - dc_tty) >> 2] | *dp->p_mem++;
556 MachEmptyWriteBuffer();
557 DELAY(10);
558 return;
559 }
560 tp->t_state &= ~TS_BUSY;
561 if (tp->t_state & TS_FLUSH)
562 tp->t_state &= ~TS_FLUSH;
563 else {
564 ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
565 dp->p_end = dp->p_mem = tp->t_outq.c_cf;
566 }
567 if (tp->t_line)
568 (*linesw[tp->t_line].l_start)(tp);
569 else
570 dcstart(tp);
571 if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
3c5e0ae7
RC
572 dcaddr = (dcregs *)dp->p_addr;
573 dcaddr->dc_tcr &= ~(1 << (minor(tp->t_dev) & 03));
12d43ee5
KM
574 MachEmptyWriteBuffer();
575 DELAY(10);
576 }
577}
578
024ed1ef 579void
12d43ee5
KM
580dcstart(tp)
581 register struct tty *tp;
582{
583 register struct pdma *dp;
584 register dcregs *dcaddr;
585 register int cc;
586 int s;
587
588 dp = (struct pdma *)tp->t_addr;
6c1a1c86 589 dcaddr = (dcregs *)dp->p_addr;
12d43ee5
KM
590 s = spltty();
591 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
592 goto out;
593 if (tp->t_outq.c_cc <= tp->t_lowat) {
594 if (tp->t_state & TS_ASLEEP) {
595 tp->t_state &= ~TS_ASLEEP;
596 wakeup((caddr_t)&tp->t_outq);
597 }
86e31fc2 598 selwakeup(&tp->t_wsel);
12d43ee5
KM
599 }
600 if (tp->t_outq.c_cc == 0)
601 goto out;
602 /* handle console specially */
6c1a1c86 603 if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
12d43ee5
KM
604 while (tp->t_outq.c_cc > 0) {
605 cc = getc(&tp->t_outq) & 0x7f;
60160479 606 cnputc(cc);
12d43ee5
KM
607 }
608 /*
609 * After we flush the output queue we may need to wake
610 * up the process that made the output.
611 */
612 if (tp->t_outq.c_cc <= tp->t_lowat) {
613 if (tp->t_state & TS_ASLEEP) {
614 tp->t_state &= ~TS_ASLEEP;
615 wakeup((caddr_t)&tp->t_outq);
616 }
86e31fc2 617 selwakeup(&tp->t_wsel);
12d43ee5
KM
618 }
619 goto out;
620 }
621 if (tp->t_flags & (RAW|LITOUT))
622 cc = ndqb(&tp->t_outq, 0);
623 else {
624 cc = ndqb(&tp->t_outq, 0200);
625 if (cc == 0) {
626 cc = getc(&tp->t_outq);
57373dbf 627 timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
12d43ee5
KM
628 tp->t_state |= TS_TIMEOUT;
629 goto out;
630 }
631 }
632 tp->t_state |= TS_BUSY;
633 dp->p_end = dp->p_mem = tp->t_outq.c_cf;
634 dp->p_end += cc;
635 dcaddr->dc_tcr |= 1 << (minor(tp->t_dev) & 03);
636 MachEmptyWriteBuffer();
637out:
638 splx(s);
639}
640
641/*
642 * Stop output on a line.
643 */
644/*ARGSUSED*/
645dcstop(tp, flag)
646 register struct tty *tp;
647{
648 register struct pdma *dp;
649 register int s;
650
651 dp = (struct pdma *)tp->t_addr;
652 s = spltty();
653 if (tp->t_state & TS_BUSY) {
654 dp->p_end = dp->p_mem;
655 if (!(tp->t_state & TS_TTSTOP))
656 tp->t_state |= TS_FLUSH;
657 }
658 splx(s);
659}
660
661dcmctl(dev, bits, how)
662 dev_t dev;
663 int bits, how;
664{
665 register dcregs *dcaddr;
666 register int unit, mbits;
667 int b, s;
84722262 668 register int msr;
12d43ee5
KM
669
670 unit = minor(dev);
671 b = 1 << (unit & 03);
6c1a1c86 672 dcaddr = (dcregs *)dcpdma[unit].p_addr;
12d43ee5
KM
673 s = spltty();
674 /* only channel 2 has modem control (what about line 3?) */
6c1a1c86 675 mbits = DML_DTR | DML_DSR | DML_CAR;
84722262
RC
676 switch (unit & 03) {
677 case 2:
12d43ee5
KM
678 mbits = 0;
679 if (dcaddr->dc_tcr & TCR_DTR2)
680 mbits |= DML_DTR;
84722262
RC
681 msr = dcaddr->dc_msr;
682 if (msr & MSR_CD2)
683 mbits |= DML_CAR;
6c1a1c86
RC
684 if (msr & MSR_DSR2) {
685 if (pmax_boardtype == DS_PMAX)
686 mbits |= DML_CAR | DML_DSR;
687 else
688 mbits |= DML_DSR;
689 }
84722262
RC
690 break;
691
84722262 692 case 3:
6c1a1c86
RC
693 if (pmax_boardtype != DS_PMAX) {
694 mbits = 0;
695 if (dcaddr->dc_tcr & TCR_DTR3)
696 mbits |= DML_DTR;
697 msr = dcaddr->dc_msr;
698 if (msr & MSR_CD3)
699 mbits |= DML_CAR;
700 if (msr & MSR_DSR3)
701 mbits |= DML_DSR;
702 }
84722262 703 }
12d43ee5
KM
704 switch (how) {
705 case DMSET:
706 mbits = bits;
707 break;
708
709 case DMBIS:
710 mbits |= bits;
711 break;
712
713 case DMBIC:
714 mbits &= ~bits;
715 break;
716
717 case DMGET:
718 (void) splx(s);
719 return (mbits);
720 }
84722262
RC
721 switch (unit & 03) {
722 case 2:
12d43ee5
KM
723 if (mbits & DML_DTR)
724 dcaddr->dc_tcr |= TCR_DTR2;
725 else
726 dcaddr->dc_tcr &= ~TCR_DTR2;
84722262
RC
727 break;
728
84722262 729 case 3:
6c1a1c86
RC
730 if (pmax_boardtype != DS_PMAX) {
731 if (mbits & DML_DTR)
732 dcaddr->dc_tcr |= TCR_DTR3;
733 else
734 dcaddr->dc_tcr &= ~TCR_DTR3;
735 }
12d43ee5
KM
736 }
737 if ((mbits & DML_DTR) && (dcsoftCAR[unit >> 2] & b))
738 dc_tty[unit].t_state |= TS_CARR_ON;
739 (void) splx(s);
740 return (mbits);
741}
742
743/*
744 * This is called by timeout() periodically.
745 * Check to see if modem status bits have changed.
746 */
6c1a1c86 747void
57373dbf
RC
748dcscan(arg)
749 void *arg;
12d43ee5
KM
750{
751 register dcregs *dcaddr;
752 register struct tty *tp;
753 register int i, bit, car;
754 int s;
755
756 s = spltty();
757 /* only channel 2 has modem control (what about line 3?) */
6c1a1c86 758 dcaddr = (dcregs *)dcpdma[i = 2].p_addr;
12d43ee5
KM
759 tp = &dc_tty[i];
760 bit = TCR_DTR2;
761 if (dcsoftCAR[i >> 2] & bit)
762 car = 1;
763 else
764 car = dcaddr->dc_msr & MSR_DSR2;
765 if (car) {
766 /* carrier present */
767 if (!(tp->t_state & TS_CARR_ON))
768 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
769 } else if ((tp->t_state & TS_CARR_ON) &&
770 (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
771 dcaddr->dc_tcr &= ~bit;
772 splx(s);
57373dbf 773 timeout(dcscan, (void *)0, hz);
12d43ee5
KM
774}
775
776/*
777 * ----------------------------------------------------------------------------
778 *
6c1a1c86 779 * dcGetc --
12d43ee5 780 *
6c1a1c86 781 * Read a character from a serial line.
12d43ee5
KM
782 *
783 * Results:
6c1a1c86 784 * A character read from the serial port.
12d43ee5
KM
785 *
786 * Side effects:
787 * None.
788 *
789 * ----------------------------------------------------------------------------
790 */
791int
6c1a1c86
RC
792dcGetc(dev)
793 dev_t dev;
12d43ee5
KM
794{
795 register dcregs *dcaddr;
796 register int c;
c74d1258 797 int s;
12d43ee5 798
6c1a1c86 799 dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
12d43ee5
KM
800 if (!dcaddr)
801 return (0);
84722262
RC
802 s = spltty();
803 for (;;) {
804 if (!(dcaddr->dc_csr & CSR_RDONE))
805 continue;
806 c = dcaddr->dc_rbuf;
807 DELAY(10);
6c1a1c86 808 if (((c >> 8) & 03) == (minor(dev) & 03))
84722262
RC
809 break;
810 }
811 splx(s);
6c1a1c86 812 return (c & 0xff);
84722262
RC
813}
814
12d43ee5 815/*
6c1a1c86 816 * Send a char on a port, non interrupt driven.
12d43ee5
KM
817 */
818void
6c1a1c86
RC
819dcPutc(dev, c)
820 dev_t dev;
12d43ee5
KM
821 int c;
822{
823 register dcregs *dcaddr;
824 register u_short tcr;
825 register int timeout;
6c1a1c86
RC
826 int s, line;
827
828 s = spltty();
12d43ee5 829
6c1a1c86 830 dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
12d43ee5 831 tcr = dcaddr->dc_tcr;
6c1a1c86 832 dcaddr->dc_tcr = tcr | (1 << minor(dev));
12d43ee5
KM
833 MachEmptyWriteBuffer();
834 DELAY(10);
835 while (1) {
836 /*
837 * Wait for transmitter to be not busy.
838 */
839 timeout = 1000000;
840 while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
841 timeout--;
842 if (timeout == 0) {
6c1a1c86 843 printf("dcPutc: timeout waiting for CSR_TRDY\n");
12d43ee5
KM
844 break;
845 }
846 line = (dcaddr->dc_csr >> 8) & 3;
847 /*
848 * Check to be sure its the right port.
849 */
6c1a1c86 850 if (line != minor(dev)) {
12d43ee5
KM
851 tcr |= 1 << line;
852 dcaddr->dc_tcr &= ~(1 << line);
853 MachEmptyWriteBuffer();
854 DELAY(10);
855 continue;
856 }
857 /*
858 * Start sending the character.
859 */
860 dcaddr->dc_tdr = dc_brk[0] | (c & 0xff);
861 MachEmptyWriteBuffer();
862 DELAY(10);
863 /*
864 * Wait for character to be sent.
865 */
866 while (1) {
867 /*
868 * cc -O bug: this code produces and infinite loop!
869 * while (!(dcaddr->dc_csr & CSR_TRDY))
870 * ;
871 */
872 timeout = 1000000;
873 while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
874 timeout--;
875 line = (dcaddr->dc_csr >> 8) & 3;
6c1a1c86 876 if (line != minor(dev)) {
12d43ee5
KM
877 tcr |= 1 << line;
878 dcaddr->dc_tcr &= ~(1 << line);
879 MachEmptyWriteBuffer();
880 DELAY(10);
881 continue;
882 }
6c1a1c86 883 dcaddr->dc_tcr &= ~(1 << minor(dev));
12d43ee5
KM
884 MachEmptyWriteBuffer();
885 DELAY(10);
886 break;
887 }
888 break;
889 }
890 /*
891 * Enable interrupts for other lines which became ready.
892 */
893 if (tcr & 0xF) {
894 dcaddr->dc_tcr = tcr;
895 MachEmptyWriteBuffer();
896 DELAY(10);
897 }
12d43ee5 898
6c1a1c86 899 splx(s);
12d43ee5
KM
900}
901#endif /* NDC */