123322Smckusick /*
229211Smckusick * Copyright (c) 1985, 1986 Regents of the University of California.
323322Smckusick * All rights reserved. The Berkeley software License Agreement
423322Smckusick * specifies the terms and conditions for redistribution.
523322Smckusick *
6*49759Smarc * @(#)dhu.c 7.16 (Berkeley) 05/16/91
723322Smckusick */
820976Smckusick
920976Smckusick /*
1020976Smckusick * based on dh.c 6.3 84/03/15
1120976Smckusick * and on dmf.c 6.2 84/02/16
1220976Smckusick *
1320976Smckusick * Dave Johnson, Brown University Computer Science
1420976Smckusick * ddj%brown@csnet-relay
1520976Smckusick */
1620976Smckusick
1720976Smckusick #include "dhu.h"
1820976Smckusick #if NDHU > 0
1920976Smckusick /*
2020976Smckusick * DHU-11 driver
2120976Smckusick */
2245804Sbostic #include "../include/pte.h"
2320976Smckusick
2445804Sbostic #include "sys/param.h"
2545804Sbostic #include "sys/conf.h"
2645804Sbostic #include "sys/user.h"
2745804Sbostic #include "sys/proc.h"
2845804Sbostic #include "sys/ioctl.h"
2945804Sbostic #include "sys/tty.h"
3045804Sbostic #include "sys/ttydefaults.h"
3145804Sbostic #include "sys/map.h"
3245804Sbostic #include "sys/buf.h"
3345804Sbostic #include "sys/vm.h"
3445804Sbostic #include "sys/kernel.h"
3545804Sbostic #include "sys/syslog.h"
3620976Smckusick
3720976Smckusick #include "uba.h"
3820976Smckusick #include "ubareg.h"
3920976Smckusick #include "ubavar.h"
4020976Smckusick #include "dhureg.h"
4120976Smckusick
4245804Sbostic #include "sys/clist.h"
4345804Sbostic #include "sys/file.h"
4445804Sbostic #include "sys/uio.h"
4520976Smckusick
4620976Smckusick /*
4720976Smckusick * Definition of the driver for the auto-configuration program.
4820976Smckusick */
4920976Smckusick int dhuprobe(), dhuattach(), dhurint(), dhuxint();
5020976Smckusick struct uba_device *dhuinfo[NDHU];
5125519Stef u_short dhustd[] = { 160440, 160500, 0 }; /* some common addresses */
5220976Smckusick struct uba_driver dhudriver =
5320976Smckusick { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
5420976Smckusick
5520976Smckusick #define NDHULINE (NDHU*16)
5620976Smckusick
5720976Smckusick #define UNIT(x) (minor(x))
5820976Smckusick
5920976Smckusick #ifndef PORTSELECTOR
6037606Smarc #define SPEED TTYDEF_SPEED
6137606Smarc #define LFLAG TTYDEF_LFLAG
6220976Smckusick #else
6337606Smarc #define SPEED B4800
6437606Smarc #define LFLAG (TTYDEF_LFLAG & ~ECHO)
6520976Smckusick #endif
6620976Smckusick
6720976Smckusick /*
6820976Smckusick * default receive silo timeout value -- valid values are 2..255
6920976Smckusick * number of ms. to delay between first char received and receive interrupt
7020976Smckusick *
7120976Smckusick * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
7220976Smckusick */
7320976Smckusick #define DHU_DEF_TIMO 20
7420976Smckusick
7520976Smckusick /*
7620976Smckusick * Other values for silo timeout register defined here but not used:
7720976Smckusick * receive interrupt only on modem control or silo alarm (3/4 full)
7820976Smckusick */
7920976Smckusick #define DHU_POLL_TIMO 0
8020976Smckusick /*
8120976Smckusick * receive interrupt immediately on receive character
8220976Smckusick */
8320976Smckusick #define DHU_NO_TIMO 1
8420976Smckusick
8520976Smckusick /*
8620976Smckusick * Local variables for the driver
8720976Smckusick */
8820976Smckusick /*
8920976Smckusick * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
9020976Smckusick * EXTA => 19200 baud
9120976Smckusick * EXTB => 2000 baud
9220976Smckusick */
9337606Smarc struct speedtab dhuspeedtab[] = {
9437606Smarc 19200, 14,
9537606Smarc 9600, 13,
9637606Smarc 4800, 11,
9737606Smarc 2400, 10,
9837606Smarc 2000, 9,
9937606Smarc 1800, 8,
10037606Smarc 1200, 7,
10137606Smarc 600, 6,
10237606Smarc 300, 5,
10337606Smarc 150, 4,
10437606Smarc 134, 3,
10537606Smarc 110, 2,
10637606Smarc 75, 1,
10737606Smarc 0, 0,
10839061Smarc EXTA, 14,
10939061Smarc EXTB, 9,
11037606Smarc -1, -1,
11137606Smarc };
11220976Smckusick
11320976Smckusick short dhusoftCAR[NDHU];
11420976Smckusick
11520976Smckusick struct tty dhu_tty[NDHULINE];
11620976Smckusick int ndhu = NDHULINE;
11720976Smckusick int dhuact; /* mask of active dhu's */
11820976Smckusick int dhustart(), ttrstrt();
11920976Smckusick
12020976Smckusick /*
12130322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS.
12230322Skarels * The identity of the board which allocated resources is recorded,
12330322Skarels * so the process may be repeated after UNIBUS resets.
12420976Smckusick * The UBACVT macro converts a clist space address for unibus uban
12520976Smckusick * into an i/o space address for the DMA routine.
12620976Smckusick */
12730322Skarels int dhu_uballoc[NUBA]; /* which dhu (if any) allocated unibus map */
12830322Skarels int cbase[NUBA]; /* base address of clists in unibus map */
12920976Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
13020976Smckusick
13120976Smckusick /*
13220976Smckusick * Routine for configuration to force a dhu to interrupt.
13320976Smckusick */
13420976Smckusick /*ARGSUSED*/
dhuprobe(reg)13520976Smckusick dhuprobe(reg)
13620976Smckusick caddr_t reg;
13720976Smckusick {
13820976Smckusick register int br, cvec; /* these are ``value-result'' */
13920976Smckusick register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
14020976Smckusick int i;
14120976Smckusick
14220976Smckusick #ifdef lint
14320976Smckusick br = 0; cvec = br; br = cvec;
14420976Smckusick if (ndhu == 0) ndhu = 1;
14520976Smckusick dhurint(0); dhuxint(0);
14620976Smckusick #endif
14720976Smckusick /*
14820976Smckusick * The basic idea here is:
14920976Smckusick * do a self-test by setting the Master-Reset bit
15020976Smckusick * if this fails, then return
15120976Smckusick * if successful, there will be 8 diagnostic codes in RX FIFO
15220976Smckusick * therefore ask for a Received-Data-Available interrupt
15320976Smckusick * wait for it...
15420976Smckusick * reset the interrupt-enable bit and flush out the diag. codes
15520976Smckusick */
15620976Smckusick dhuaddr->dhucsr = DHU_CS_MCLR;
15720976Smckusick for (i = 0; i < 1000; i++) {
15820976Smckusick DELAY(10000);
15920976Smckusick if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
16020976Smckusick break;
16120976Smckusick }
16220976Smckusick if (dhuaddr->dhucsr&DHU_CS_MCLR)
16320976Smckusick return(0);
16420976Smckusick if (dhuaddr->dhucsr&DHU_CS_DFAIL)
16520976Smckusick return(0);
16620976Smckusick dhuaddr->dhucsr = DHU_CS_RIE;
16720976Smckusick DELAY(1000);
16820976Smckusick dhuaddr->dhucsr = 0;
16920976Smckusick while (dhuaddr->dhurbuf < 0)
17020976Smckusick /* void */;
17120976Smckusick return (sizeof(struct dhudevice));
17220976Smckusick }
17320976Smckusick
17420976Smckusick /*
17520976Smckusick * Routine called to attach a dhu.
17620976Smckusick */
17720976Smckusick dhuattach(ui)
17820976Smckusick struct uba_device *ui;
17920976Smckusick {
18020976Smckusick
18120976Smckusick dhusoftCAR[ui->ui_unit] = ui->ui_flags;
18226220Skarels cbase[ui->ui_ubanum] = -1;
18336610Sbostic dhu_uballoc[ui->ui_ubanum] = -1;
18420976Smckusick }
18520976Smckusick
18620976Smckusick /*
18720976Smckusick * Open a DHU11 line, mapping the clist onto the uba if this
18820976Smckusick * is the first dhu on this uba. Turn on this dhu if this is
18920976Smckusick * the first use of it.
19020976Smckusick */
19120976Smckusick /*ARGSUSED*/
dhuopen(dev,flag)19220976Smckusick dhuopen(dev, flag)
19320976Smckusick dev_t dev;
19420976Smckusick {
19520976Smckusick register struct tty *tp;
19620976Smckusick register int unit, dhu;
19720976Smckusick register struct dhudevice *addr;
19820976Smckusick register struct uba_device *ui;
19940729Skarels int s, error = 0;
20037606Smarc extern dhuparam();
20120976Smckusick
20220976Smckusick unit = UNIT(dev);
20320976Smckusick dhu = unit >> 4;
20420976Smckusick if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
20520976Smckusick return (ENXIO);
20620976Smckusick tp = &dhu_tty[unit];
20720976Smckusick if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
20820976Smckusick return (EBUSY);
20920976Smckusick addr = (struct dhudevice *)ui->ui_addr;
21020976Smckusick tp->t_addr = (caddr_t)addr;
21120976Smckusick tp->t_oproc = dhustart;
21237606Smarc tp->t_param = dhuparam;
21320976Smckusick /*
21420976Smckusick * While setting up state for this uba and this dhu,
21520976Smckusick * block uba resets which can clear the state.
21620976Smckusick */
21720976Smckusick s = spl5();
21826220Skarels if (cbase[ui->ui_ubanum] == -1) {
21930322Skarels dhu_uballoc[ui->ui_ubanum] = dhu;
22030322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22130322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22220976Smckusick }
22320976Smckusick if ((dhuact&(1<<dhu)) == 0) {
22420976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE;
22520976Smckusick addr->dhutimo = DHU_DEF_TIMO;
22620976Smckusick dhuact |= (1<<dhu);
22720976Smckusick /* anything else to configure whole board */
22820976Smckusick }
22920976Smckusick (void) splx(s);
23020976Smckusick /*
23120976Smckusick * If this is first open, initialize tty state to default.
23220976Smckusick */
23320976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) {
23444393Smarc tp->t_state |= TS_WOPEN;
23520976Smckusick ttychars(tp);
23620976Smckusick #ifndef PORTSELECTOR
23737606Smarc if (tp->t_ospeed == 0) {
23837606Smarc #endif
23937606Smarc tp->t_ispeed = SPEED;
24037606Smarc tp->t_ospeed = SPEED;
24137606Smarc ttsetwater(tp);
24237606Smarc tp->t_iflag = TTYDEF_IFLAG;
24337606Smarc tp->t_oflag = TTYDEF_OFLAG;
24437606Smarc tp->t_lflag = LFLAG;
24537606Smarc tp->t_cflag = TTYDEF_CFLAG;
24637606Smarc #ifdef PORTSELECTOR
24737606Smarc tp->t_cflag |= HUPCL;
24837606Smarc #else
24920976Smckusick }
25037606Smarc #endif
25120976Smckusick tp->t_dev = dev;
25237606Smarc dhuparam(tp, &tp->t_termios);
25320976Smckusick }
25420976Smckusick /*
25520976Smckusick * Wait for carrier, then process line discipline specific open.
25620976Smckusick */
25737606Smarc s = spltty();
25820976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
25920976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf))))
26020976Smckusick tp->t_state |= TS_CARR_ON;
26140729Skarels while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
26240729Skarels (tp->t_state & TS_CARR_ON) == 0) {
26320976Smckusick tp->t_state |= TS_WOPEN;
26444393Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
26544393Smarc ttopen, 0))
26640729Skarels break;
26720976Smckusick }
26820976Smckusick (void) splx(s);
26940729Skarels if (error)
27040729Skarels return (error);
27120976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp));
27220976Smckusick }
27320976Smckusick
27420976Smckusick /*
27520976Smckusick * Close a DHU11 line, turning off the modem control.
27620976Smckusick */
27720976Smckusick /*ARGSUSED*/
dhuclose(dev,flag,mode,p)278*49759Smarc dhuclose(dev, flag, mode, p)
27920976Smckusick dev_t dev;
280*49759Smarc int flag, mode;
281*49759Smarc struct proc *p;
28220976Smckusick {
28320976Smckusick register struct tty *tp;
28420976Smckusick register unit;
28520976Smckusick
28620976Smckusick unit = UNIT(dev);
28720976Smckusick tp = &dhu_tty[unit];
288*49759Smarc (*linesw[tp->t_line].l_close)(tp, flag);
28920976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC);
29037606Smarc if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
29140729Skarels (tp->t_state&TS_ISOPEN) == 0) {
29220976Smckusick #ifdef PORTSELECTOR
29320976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET);
29420976Smckusick /* Hold DTR low for 0.5 seconds */
29540729Skarels (void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2);
29620976Smckusick #else
29720976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET);
29820976Smckusick #endif PORTSELECTOR
29940729Skarels }
30040729Skarels return (ttyclose(tp));
30120976Smckusick }
30220976Smckusick
dhuread(dev,uio,flag)30339061Smarc dhuread(dev, uio, flag)
30420976Smckusick dev_t dev;
30520976Smckusick struct uio *uio;
30620976Smckusick {
30720976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)];
30820976Smckusick
30939061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
31020976Smckusick }
31120976Smckusick
dhuwrite(dev,uio,flag)31239061Smarc dhuwrite(dev, uio, flag)
31320976Smckusick dev_t dev;
31420976Smckusick struct uio *uio;
31520976Smckusick {
31620976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)];
31720976Smckusick
31839061Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
31920976Smckusick }
32020976Smckusick
32120976Smckusick /*
32220976Smckusick * DHU11 receiver interrupt.
32320976Smckusick */
dhurint(dhu)32420976Smckusick dhurint(dhu)
32520976Smckusick int dhu;
32620976Smckusick {
32720976Smckusick register struct tty *tp;
32837606Smarc register creg, c;
32920976Smckusick register struct dhudevice *addr;
33020976Smckusick register struct tty *tp0;
33120976Smckusick register struct uba_device *ui;
33220976Smckusick register line;
33320976Smckusick int overrun = 0;
33420976Smckusick
33535401Stef #ifdef QBA
33637606Smarc (void) spltty();
33727256Skridle #endif
33820976Smckusick ui = dhuinfo[dhu];
33920976Smckusick if (ui == 0 || ui->ui_alive == 0)
34020976Smckusick return;
34120976Smckusick addr = (struct dhudevice *)ui->ui_addr;
34220976Smckusick tp0 = &dhu_tty[dhu<<4];
34320976Smckusick /*
34420976Smckusick * Loop fetching characters from the silo for this
34520976Smckusick * dhu until there are no more in the silo.
34620976Smckusick */
34737606Smarc while ((creg = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */
34837606Smarc line = DHU_RX_LINE(creg);
34920976Smckusick tp = tp0 + line;
35037606Smarc c = creg & 0xff;
35137606Smarc if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
35220976Smckusick /*
35320976Smckusick * modem changed or diag info
35420976Smckusick */
35537606Smarc if (creg & DHU_RB_DIAG) {
35620976Smckusick /* decode diagnostic messages */
35720976Smckusick continue;
35820976Smckusick }
35937606Smarc if (creg & DHU_ST_DCD)
36025395Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1);
36125395Skarels else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
36225395Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36325395Skarels (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
36420976Smckusick continue;
36520976Smckusick }
36620976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) {
36720976Smckusick wakeup((caddr_t)&tp->t_rawq);
36820976Smckusick #ifdef PORTSELECTOR
36920976Smckusick if ((tp->t_state&TS_WOPEN) == 0)
37020976Smckusick #endif
37125395Skarels continue;
37220976Smckusick }
37339061Smarc if (creg & DHU_RB_PE)
37439061Smarc c |= TTY_PE;
37539061Smarc if (creg & DHU_RB_DO && overrun == 0) {
37639061Smarc log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
37739061Smarc overrun = 1;
37820976Smckusick }
37939061Smarc if (creg & DHU_RB_FE)
38039061Smarc c |= TTY_FE;
38137606Smarc
38239061Smarc (*linesw[tp->t_line].l_rint)(c, tp);
38320976Smckusick }
38420976Smckusick }
38520976Smckusick
38620976Smckusick /*
38720976Smckusick * Ioctl for DHU11.
38820976Smckusick */
38920976Smckusick /*ARGSUSED*/
dhuioctl(dev,cmd,data,flag)39020976Smckusick dhuioctl(dev, cmd, data, flag)
39120976Smckusick caddr_t data;
39220976Smckusick {
39320976Smckusick register struct tty *tp;
39420976Smckusick register int unit = UNIT(dev);
39520976Smckusick int error;
39620976Smckusick
39720976Smckusick tp = &dhu_tty[unit];
39820976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
39920976Smckusick if (error >= 0)
40020976Smckusick return (error);
40120976Smckusick error = ttioctl(tp, cmd, data, flag);
40237606Smarc if (error >= 0)
40320976Smckusick return (error);
40420976Smckusick
40520976Smckusick switch (cmd) {
40620976Smckusick case TIOCSBRK:
40720976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS);
40820976Smckusick break;
40920976Smckusick
41020976Smckusick case TIOCCBRK:
41120976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC);
41220976Smckusick break;
41320976Smckusick
41420976Smckusick case TIOCSDTR:
41520976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
41620976Smckusick break;
41720976Smckusick
41820976Smckusick case TIOCCDTR:
41920976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
42020976Smckusick break;
42120976Smckusick
42220976Smckusick case TIOCMSET:
42320976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
42420976Smckusick break;
42520976Smckusick
42620976Smckusick case TIOCMBIS:
42720976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
42820976Smckusick break;
42920976Smckusick
43020976Smckusick case TIOCMBIC:
43120976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
43220976Smckusick break;
43320976Smckusick
43420976Smckusick case TIOCMGET:
43520976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
43620976Smckusick break;
43720976Smckusick default:
43820976Smckusick return (ENOTTY);
43920976Smckusick }
44020976Smckusick return (0);
44120976Smckusick }
44220976Smckusick
dmtodhu(bits)44320976Smckusick dmtodhu(bits)
44420976Smckusick register int bits;
44520976Smckusick {
44620976Smckusick register int b = 0;
44720976Smckusick
44820976Smckusick if (bits & DML_RTS) b |= DHU_RTS;
44920976Smckusick if (bits & DML_DTR) b |= DHU_DTR;
45020976Smckusick if (bits & DML_LE) b |= DHU_LE;
45120976Smckusick return(b);
45220976Smckusick }
45320976Smckusick
dhutodm(bits)45420976Smckusick dhutodm(bits)
45520976Smckusick register int bits;
45620976Smckusick {
45720976Smckusick register int b = 0;
45820976Smckusick
45920976Smckusick if (bits & DHU_DSR) b |= DML_DSR;
46020976Smckusick if (bits & DHU_RNG) b |= DML_RNG;
46120976Smckusick if (bits & DHU_CAR) b |= DML_CAR;
46220976Smckusick if (bits & DHU_CTS) b |= DML_CTS;
46320976Smckusick if (bits & DHU_RTS) b |= DML_RTS;
46420976Smckusick if (bits & DHU_DTR) b |= DML_DTR;
46520976Smckusick if (bits & DHU_LE) b |= DML_LE;
46620976Smckusick return(b);
46720976Smckusick }
46820976Smckusick
46920976Smckusick
47020976Smckusick /*
47120976Smckusick * Set parameters from open or stty into the DHU hardware
47237606Smarc * registers. Impossible values for speed or character
47337606Smarc * size are ignored and not copied back into tp.
47420976Smckusick */
dhuparam(tp,want)47537606Smarc dhuparam(tp, want)
47637606Smarc register struct tty *tp;
47737606Smarc register struct termios *want;
47820976Smckusick {
47937606Smarc register int unit = UNIT(tp->t_dev);
48037606Smarc register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
48120976Smckusick register int lpar;
48237606Smarc register long cflag;
48337606Smarc register int incode, outcode;
48420976Smckusick int s;
48537606Smarc
48620976Smckusick /*
48720976Smckusick * Block interrupts so parameters will be set
48820976Smckusick * before the line interrupts.
48920976Smckusick */
49037606Smarc s = spltty();
49137606Smarc
49237606Smarc if (want->c_ospeed == 0) {
49337606Smarc tp->t_ospeed = 0;
49437606Smarc tp->t_cflag |= HUPCL;
49520976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET);
49620976Smckusick splx(s);
49746352Skarels return (0);
49820976Smckusick }
49937606Smarc
50037606Smarc if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
50137606Smarc tp->t_ospeed = want->c_ospeed;
50237606Smarc else
50337606Smarc outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
50437606Smarc
50537606Smarc if (want->c_ispeed == 0) {
50637606Smarc tp->t_ispeed = 0;
50737606Smarc incode = outcode;
50837606Smarc } else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
50937606Smarc tp->t_ispeed = want->c_ispeed;
51037606Smarc else
51137606Smarc incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
51237606Smarc
51337606Smarc lpar = ((char)outcode<<12) | ((char)incode<<8);
51437606Smarc
51537606Smarc switch (want->c_cflag&CSIZE) {
51637606Smarc case CS6: case CS7: case CS8:
51737606Smarc tp->t_cflag = want->c_cflag;
51837606Smarc break;
51937606Smarc default:
52037606Smarc tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
52137606Smarc }
52237606Smarc cflag = tp->t_cflag;
52337606Smarc
52437606Smarc switch(cflag&CSIZE) {
52537606Smarc case CS6:
52637606Smarc lpar |= DHU_LP_BITS6;
52737606Smarc break;
52837606Smarc case CS7:
52937606Smarc lpar |= DHU_LP_BITS7;
53037606Smarc break;
53137606Smarc case CS8:
53220976Smckusick lpar |= DHU_LP_BITS8;
53337606Smarc break;
53437606Smarc }
53537606Smarc if (cflag&PARENB) {
53637606Smarc lpar |= DHU_LP_PENABLE;
53737606Smarc if ((cflag&PARODD) == 0)
53837606Smarc lpar |= DHU_LP_EPAR;
53937606Smarc }
54037606Smarc if (cflag&CSTOPB)
54137606Smarc lpar |= DHU_LP_TWOSB;
54237606Smarc
54339061Smarc addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
54420976Smckusick addr->dhulpr = lpar;
54520976Smckusick splx(s);
54646352Skarels return (0);
54720976Smckusick }
54820976Smckusick
54920976Smckusick /*
55020976Smckusick * DHU11 transmitter interrupt.
55120976Smckusick * Restart each line which used to be active but has
55220976Smckusick * terminated transmission since the last interrupt.
55320976Smckusick */
dhuxint(dhu)55420976Smckusick dhuxint(dhu)
55520976Smckusick int dhu;
55620976Smckusick {
55720976Smckusick register struct tty *tp;
55820976Smckusick register struct dhudevice *addr;
55920976Smckusick register struct tty *tp0;
56020976Smckusick register struct uba_device *ui;
56120976Smckusick register int line, t;
56220976Smckusick u_short cntr;
56320976Smckusick
56435401Stef #ifdef QBA
56527256Skridle (void) spl5();
56627256Skridle #endif
56720976Smckusick ui = dhuinfo[dhu];
56820976Smckusick tp0 = &dhu_tty[dhu<<4];
56920976Smckusick addr = (struct dhudevice *)ui->ui_addr;
57020976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) {
57120976Smckusick line = DHU_TX_LINE(t);
57220976Smckusick tp = tp0 + line;
57320976Smckusick tp->t_state &= ~TS_BUSY;
57420976Smckusick if (t & DHU_CSH_NXM) {
57520976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line);
57620976Smckusick /* SHOULD RESTART OR SOMETHING... */
57720976Smckusick }
57820976Smckusick if (tp->t_state&TS_FLUSH)
57920976Smckusick tp->t_state &= ~TS_FLUSH;
58020976Smckusick else {
58120976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
58220976Smckusick /*
58320976Smckusick * Do arithmetic in a short to make up
58420976Smckusick * for lost 16&17 bits.
58520976Smckusick */
58620976Smckusick cntr = addr->dhubar1 -
58720976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
58820976Smckusick ndflush(&tp->t_outq, (int)cntr);
58920976Smckusick }
59020976Smckusick if (tp->t_line)
59120976Smckusick (*linesw[tp->t_line].l_start)(tp);
59220976Smckusick else
59320976Smckusick dhustart(tp);
59420976Smckusick }
59520976Smckusick }
59620976Smckusick
59720976Smckusick /*
59820976Smckusick * Start (restart) transmission on the given DHU11 line.
59920976Smckusick */
dhustart(tp)60020976Smckusick dhustart(tp)
60120976Smckusick register struct tty *tp;
60220976Smckusick {
60320976Smckusick register struct dhudevice *addr;
60420976Smckusick register int car, dhu, unit, nch;
60520976Smckusick int s;
60620976Smckusick
60720976Smckusick unit = minor(tp->t_dev);
60820976Smckusick dhu = unit >> 4;
60920976Smckusick unit &= 0xf;
61020976Smckusick addr = (struct dhudevice *)tp->t_addr;
61120976Smckusick
61220976Smckusick /*
61320976Smckusick * Must hold interrupts in following code to prevent
61420976Smckusick * state of the tp from changing.
61520976Smckusick */
61620976Smckusick s = spl5();
61720976Smckusick /*
61820976Smckusick * If it's currently active, or delaying, no need to do anything.
61920976Smckusick */
62020976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
62120976Smckusick goto out;
62220976Smckusick /*
62320976Smckusick * If there are sleepers, and output has drained below low
62420976Smckusick * water mark, wake up the sleepers..
62520976Smckusick */
62637606Smarc if (tp->t_outq.c_cc <= tp->t_lowat) {
62720976Smckusick if (tp->t_state&TS_ASLEEP) {
62820976Smckusick tp->t_state &= ~TS_ASLEEP;
62920976Smckusick wakeup((caddr_t)&tp->t_outq);
63020976Smckusick }
63120976Smckusick if (tp->t_wsel) {
63220976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
63320976Smckusick tp->t_wsel = 0;
63420976Smckusick tp->t_state &= ~TS_WCOLL;
63520976Smckusick }
63620976Smckusick }
63720976Smckusick /*
63820976Smckusick * Now restart transmission unless the output queue is
63920976Smckusick * empty.
64020976Smckusick */
64120976Smckusick if (tp->t_outq.c_cc == 0)
64220976Smckusick goto out;
64339061Smarc if (1 || !(tp->t_oflag & OPOST)) /*XXX*/
64420976Smckusick nch = ndqb(&tp->t_outq, 0);
64520976Smckusick else {
64620976Smckusick nch = ndqb(&tp->t_outq, 0200);
64720976Smckusick /*
64820976Smckusick * If first thing on queue is a delay process it.
64920976Smckusick */
65020976Smckusick if (nch == 0) {
65120976Smckusick nch = getc(&tp->t_outq);
65220976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
65320976Smckusick tp->t_state |= TS_TIMEOUT;
65420976Smckusick goto out;
65520976Smckusick }
65620976Smckusick }
65720976Smckusick /*
65820976Smckusick * If characters to transmit, restart transmission.
65920976Smckusick */
66020976Smckusick if (nch) {
66120976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
66220976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
66320976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT;
66420976Smckusick addr->dhubcr = nch;
66520976Smckusick addr->dhubar1 = car;
66620976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
66720976Smckusick DHU_BA2_DMAGO;
66820976Smckusick tp->t_state |= TS_BUSY;
66920976Smckusick }
67020976Smckusick out:
67120976Smckusick splx(s);
67220976Smckusick }
67320976Smckusick
67420976Smckusick /*
67520976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush.
67620976Smckusick */
67720976Smckusick /*ARGSUSED*/
dhustop(tp,flag)67820976Smckusick dhustop(tp, flag)
67920976Smckusick register struct tty *tp;
68020976Smckusick {
68120976Smckusick register struct dhudevice *addr;
68220976Smckusick register int unit, s;
68320976Smckusick
68420976Smckusick addr = (struct dhudevice *)tp->t_addr;
68520976Smckusick /*
68620976Smckusick * Block input/output interrupts while messing with state.
68720976Smckusick */
68820976Smckusick s = spl5();
68920976Smckusick if (tp->t_state & TS_BUSY) {
69020976Smckusick /*
69120976Smckusick * Device is transmitting; stop output
69220976Smckusick * by selecting the line and setting the
69320976Smckusick * abort xmit bit. We will get an xmit interrupt,
69420976Smckusick * where we will figure out where to continue the
69520976Smckusick * next time the transmitter is enabled. If
69620976Smckusick * TS_FLUSH is set, the outq will be flushed.
69720976Smckusick * In either case, dhustart will clear the TXABORT bit.
69820976Smckusick */
69920976Smckusick unit = minor(tp->t_dev);
70020976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
70120976Smckusick addr->dhulcr |= DHU_LC_TXABORT;
70220976Smckusick if ((tp->t_state&TS_TTSTOP)==0)
70320976Smckusick tp->t_state |= TS_FLUSH;
70420976Smckusick }
70520976Smckusick (void) splx(s);
70620976Smckusick }
70720976Smckusick
70820976Smckusick /*
70920976Smckusick * DHU11 modem control
71020976Smckusick */
dhumctl(dev,bits,how)71120976Smckusick dhumctl(dev, bits, how)
71220976Smckusick dev_t dev;
71320976Smckusick int bits, how;
71420976Smckusick {
71520976Smckusick register struct dhudevice *dhuaddr;
71626291Skarels register int unit, mbits;
71720976Smckusick int s;
71820976Smckusick
71920976Smckusick unit = UNIT(dev);
72020976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
72120976Smckusick unit &= 0xf;
72220976Smckusick s = spl5();
72320976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
72420976Smckusick /*
72520976Smckusick * combine byte from stat register (read only, bits 16..23)
72620976Smckusick * with lcr register (read write, bits 0..15).
72720976Smckusick */
72820976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
72920976Smckusick switch (how) {
73020976Smckusick case DMSET:
73120976Smckusick mbits = (mbits & 0xff0000) | bits;
73220976Smckusick break;
73320976Smckusick
73420976Smckusick case DMBIS:
73520976Smckusick mbits |= bits;
73620976Smckusick break;
73720976Smckusick
73820976Smckusick case DMBIC:
73920976Smckusick mbits &= ~bits;
74020976Smckusick break;
74120976Smckusick
74220976Smckusick case DMGET:
74320976Smckusick (void) splx(s);
74420976Smckusick return(mbits);
74520976Smckusick }
74620976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
74720976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN;
74820976Smckusick (void) splx(s);
74920976Smckusick return(mbits);
75020976Smckusick }
75120976Smckusick
75220976Smckusick /*
75320976Smckusick * Reset state of driver if UBA reset was necessary.
75420976Smckusick * Reset the line and modem control registers.
75520976Smckusick * restart transmitters.
75620976Smckusick */
dhureset(uban)75720976Smckusick dhureset(uban)
75820976Smckusick int uban;
75920976Smckusick {
76020976Smckusick register int dhu, unit;
76120976Smckusick register struct tty *tp;
76220976Smckusick register struct uba_device *ui;
76320976Smckusick register struct dhudevice *addr;
76420976Smckusick int i;
76520976Smckusick
76620976Smckusick for (dhu = 0; dhu < NDHU; dhu++) {
76720976Smckusick ui = dhuinfo[dhu];
76820976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
76920976Smckusick continue;
77020976Smckusick printf(" dhu%d", dhu);
77130322Skarels if (dhu_uballoc[uban] == dhu) {
77230322Skarels int info;
77330322Skarels
77430322Skarels info = uballoc(uban, (caddr_t)cfree,
77530322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT);
77630322Skarels if (info)
77730322Skarels cbase[uban] = UBAI_ADDR(info);
77830322Skarels else {
77930322Skarels printf(" [can't get uba map]");
78030322Skarels cbase[uban] = -1;
78130322Skarels }
78225434Skarels }
78320976Smckusick addr = (struct dhudevice *)ui->ui_addr;
78420976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE;
78520976Smckusick addr->dhutimo = DHU_DEF_TIMO;
78620976Smckusick unit = dhu * 16;
78720976Smckusick for (i = 0; i < 16; i++) {
78820976Smckusick tp = &dhu_tty[unit];
78920976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
79037606Smarc dhuparam(tp, &tp->t_termios);
79120976Smckusick (void)dhumctl(unit, DHU_ON, DMSET);
79220976Smckusick tp->t_state &= ~TS_BUSY;
79320976Smckusick dhustart(tp);
79420976Smckusick }
79520976Smckusick unit++;
79620976Smckusick }
79720976Smckusick }
79820976Smckusick }
79920976Smckusick #endif
800