1 /*
2 * Copyright (c) 1985, 1986 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)dhu.c 7.16 (Berkeley) 05/16/91
7 */
8
9 /*
10 * based on dh.c 6.3 84/03/15
11 * and on dmf.c 6.2 84/02/16
12 *
13 * Dave Johnson, Brown University Computer Science
14 * ddj%brown@csnet-relay
15 */
16
17 #include "dhu.h"
18 #if NDHU > 0
19 /*
20 * DHU-11 driver
21 */
22 #include "../include/pte.h"
23
24 #include "sys/param.h"
25 #include "sys/conf.h"
26 #include "sys/user.h"
27 #include "sys/proc.h"
28 #include "sys/ioctl.h"
29 #include "sys/tty.h"
30 #include "sys/ttydefaults.h"
31 #include "sys/map.h"
32 #include "sys/buf.h"
33 #include "sys/vm.h"
34 #include "sys/kernel.h"
35 #include "sys/syslog.h"
36
37 #include "uba.h"
38 #include "ubareg.h"
39 #include "ubavar.h"
40 #include "dhureg.h"
41
42 #include "sys/clist.h"
43 #include "sys/file.h"
44 #include "sys/uio.h"
45
46 /*
47 * Definition of the driver for the auto-configuration program.
48 */
49 int dhuprobe(), dhuattach(), dhurint(), dhuxint();
50 struct uba_device *dhuinfo[NDHU];
51 u_short dhustd[] = { 160440, 160500, 0 }; /* some common addresses */
52 struct uba_driver dhudriver =
53 { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
54
55 #define NDHULINE (NDHU*16)
56
57 #define UNIT(x) (minor(x))
58
59 #ifndef PORTSELECTOR
60 #define SPEED TTYDEF_SPEED
61 #define LFLAG TTYDEF_LFLAG
62 #else
63 #define SPEED B4800
64 #define LFLAG (TTYDEF_LFLAG & ~ECHO)
65 #endif
66
67 /*
68 * default receive silo timeout value -- valid values are 2..255
69 * number of ms. to delay between first char received and receive interrupt
70 *
71 * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
72 */
73 #define DHU_DEF_TIMO 20
74
75 /*
76 * Other values for silo timeout register defined here but not used:
77 * receive interrupt only on modem control or silo alarm (3/4 full)
78 */
79 #define DHU_POLL_TIMO 0
80 /*
81 * receive interrupt immediately on receive character
82 */
83 #define DHU_NO_TIMO 1
84
85 /*
86 * Local variables for the driver
87 */
88 /*
89 * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
90 * EXTA => 19200 baud
91 * EXTB => 2000 baud
92 */
93 struct speedtab dhuspeedtab[] = {
94 19200, 14,
95 9600, 13,
96 4800, 11,
97 2400, 10,
98 2000, 9,
99 1800, 8,
100 1200, 7,
101 600, 6,
102 300, 5,
103 150, 4,
104 134, 3,
105 110, 2,
106 75, 1,
107 0, 0,
108 EXTA, 14,
109 EXTB, 9,
110 -1, -1,
111 };
112
113 short dhusoftCAR[NDHU];
114
115 struct tty dhu_tty[NDHULINE];
116 int ndhu = NDHULINE;
117 int dhuact; /* mask of active dhu's */
118 int dhustart(), ttrstrt();
119
120 /*
121 * The clist space is mapped by one terminal driver onto each UNIBUS.
122 * The identity of the board which allocated resources is recorded,
123 * so the process may be repeated after UNIBUS resets.
124 * The UBACVT macro converts a clist space address for unibus uban
125 * into an i/o space address for the DMA routine.
126 */
127 int dhu_uballoc[NUBA]; /* which dhu (if any) allocated unibus map */
128 int cbase[NUBA]; /* base address of clists in unibus map */
129 #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
130
131 /*
132 * Routine for configuration to force a dhu to interrupt.
133 */
134 /*ARGSUSED*/
dhuprobe(reg)135 dhuprobe(reg)
136 caddr_t reg;
137 {
138 register int br, cvec; /* these are ``value-result'' */
139 register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
140 int i;
141
142 #ifdef lint
143 br = 0; cvec = br; br = cvec;
144 if (ndhu == 0) ndhu = 1;
145 dhurint(0); dhuxint(0);
146 #endif
147 /*
148 * The basic idea here is:
149 * do a self-test by setting the Master-Reset bit
150 * if this fails, then return
151 * if successful, there will be 8 diagnostic codes in RX FIFO
152 * therefore ask for a Received-Data-Available interrupt
153 * wait for it...
154 * reset the interrupt-enable bit and flush out the diag. codes
155 */
156 dhuaddr->dhucsr = DHU_CS_MCLR;
157 for (i = 0; i < 1000; i++) {
158 DELAY(10000);
159 if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
160 break;
161 }
162 if (dhuaddr->dhucsr&DHU_CS_MCLR)
163 return(0);
164 if (dhuaddr->dhucsr&DHU_CS_DFAIL)
165 return(0);
166 dhuaddr->dhucsr = DHU_CS_RIE;
167 DELAY(1000);
168 dhuaddr->dhucsr = 0;
169 while (dhuaddr->dhurbuf < 0)
170 /* void */;
171 return (sizeof(struct dhudevice));
172 }
173
174 /*
175 * Routine called to attach a dhu.
176 */
177 dhuattach(ui)
178 struct uba_device *ui;
179 {
180
181 dhusoftCAR[ui->ui_unit] = ui->ui_flags;
182 cbase[ui->ui_ubanum] = -1;
183 dhu_uballoc[ui->ui_ubanum] = -1;
184 }
185
186 /*
187 * Open a DHU11 line, mapping the clist onto the uba if this
188 * is the first dhu on this uba. Turn on this dhu if this is
189 * the first use of it.
190 */
191 /*ARGSUSED*/
dhuopen(dev,flag)192 dhuopen(dev, flag)
193 dev_t dev;
194 {
195 register struct tty *tp;
196 register int unit, dhu;
197 register struct dhudevice *addr;
198 register struct uba_device *ui;
199 int s, error = 0;
200 extern dhuparam();
201
202 unit = UNIT(dev);
203 dhu = unit >> 4;
204 if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
205 return (ENXIO);
206 tp = &dhu_tty[unit];
207 if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
208 return (EBUSY);
209 addr = (struct dhudevice *)ui->ui_addr;
210 tp->t_addr = (caddr_t)addr;
211 tp->t_oproc = dhustart;
212 tp->t_param = dhuparam;
213 /*
214 * While setting up state for this uba and this dhu,
215 * block uba resets which can clear the state.
216 */
217 s = spl5();
218 if (cbase[ui->ui_ubanum] == -1) {
219 dhu_uballoc[ui->ui_ubanum] = dhu;
220 cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
221 (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
222 }
223 if ((dhuact&(1<<dhu)) == 0) {
224 addr->dhucsr = DHU_SELECT(0) | DHU_IE;
225 addr->dhutimo = DHU_DEF_TIMO;
226 dhuact |= (1<<dhu);
227 /* anything else to configure whole board */
228 }
229 (void) splx(s);
230 /*
231 * If this is first open, initialize tty state to default.
232 */
233 if ((tp->t_state&TS_ISOPEN) == 0) {
234 tp->t_state |= TS_WOPEN;
235 ttychars(tp);
236 #ifndef PORTSELECTOR
237 if (tp->t_ospeed == 0) {
238 #endif
239 tp->t_ispeed = SPEED;
240 tp->t_ospeed = SPEED;
241 ttsetwater(tp);
242 tp->t_iflag = TTYDEF_IFLAG;
243 tp->t_oflag = TTYDEF_OFLAG;
244 tp->t_lflag = LFLAG;
245 tp->t_cflag = TTYDEF_CFLAG;
246 #ifdef PORTSELECTOR
247 tp->t_cflag |= HUPCL;
248 #else
249 }
250 #endif
251 tp->t_dev = dev;
252 dhuparam(tp, &tp->t_termios);
253 }
254 /*
255 * Wait for carrier, then process line discipline specific open.
256 */
257 s = spltty();
258 if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
259 (dhusoftCAR[dhu] & (1<<(unit&0xf))))
260 tp->t_state |= TS_CARR_ON;
261 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
262 (tp->t_state & TS_CARR_ON) == 0) {
263 tp->t_state |= TS_WOPEN;
264 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
265 ttopen, 0))
266 break;
267 }
268 (void) splx(s);
269 if (error)
270 return (error);
271 return ((*linesw[tp->t_line].l_open)(dev, tp));
272 }
273
274 /*
275 * Close a DHU11 line, turning off the modem control.
276 */
277 /*ARGSUSED*/
dhuclose(dev,flag,mode,p)278 dhuclose(dev, flag, mode, p)
279 dev_t dev;
280 int flag, mode;
281 struct proc *p;
282 {
283 register struct tty *tp;
284 register unit;
285
286 unit = UNIT(dev);
287 tp = &dhu_tty[unit];
288 (*linesw[tp->t_line].l_close)(tp, flag);
289 (void) dhumctl(unit, DHU_BRK, DMBIC);
290 if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
291 (tp->t_state&TS_ISOPEN) == 0) {
292 #ifdef PORTSELECTOR
293 (void) dhumctl(unit, DHU_OFF, DMSET);
294 /* Hold DTR low for 0.5 seconds */
295 (void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2);
296 #else
297 (void) dhumctl(unit, DHU_OFF, DMSET);
298 #endif PORTSELECTOR
299 }
300 return (ttyclose(tp));
301 }
302
dhuread(dev,uio,flag)303 dhuread(dev, uio, flag)
304 dev_t dev;
305 struct uio *uio;
306 {
307 register struct tty *tp = &dhu_tty[UNIT(dev)];
308
309 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
310 }
311
dhuwrite(dev,uio,flag)312 dhuwrite(dev, uio, flag)
313 dev_t dev;
314 struct uio *uio;
315 {
316 register struct tty *tp = &dhu_tty[UNIT(dev)];
317
318 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
319 }
320
321 /*
322 * DHU11 receiver interrupt.
323 */
dhurint(dhu)324 dhurint(dhu)
325 int dhu;
326 {
327 register struct tty *tp;
328 register creg, c;
329 register struct dhudevice *addr;
330 register struct tty *tp0;
331 register struct uba_device *ui;
332 register line;
333 int overrun = 0;
334
335 #ifdef QBA
336 (void) spltty();
337 #endif
338 ui = dhuinfo[dhu];
339 if (ui == 0 || ui->ui_alive == 0)
340 return;
341 addr = (struct dhudevice *)ui->ui_addr;
342 tp0 = &dhu_tty[dhu<<4];
343 /*
344 * Loop fetching characters from the silo for this
345 * dhu until there are no more in the silo.
346 */
347 while ((creg = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */
348 line = DHU_RX_LINE(creg);
349 tp = tp0 + line;
350 c = creg & 0xff;
351 if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
352 /*
353 * modem changed or diag info
354 */
355 if (creg & DHU_RB_DIAG) {
356 /* decode diagnostic messages */
357 continue;
358 }
359 if (creg & DHU_ST_DCD)
360 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
361 else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
362 (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
363 (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
364 continue;
365 }
366 if ((tp->t_state&TS_ISOPEN) == 0) {
367 wakeup((caddr_t)&tp->t_rawq);
368 #ifdef PORTSELECTOR
369 if ((tp->t_state&TS_WOPEN) == 0)
370 #endif
371 continue;
372 }
373 if (creg & DHU_RB_PE)
374 c |= TTY_PE;
375 if (creg & DHU_RB_DO && overrun == 0) {
376 log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
377 overrun = 1;
378 }
379 if (creg & DHU_RB_FE)
380 c |= TTY_FE;
381
382 (*linesw[tp->t_line].l_rint)(c, tp);
383 }
384 }
385
386 /*
387 * Ioctl for DHU11.
388 */
389 /*ARGSUSED*/
dhuioctl(dev,cmd,data,flag)390 dhuioctl(dev, cmd, data, flag)
391 caddr_t data;
392 {
393 register struct tty *tp;
394 register int unit = UNIT(dev);
395 int error;
396
397 tp = &dhu_tty[unit];
398 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
399 if (error >= 0)
400 return (error);
401 error = ttioctl(tp, cmd, data, flag);
402 if (error >= 0)
403 return (error);
404
405 switch (cmd) {
406 case TIOCSBRK:
407 (void) dhumctl(unit, DHU_BRK, DMBIS);
408 break;
409
410 case TIOCCBRK:
411 (void) dhumctl(unit, DHU_BRK, DMBIC);
412 break;
413
414 case TIOCSDTR:
415 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
416 break;
417
418 case TIOCCDTR:
419 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
420 break;
421
422 case TIOCMSET:
423 (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
424 break;
425
426 case TIOCMBIS:
427 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
428 break;
429
430 case TIOCMBIC:
431 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
432 break;
433
434 case TIOCMGET:
435 *(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
436 break;
437 default:
438 return (ENOTTY);
439 }
440 return (0);
441 }
442
dmtodhu(bits)443 dmtodhu(bits)
444 register int bits;
445 {
446 register int b = 0;
447
448 if (bits & DML_RTS) b |= DHU_RTS;
449 if (bits & DML_DTR) b |= DHU_DTR;
450 if (bits & DML_LE) b |= DHU_LE;
451 return(b);
452 }
453
dhutodm(bits)454 dhutodm(bits)
455 register int bits;
456 {
457 register int b = 0;
458
459 if (bits & DHU_DSR) b |= DML_DSR;
460 if (bits & DHU_RNG) b |= DML_RNG;
461 if (bits & DHU_CAR) b |= DML_CAR;
462 if (bits & DHU_CTS) b |= DML_CTS;
463 if (bits & DHU_RTS) b |= DML_RTS;
464 if (bits & DHU_DTR) b |= DML_DTR;
465 if (bits & DHU_LE) b |= DML_LE;
466 return(b);
467 }
468
469
470 /*
471 * Set parameters from open or stty into the DHU hardware
472 * registers. Impossible values for speed or character
473 * size are ignored and not copied back into tp.
474 */
dhuparam(tp,want)475 dhuparam(tp, want)
476 register struct tty *tp;
477 register struct termios *want;
478 {
479 register int unit = UNIT(tp->t_dev);
480 register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
481 register int lpar;
482 register long cflag;
483 register int incode, outcode;
484 int s;
485
486 /*
487 * Block interrupts so parameters will be set
488 * before the line interrupts.
489 */
490 s = spltty();
491
492 if (want->c_ospeed == 0) {
493 tp->t_ospeed = 0;
494 tp->t_cflag |= HUPCL;
495 (void)dhumctl(unit, DHU_OFF, DMSET);
496 splx(s);
497 return (0);
498 }
499
500 if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
501 tp->t_ospeed = want->c_ospeed;
502 else
503 outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
504
505 if (want->c_ispeed == 0) {
506 tp->t_ispeed = 0;
507 incode = outcode;
508 } else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
509 tp->t_ispeed = want->c_ispeed;
510 else
511 incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
512
513 lpar = ((char)outcode<<12) | ((char)incode<<8);
514
515 switch (want->c_cflag&CSIZE) {
516 case CS6: case CS7: case CS8:
517 tp->t_cflag = want->c_cflag;
518 break;
519 default:
520 tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
521 }
522 cflag = tp->t_cflag;
523
524 switch(cflag&CSIZE) {
525 case CS6:
526 lpar |= DHU_LP_BITS6;
527 break;
528 case CS7:
529 lpar |= DHU_LP_BITS7;
530 break;
531 case CS8:
532 lpar |= DHU_LP_BITS8;
533 break;
534 }
535 if (cflag&PARENB) {
536 lpar |= DHU_LP_PENABLE;
537 if ((cflag&PARODD) == 0)
538 lpar |= DHU_LP_EPAR;
539 }
540 if (cflag&CSTOPB)
541 lpar |= DHU_LP_TWOSB;
542
543 addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
544 addr->dhulpr = lpar;
545 splx(s);
546 return (0);
547 }
548
549 /*
550 * DHU11 transmitter interrupt.
551 * Restart each line which used to be active but has
552 * terminated transmission since the last interrupt.
553 */
dhuxint(dhu)554 dhuxint(dhu)
555 int dhu;
556 {
557 register struct tty *tp;
558 register struct dhudevice *addr;
559 register struct tty *tp0;
560 register struct uba_device *ui;
561 register int line, t;
562 u_short cntr;
563
564 #ifdef QBA
565 (void) spl5();
566 #endif
567 ui = dhuinfo[dhu];
568 tp0 = &dhu_tty[dhu<<4];
569 addr = (struct dhudevice *)ui->ui_addr;
570 while ((t = addr->dhucsrh) & DHU_CSH_TI) {
571 line = DHU_TX_LINE(t);
572 tp = tp0 + line;
573 tp->t_state &= ~TS_BUSY;
574 if (t & DHU_CSH_NXM) {
575 printf("dhu(%d,%d): NXM fault\n", dhu, line);
576 /* SHOULD RESTART OR SOMETHING... */
577 }
578 if (tp->t_state&TS_FLUSH)
579 tp->t_state &= ~TS_FLUSH;
580 else {
581 addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
582 /*
583 * Do arithmetic in a short to make up
584 * for lost 16&17 bits.
585 */
586 cntr = addr->dhubar1 -
587 UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
588 ndflush(&tp->t_outq, (int)cntr);
589 }
590 if (tp->t_line)
591 (*linesw[tp->t_line].l_start)(tp);
592 else
593 dhustart(tp);
594 }
595 }
596
597 /*
598 * Start (restart) transmission on the given DHU11 line.
599 */
dhustart(tp)600 dhustart(tp)
601 register struct tty *tp;
602 {
603 register struct dhudevice *addr;
604 register int car, dhu, unit, nch;
605 int s;
606
607 unit = minor(tp->t_dev);
608 dhu = unit >> 4;
609 unit &= 0xf;
610 addr = (struct dhudevice *)tp->t_addr;
611
612 /*
613 * Must hold interrupts in following code to prevent
614 * state of the tp from changing.
615 */
616 s = spl5();
617 /*
618 * If it's currently active, or delaying, no need to do anything.
619 */
620 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
621 goto out;
622 /*
623 * If there are sleepers, and output has drained below low
624 * water mark, wake up the sleepers..
625 */
626 if (tp->t_outq.c_cc <= tp->t_lowat) {
627 if (tp->t_state&TS_ASLEEP) {
628 tp->t_state &= ~TS_ASLEEP;
629 wakeup((caddr_t)&tp->t_outq);
630 }
631 if (tp->t_wsel) {
632 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
633 tp->t_wsel = 0;
634 tp->t_state &= ~TS_WCOLL;
635 }
636 }
637 /*
638 * Now restart transmission unless the output queue is
639 * empty.
640 */
641 if (tp->t_outq.c_cc == 0)
642 goto out;
643 if (1 || !(tp->t_oflag & OPOST)) /*XXX*/
644 nch = ndqb(&tp->t_outq, 0);
645 else {
646 nch = ndqb(&tp->t_outq, 0200);
647 /*
648 * If first thing on queue is a delay process it.
649 */
650 if (nch == 0) {
651 nch = getc(&tp->t_outq);
652 timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
653 tp->t_state |= TS_TIMEOUT;
654 goto out;
655 }
656 }
657 /*
658 * If characters to transmit, restart transmission.
659 */
660 if (nch) {
661 car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
662 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
663 addr->dhulcr &= ~DHU_LC_TXABORT;
664 addr->dhubcr = nch;
665 addr->dhubar1 = car;
666 addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
667 DHU_BA2_DMAGO;
668 tp->t_state |= TS_BUSY;
669 }
670 out:
671 splx(s);
672 }
673
674 /*
675 * Stop output on a line, e.g. for ^S/^Q or output flush.
676 */
677 /*ARGSUSED*/
dhustop(tp,flag)678 dhustop(tp, flag)
679 register struct tty *tp;
680 {
681 register struct dhudevice *addr;
682 register int unit, s;
683
684 addr = (struct dhudevice *)tp->t_addr;
685 /*
686 * Block input/output interrupts while messing with state.
687 */
688 s = spl5();
689 if (tp->t_state & TS_BUSY) {
690 /*
691 * Device is transmitting; stop output
692 * by selecting the line and setting the
693 * abort xmit bit. We will get an xmit interrupt,
694 * where we will figure out where to continue the
695 * next time the transmitter is enabled. If
696 * TS_FLUSH is set, the outq will be flushed.
697 * In either case, dhustart will clear the TXABORT bit.
698 */
699 unit = minor(tp->t_dev);
700 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
701 addr->dhulcr |= DHU_LC_TXABORT;
702 if ((tp->t_state&TS_TTSTOP)==0)
703 tp->t_state |= TS_FLUSH;
704 }
705 (void) splx(s);
706 }
707
708 /*
709 * DHU11 modem control
710 */
dhumctl(dev,bits,how)711 dhumctl(dev, bits, how)
712 dev_t dev;
713 int bits, how;
714 {
715 register struct dhudevice *dhuaddr;
716 register int unit, mbits;
717 int s;
718
719 unit = UNIT(dev);
720 dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
721 unit &= 0xf;
722 s = spl5();
723 dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
724 /*
725 * combine byte from stat register (read only, bits 16..23)
726 * with lcr register (read write, bits 0..15).
727 */
728 mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
729 switch (how) {
730 case DMSET:
731 mbits = (mbits & 0xff0000) | bits;
732 break;
733
734 case DMBIS:
735 mbits |= bits;
736 break;
737
738 case DMBIC:
739 mbits &= ~bits;
740 break;
741
742 case DMGET:
743 (void) splx(s);
744 return(mbits);
745 }
746 dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
747 dhuaddr->dhulcr2 = DHU_LC2_TXEN;
748 (void) splx(s);
749 return(mbits);
750 }
751
752 /*
753 * Reset state of driver if UBA reset was necessary.
754 * Reset the line and modem control registers.
755 * restart transmitters.
756 */
dhureset(uban)757 dhureset(uban)
758 int uban;
759 {
760 register int dhu, unit;
761 register struct tty *tp;
762 register struct uba_device *ui;
763 register struct dhudevice *addr;
764 int i;
765
766 for (dhu = 0; dhu < NDHU; dhu++) {
767 ui = dhuinfo[dhu];
768 if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
769 continue;
770 printf(" dhu%d", dhu);
771 if (dhu_uballoc[uban] == dhu) {
772 int info;
773
774 info = uballoc(uban, (caddr_t)cfree,
775 nclist * sizeof(struct cblock), UBA_CANTWAIT);
776 if (info)
777 cbase[uban] = UBAI_ADDR(info);
778 else {
779 printf(" [can't get uba map]");
780 cbase[uban] = -1;
781 }
782 }
783 addr = (struct dhudevice *)ui->ui_addr;
784 addr->dhucsr = DHU_SELECT(0) | DHU_IE;
785 addr->dhutimo = DHU_DEF_TIMO;
786 unit = dhu * 16;
787 for (i = 0; i < 16; i++) {
788 tp = &dhu_tty[unit];
789 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
790 dhuparam(tp, &tp->t_termios);
791 (void)dhumctl(unit, DHU_ON, DMSET);
792 tp->t_state &= ~TS_BUSY;
793 dhustart(tp);
794 }
795 unit++;
796 }
797 }
798 }
799 #endif
800