123320Smckusick /*
229209Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323320Smckusick * All rights reserved. The Berkeley software License Agreement
423320Smckusick * specifies the terms and conditions for redistribution.
523320Smckusick *
6*49759Smarc * @(#)dh.c 7.17 (Berkeley) 05/16/91
723320Smckusick */
813Sbill
91934Swnj #include "dh.h"
102643Swnj #if NDH > 0
1113Sbill /*
122479Swnj * DH-11/DM-11 driver
1313Sbill */
1445804Sbostic #include "../include/pte.h"
159771Ssam
1645804Sbostic #include "sys/param.h"
1716062Skarels #include "uba.h"
1845804Sbostic #include "sys/conf.h"
1945804Sbostic #include "sys/user.h"
2045804Sbostic #include "sys/proc.h"
2145804Sbostic #include "sys/ioctl.h"
2245804Sbostic #include "sys/tty.h"
2345804Sbostic #include "sys/map.h"
2445804Sbostic #include "sys/buf.h"
2545804Sbostic #include "sys/vm.h"
2645804Sbostic #include "sys/kernel.h"
2745804Sbostic #include "sys/syslog.h"
288472Sroot
2917122Sbloom #include "ubareg.h"
3017122Sbloom #include "ubavar.h"
3117122Sbloom #include "dhreg.h"
3217122Sbloom #include "dmreg.h"
338472Sroot
3445804Sbostic #include "sys/clist.h"
3545804Sbostic #include "sys/file.h"
3645804Sbostic #include "sys/uio.h"
3713Sbill
382468Swnj /*
392479Swnj * Definition of the driver for the auto-configuration program.
402479Swnj * There is one definition for the dh and one for the dm.
412468Swnj */
4216190Skarels int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
432974Swnj struct uba_device *dhinfo[NDH];
442395Swnj u_short dhstd[] = { 0 };
452395Swnj struct uba_driver dhdriver =
462605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
472395Swnj
482605Swnj int dmprobe(), dmattach(), dmintr();
492974Swnj struct uba_device *dminfo[NDH];
502479Swnj u_short dmstd[] = { 0 };
512479Swnj struct uba_driver dmdriver =
522605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
5313Sbill
546615Ssam #ifndef PORTSELECTOR
5539061Smarc #define ISPEED TTYDEF_SPEED
5639061Smarc #define LFLAG TTYDEF_LFLAG
576615Ssam #else
586615Ssam #define ISPEED B4800
5939061Smarc #define LFLAG (TTYDEF_LFLAG&~ECHO)
606615Ssam #endif
616615Ssam
6216190Skarels #define FASTTIMER (hz/30) /* scan rate with silos on */
6316190Skarels
6413Sbill /*
652479Swnj * Local variables for the driver
6613Sbill */
672643Swnj short dhsar[NDH]; /* software copy of last bar */
682643Swnj short dhsoftCAR[NDH];
6913Sbill
702643Swnj struct tty dh11[NDH*16];
712643Swnj int ndh11 = NDH*16;
722479Swnj int dhact; /* mask of active dh's */
7316190Skarels int dhsilos; /* mask of dh's with silo in use */
7416190Skarels int dhchars[NDH]; /* recent input count */
7516190Skarels int dhrate[NDH]; /* smoothed input count */
7616190Skarels int dhhighrate = 100; /* silo on if dhchars > dhhighrate */
7716190Skarels int dhlowrate = 75; /* silo off if dhrate < dhlowrate */
7816190Skarels static short timerstarted;
792479Swnj int dhstart(), ttrstrt();
8013Sbill
8139061Smarc struct speedtab dhspeedtab[] = {
8239061Smarc 19200, 14,
8339061Smarc 9600, 13,
8439061Smarc 4800, 12,
8539061Smarc 2400, 11,
8639061Smarc 1800, 10,
8739061Smarc 1200, 9,
8839061Smarc 600, 8,
8939061Smarc 300, 7,
9039061Smarc 200, 6,
9139061Smarc 150, 5,
9239061Smarc 134, 4,
9339061Smarc 110, 3,
9439061Smarc 75, 2,
9539061Smarc 50, 1,
9639061Smarc 0, 0,
9739061Smarc EXTA, 14,
9839061Smarc EXTB, 15,
9939061Smarc -1, -1
10039061Smarc };
10139061Smarc
1022479Swnj /*
10330322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS.
10430322Skarels * The identity of the board which allocated resources is recorded,
10530322Skarels * so the process may be repeated after UNIBUS resets.
1062479Swnj * The UBACVT macro converts a clist space address for unibus uban
1072479Swnj * into an i/o space address for the DMA routine.
1082479Swnj */
10930322Skarels int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */
11030322Skarels int cbase[NUBA]; /* base address of clists in unibus map */
1112479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
11213Sbill
1132456Swnj /*
1142456Swnj * Routine for configuration to force a dh to interrupt.
1152456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1162456Swnj */
1172468Swnj /*ARGSUSED*/
dhprobe(reg)1182605Swnj dhprobe(reg)
1192395Swnj caddr_t reg;
1202395Swnj {
1212468Swnj register int br, cvec; /* these are ``value-result'' */
1222479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1232395Swnj
1242605Swnj #ifdef lint
1252605Swnj br = 0; cvec = br; br = cvec;
1267384Sroot if (ndh11 == 0) ndh11 = 1;
1274932Swnj dhrint(0); dhxint(0);
1282605Swnj #endif
1292696Swnj #ifndef notdef
1302566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1316380Swnj DELAY(1000);
1327384Sroot dhaddr->un.dhcsr &= ~DH_RI;
1332566Swnj dhaddr->un.dhcsr = 0;
1342566Swnj #else
1352456Swnj dhaddr->un.dhcsr = DH_TIE;
1362456Swnj DELAY(5);
1372456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1382421Skre dhaddr->dhbcr = -1;
1392456Swnj dhaddr->dhcar = 0;
1402421Skre dhaddr->dhbar = 1;
1412456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */
1422421Skre dhaddr->un.dhcsr = 0;
1432456Swnj if (cvec && cvec != 0x200)
1442456Swnj cvec -= 4; /* transmit -> receive */
1452482Swnj #endif
1467408Skre return (sizeof (struct dhdevice));
1472395Swnj }
1482395Swnj
1492456Swnj /*
1502605Swnj * Routine called to attach a dh.
1512456Swnj */
1522605Swnj dhattach(ui)
1532974Swnj struct uba_device *ui;
1542395Swnj {
1552395Swnj
1562566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags;
15726219Skarels cbase[ui->ui_ubanum] = -1;
15836610Sbostic dh_uballoc[ui->ui_ubanum] = -1;
1592395Swnj }
1602395Swnj
16113Sbill /*
1622479Swnj * Configuration routine to cause a dm to interrupt.
1632479Swnj */
dmprobe(reg)1642605Swnj dmprobe(reg)
1652605Swnj caddr_t reg;
1662479Swnj {
1672479Swnj register int br, vec; /* value-result */
1682605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1692479Swnj
1702605Swnj #ifdef lint
1713101Swnj br = 0; vec = br; br = vec;
1726185Ssam dmintr(0);
1732605Swnj #endif
1742479Swnj dmaddr->dmcsr = DM_DONE|DM_IE;
1752479Swnj DELAY(20);
1762479Swnj dmaddr->dmcsr = 0;
1772605Swnj return (1);
1782479Swnj }
1792479Swnj
1802605Swnj /*ARGSUSED*/
1812605Swnj dmattach(ui)
1822974Swnj struct uba_device *ui;
1832479Swnj {
1842479Swnj
1852479Swnj /* no local state to set up */
1862479Swnj }
1872479Swnj
1882479Swnj /*
1892468Swnj * Open a DH11 line, mapping the clist onto the uba if this
1902468Swnj * is the first dh on this uba. Turn on this dh if this is
1912468Swnj * the first use of it. Also do a dmopen to wait for carrier.
19213Sbill */
19313Sbill /*ARGSUSED*/
dhopen(dev,flag)19413Sbill dhopen(dev, flag)
1952395Swnj dev_t dev;
19613Sbill {
19713Sbill register struct tty *tp;
1982395Swnj register int unit, dh;
1992479Swnj register struct dhdevice *addr;
2002974Swnj register struct uba_device *ui;
20140729Skarels int s, error;
20239061Smarc int dhparam();
20313Sbill
2042395Swnj unit = minor(dev);
2052395Swnj dh = unit >> 4;
2068566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
2078566Sroot return (ENXIO);
2082395Swnj tp = &dh11[unit];
2098566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
2108566Sroot return (EBUSY);
2112479Swnj addr = (struct dhdevice *)ui->ui_addr;
21213Sbill tp->t_addr = (caddr_t)addr;
21313Sbill tp->t_oproc = dhstart;
21439061Smarc tp->t_param = dhparam;
21539061Smarc tp->t_dev = dev;
2162468Swnj /*
2172468Swnj * While setting up state for this uba and this dh,
2182468Swnj * block uba resets which can clear the state.
2192468Swnj */
2202468Swnj s = spl5();
22126219Skarels if (cbase[ui->ui_ubanum] == -1) {
22230322Skarels dh_uballoc[ui->ui_ubanum] = dh;
22330322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22430322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22513Sbill }
22616190Skarels if (timerstarted == 0) {
22716190Skarels timerstarted++;
22816190Skarels timeout(dhtimer, (caddr_t) 0, hz);
22916190Skarels }
2302456Swnj if ((dhact&(1<<dh)) == 0) {
2312456Swnj addr->un.dhcsr |= DH_IE;
2322468Swnj dhact |= (1<<dh);
23316190Skarels addr->dhsilo = 0;
2342456Swnj }
23513Sbill splx(s);
2362468Swnj /*
23727049Skarels * If this is first open, initialize tty state to default.
2382468Swnj */
2395406Swnj if ((tp->t_state&TS_ISOPEN) == 0) {
24044393Smarc tp->t_state |= TS_WOPEN;
24113Sbill ttychars(tp);
24227049Skarels #ifndef PORTSELECTOR
24327049Skarels if (tp->t_ispeed == 0) {
24439061Smarc #endif
24539061Smarc tp->t_iflag = TTYDEF_IFLAG;
24639061Smarc tp->t_oflag = TTYDEF_OFLAG;
24739061Smarc tp->t_cflag = TTYDEF_CFLAG;
24839061Smarc tp->t_lflag = LFLAG;
24939061Smarc tp->t_ispeed = tp->t_ospeed = ISPEED;
25039061Smarc #ifdef PORTSELECTOR
25139061Smarc tp->t_cflag |= HUPCL;
25227049Skarels #else
25327049Skarels }
25439061Smarc #endif
25539061Smarc dhparam(tp, &tp->t_termios);
25639061Smarc ttsetwater(tp);
25713Sbill }
2582468Swnj /*
2592468Swnj * Wait for carrier, then process line discipline specific open.
2602468Swnj */
26140729Skarels if (error = dmopen(dev, flag))
26240729Skarels return (error);
2638566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp));
26413Sbill }
26513Sbill
26613Sbill /*
2672468Swnj * Close a DH11 line, turning off the DM11.
26813Sbill */
26913Sbill /*ARGSUSED*/
dhclose(dev,flag,mode,p)270*49759Smarc dhclose(dev, flag, mode, p)
2712395Swnj dev_t dev;
272*49759Smarc int flag, mode;
273*49759Smarc struct proc *p;
27413Sbill {
27513Sbill register struct tty *tp;
2762395Swnj register unit;
27713Sbill
2782395Swnj unit = minor(dev);
2792395Swnj tp = &dh11[unit];
280*49759Smarc (*linesw[tp->t_line].l_close)(tp, flag);
2812479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
28239061Smarc if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0)
2832479Swnj dmctl(unit, DML_OFF, DMSET);
28440729Skarels return (ttyclose(tp));
28513Sbill }
28613Sbill
dhread(dev,uio,flag)28739061Smarc dhread(dev, uio, flag)
2882395Swnj dev_t dev;
2897725Sroot struct uio *uio;
29013Sbill {
2918490Sroot register struct tty *tp = &dh11[minor(dev)];
29213Sbill
29339061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
29413Sbill }
29513Sbill
dhwrite(dev,uio,flag)29639061Smarc dhwrite(dev, uio, flag)
2972395Swnj dev_t dev;
2987831Sroot struct uio *uio;
29913Sbill {
3008490Sroot register struct tty *tp = &dh11[minor(dev)];
30113Sbill
30239061Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
30313Sbill }
30413Sbill
30513Sbill /*
30613Sbill * DH11 receiver interrupt.
30713Sbill */
dhrint(dh)3082395Swnj dhrint(dh)
3092395Swnj int dh;
31013Sbill {
31113Sbill register struct tty *tp;
31239061Smarc register c, cc;
3132479Swnj register struct dhdevice *addr;
314117Sbill register struct tty *tp0;
3152974Swnj register struct uba_device *ui;
3162924Swnj int overrun = 0;
31713Sbill
3182395Swnj ui = dhinfo[dh];
3192479Swnj if (ui == 0 || ui->ui_alive == 0)
3202479Swnj return;
3212479Swnj addr = (struct dhdevice *)ui->ui_addr;
3222468Swnj tp0 = &dh11[dh<<4];
3232468Swnj /*
3242468Swnj * Loop fetching characters from the silo for this
3252468Swnj * dh until there are no more in the silo.
3262468Swnj */
3272468Swnj while ((c = addr->dhrcr) < 0) {
3282468Swnj tp = tp0 + ((c>>8)&0xf);
32916190Skarels dhchars[dh]++;
3305406Swnj if ((tp->t_state&TS_ISOPEN)==0) {
33125394Skarels wakeup((caddr_t)&tp->t_rawq);
33225394Skarels #ifdef PORTSELECTOR
33325394Skarels if ((tp->t_state&TS_WOPEN) == 0)
3346615Ssam #endif
33525394Skarels continue;
33613Sbill }
33739061Smarc cc = c&0xff;
33839061Smarc if (c&DH_PE)
33939061Smarc cc |= TTY_PE;
34039061Smarc if ((c&DH_DO) && overrun == 0) {
34124840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh);
3422924Swnj overrun = 1;
3432924Swnj }
34439061Smarc if (c&DH_FE)
34539061Smarc cc |= TTY_FE;
34639061Smarc (*linesw[tp->t_line].l_rint)(cc, tp);
34713Sbill }
34813Sbill }
34913Sbill
35013Sbill /*
3512468Swnj * Ioctl for DH11.
35213Sbill */
35313Sbill /*ARGSUSED*/
dhioctl(dev,cmd,data,flag)3547629Ssam dhioctl(dev, cmd, data, flag)
3557629Ssam caddr_t data;
35613Sbill {
35713Sbill register struct tty *tp;
3588566Sroot register int unit = minor(dev);
3598566Sroot int error;
36013Sbill
3612395Swnj tp = &dh11[unit];
3628566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3638566Sroot if (error >= 0)
3648566Sroot return (error);
3658566Sroot error = ttioctl(tp, cmd, data, flag);
36639061Smarc if (error >= 0)
3678566Sroot return (error);
3688566Sroot switch (cmd) {
3697629Ssam
370168Sbill case TIOCSBRK:
3712479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
372168Sbill break;
3737629Ssam
374168Sbill case TIOCCBRK:
3752479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
376168Sbill break;
3777629Ssam
378168Sbill case TIOCSDTR:
3792479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS);
380168Sbill break;
3817629Ssam
382168Sbill case TIOCCDTR:
3832479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC);
384168Sbill break;
3857629Ssam
386168Sbill default:
3878566Sroot return (ENOTTY);
388168Sbill }
3898566Sroot return (0);
39013Sbill }
39113Sbill
39213Sbill /*
39313Sbill * Set parameters from open or stty into the DH hardware
39413Sbill * registers.
39513Sbill */
dhparam(tp,t)39639061Smarc dhparam(tp, t)
39739061Smarc register struct tty *tp;
39839061Smarc register struct termios *t;
39913Sbill {
4002479Swnj register struct dhdevice *addr;
4012395Swnj register int lpar;
40239061Smarc register int cflag = t->c_cflag;
40339061Smarc int unit = minor(tp->t_dev);
404300Sbill int s;
40539061Smarc int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab);
40639061Smarc int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab);
40713Sbill
40839061Smarc /* check requested parameters */
40939061Smarc if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
41039061Smarc return(EINVAL);
41139061Smarc if (ispeed == 0)
41239061Smarc ispeed = ospeed;
41339061Smarc /* and copy to tty */
41439061Smarc tp->t_ispeed = t->c_ispeed;
41539061Smarc tp->t_ospeed = t->c_ospeed;
41639061Smarc tp->t_cflag = cflag;
4172468Swnj /*
4182468Swnj * Block interrupts so parameters will be set
4192468Swnj * before the line interrupts.
4202468Swnj */
42139061Smarc addr = (struct dhdevice *)tp->t_addr;
422300Sbill s = spl5();
4232468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE;
42439061Smarc if (ospeed == 0) {
42539061Smarc tp->t_cflag |= HUPCL;
4262479Swnj dmctl(unit, DML_OFF, DMSET);
42728147Skarels splx(s);
42839061Smarc return 0;
42913Sbill }
43039061Smarc lpar = (ospeed<<10) | (ispeed<<6);
43139061Smarc switch (cflag&CSIZE) {
43239061Smarc case CS6: lpar |= BITS6; break;
43339061Smarc case CS7: lpar |= BITS7; break;
43439061Smarc case CS8: lpar |= BITS8; break;
43539061Smarc }
43639061Smarc if (cflag&PARENB)
43739061Smarc lpar |= PENABLE;
43839061Smarc if (cflag&PARODD)
4392395Swnj lpar |= OPAR;
44039061Smarc if (cflag&CSTOPB)
4412395Swnj lpar |= TWOSB;
4422395Swnj addr->dhlpr = lpar;
443300Sbill splx(s);
44439061Smarc return 0;
44513Sbill }
44613Sbill
44713Sbill /*
44813Sbill * DH11 transmitter interrupt.
44913Sbill * Restart each line which used to be active but has
45013Sbill * terminated transmission since the last interrupt.
45113Sbill */
dhxint(dh)4522395Swnj dhxint(dh)
4532395Swnj int dh;
45413Sbill {
45513Sbill register struct tty *tp;
4562479Swnj register struct dhdevice *addr;
45713Sbill short ttybit, bar, *sbar;
4582974Swnj register struct uba_device *ui;
4592468Swnj register int unit;
4602605Swnj u_short cntr;
46113Sbill
4622395Swnj ui = dhinfo[dh];
4632479Swnj addr = (struct dhdevice *)ui->ui_addr;
4642456Swnj if (addr->un.dhcsr & DH_NXM) {
4652456Swnj addr->un.dhcsr |= DH_CNI;
4662924Swnj printf("dh%d: NXM\n", dh);
467105Sbill }
4682395Swnj sbar = &dhsar[dh];
46913Sbill bar = *sbar & ~addr->dhbar;
4702395Swnj unit = dh * 16; ttybit = 1;
4712468Swnj addr->un.dhcsr &= (short)~DH_TI;
4722468Swnj for (; bar; unit++, ttybit <<= 1) {
4732468Swnj if (bar & ttybit) {
47413Sbill *sbar &= ~ttybit;
47513Sbill bar &= ~ttybit;
4762395Swnj tp = &dh11[unit];
4775406Swnj tp->t_state &= ~TS_BUSY;
4785406Swnj if (tp->t_state&TS_FLUSH)
4795406Swnj tp->t_state &= ~TS_FLUSH;
480113Sbill else {
4812456Swnj addr->un.dhcsrl = (unit&017)|DH_IE;
4822468Swnj /*
4832468Swnj * Do arithmetic in a short to make up
4842468Swnj * for lost 16&17 bits.
4852468Swnj */
4862605Swnj cntr = addr->dhcar -
4872468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4883101Swnj ndflush(&tp->t_outq, (int)cntr);
489113Sbill }
490113Sbill if (tp->t_line)
49113Sbill (*linesw[tp->t_line].l_start)(tp);
492113Sbill else
49313Sbill dhstart(tp);
49413Sbill }
49513Sbill }
49613Sbill }
49713Sbill
49813Sbill /*
49913Sbill * Start (restart) transmission on the given DH11 line.
50013Sbill */
dhstart(tp)50113Sbill dhstart(tp)
5022395Swnj register struct tty *tp;
50313Sbill {
5042479Swnj register struct dhdevice *addr;
5052468Swnj register int car, dh, unit, nch;
5062395Swnj int s;
50713Sbill
5082468Swnj unit = minor(tp->t_dev);
5092468Swnj dh = unit >> 4;
5102468Swnj unit &= 0xf;
5112479Swnj addr = (struct dhdevice *)tp->t_addr;
5122468Swnj
51313Sbill /*
5142468Swnj * Must hold interrupts in following code to prevent
5152468Swnj * state of the tp from changing.
51613Sbill */
51713Sbill s = spl5();
5182468Swnj /*
5192468Swnj * If it's currently active, or delaying, no need to do anything.
5202468Swnj */
5215406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
52213Sbill goto out;
5232468Swnj /*
5242468Swnj * If there are sleepers, and output has drained below low
5252468Swnj * water mark, wake up the sleepers.
5262468Swnj */
52739061Smarc if (tp->t_outq.c_cc<=tp->t_lowat) {
5285406Swnj if (tp->t_state&TS_ASLEEP) {
5295406Swnj tp->t_state &= ~TS_ASLEEP;
5305406Swnj wakeup((caddr_t)&tp->t_outq);
5315406Swnj }
5325406Swnj if (tp->t_wsel) {
5335406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5345406Swnj tp->t_wsel = 0;
5355406Swnj tp->t_state &= ~TS_WCOLL;
5365406Swnj }
53713Sbill }
5382468Swnj /*
5392468Swnj * Now restart transmission unless the output queue is
5402468Swnj * empty.
5412468Swnj */
54213Sbill if (tp->t_outq.c_cc == 0)
54313Sbill goto out;
54439061Smarc if (1 || !(tp->t_oflag&OPOST)) /*XXX*/
54513Sbill nch = ndqb(&tp->t_outq, 0);
5462395Swnj else {
54713Sbill nch = ndqb(&tp->t_outq, 0200);
5482468Swnj /*
5492468Swnj * If first thing on queue is a delay process it.
5502468Swnj */
55113Sbill if (nch == 0) {
55213Sbill nch = getc(&tp->t_outq);
5532468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5545406Swnj tp->t_state |= TS_TIMEOUT;
55513Sbill goto out;
55613Sbill }
55713Sbill }
5582468Swnj /*
5592468Swnj * If characters to transmit, restart transmission.
5602468Swnj */
56113Sbill if (nch) {
5622468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5632468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5643586Sroot /*
5653586Sroot * The following nonsense with short word
5663586Sroot * is to make sure the dhbar |= word below
5673586Sroot * is done with an interlocking bisw2 instruction.
5683586Sroot */
5693586Sroot { short word = 1 << unit;
5703586Sroot dhsar[dh] |= word;
5712468Swnj addr->dhcar = car;
57213Sbill addr->dhbcr = -nch;
5733586Sroot addr->dhbar |= word;
5743586Sroot }
5755406Swnj tp->t_state |= TS_BUSY;
57613Sbill }
5772395Swnj out:
57813Sbill splx(s);
57913Sbill }
58013Sbill
58113Sbill /*
5822468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush.
58313Sbill */
58413Sbill /*ARGSUSED*/
dhstop(tp,flag)58513Sbill dhstop(tp, flag)
5862468Swnj register struct tty *tp;
58713Sbill {
5882479Swnj register struct dhdevice *addr;
5892395Swnj register int unit, s;
59013Sbill
5912479Swnj addr = (struct dhdevice *)tp->t_addr;
5922468Swnj /*
5932468Swnj * Block input/output interrupts while messing with state.
5942468Swnj */
5952468Swnj s = spl5();
5965406Swnj if (tp->t_state & TS_BUSY) {
5972468Swnj /*
5982468Swnj * Device is transmitting; stop output
5992468Swnj * by selecting the line and setting the byte
6002468Swnj * count to -1. We will clean up later
6012468Swnj * by examining the address where the dh stopped.
6022468Swnj */
6032395Swnj unit = minor(tp->t_dev);
6042456Swnj addr->un.dhcsrl = (unit&017) | DH_IE;
6055406Swnj if ((tp->t_state&TS_TTSTOP)==0)
6065406Swnj tp->t_state |= TS_FLUSH;
607113Sbill addr->dhbcr = -1;
608113Sbill }
60913Sbill splx(s);
61013Sbill }
61113Sbill
612168Sbill /*
613280Sbill * Reset state of driver if UBA reset was necessary.
614280Sbill * Reset the csrl and lpr registers on open lines, and
615280Sbill * restart transmitters.
616280Sbill */
dhreset(uban)6172395Swnj dhreset(uban)
6182468Swnj int uban;
619280Sbill {
6202395Swnj register int dh, unit;
621280Sbill register struct tty *tp;
6222974Swnj register struct uba_device *ui;
6232421Skre int i;
624280Sbill
6252395Swnj dh = 0;
6262643Swnj for (dh = 0; dh < NDH; dh++) {
6272421Skre ui = dhinfo[dh];
6282421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6292421Skre continue;
6302924Swnj printf(" dh%d", dh);
63130322Skarels if (dh_uballoc[uban] == dh) {
63230322Skarels int info;
63330322Skarels
63430322Skarels info = uballoc(uban, (caddr_t)cfree,
63530322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT);
63630322Skarels if (info)
63730322Skarels cbase[uban] = UBAI_ADDR(info);
63830322Skarels else {
63930322Skarels printf(" [can't get uba map]");
64030322Skarels cbase[uban] = -1;
64130322Skarels }
64225433Skarels }
6432479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
64416190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
6452421Skre unit = dh * 16;
6462421Skre for (i = 0; i < 16; i++) {
6472421Skre tp = &dh11[unit];
6485406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6492421Skre dhparam(unit);
6502479Swnj dmctl(unit, DML_ON, DMSET);
6515406Swnj tp->t_state &= ~TS_BUSY;
6522421Skre dhstart(tp);
6532421Skre }
6542421Skre unit++;
655300Sbill }
656300Sbill }
65716190Skarels dhsilos = 0;
658280Sbill }
6592395Swnj
66016190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/
6612468Swnj /*
66216190Skarels * At software clock interrupt time, check status.
66316190Skarels * Empty all the dh silos that are in use, and decide whether
66416190Skarels * to turn any silos off or on.
6652468Swnj */
dhtimer()6662456Swnj dhtimer()
6672456Swnj {
66816190Skarels register int dh, s;
66916190Skarels static int timercalls;
6702456Swnj
67116190Skarels if (dhsilos) {
67216190Skarels dhfasttimers++; /*DEBUG*/
67316190Skarels timercalls++;
67416190Skarels s = spl5();
67516190Skarels for (dh = 0; dh < NDH; dh++)
67616190Skarels if (dhsilos & (1 << dh))
67716190Skarels dhrint(dh);
67816190Skarels splx(s);
67916190Skarels }
68016190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
68116190Skarels dhslowtimers++; /*DEBUG*/
68216190Skarels timercalls = 0;
68316190Skarels for (dh = 0; dh < NDH; dh++) {
68416190Skarels ave(dhrate[dh], dhchars[dh], 8);
68516190Skarels if ((dhchars[dh] > dhhighrate) &&
68616190Skarels ((dhsilos & (1 << dh)) == 0)) {
68716190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
68816190Skarels (dhchars[dh] > 500? 32 : 16);
68916190Skarels dhsilos |= (1 << dh);
69016190Skarels dhtransitions++; /*DEBUG*/
69116190Skarels } else if ((dhsilos & (1 << dh)) &&
69216190Skarels (dhrate[dh] < dhlowrate)) {
69316190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
69416190Skarels dhsilos &= ~(1 << dh);
69516190Skarels }
69616190Skarels dhchars[dh] = 0;
69716190Skarels }
69816190Skarels }
69916190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
7002456Swnj }
7012456Swnj
7022468Swnj /*
7032479Swnj * Turn on the line associated with dh dev.
7042468Swnj */
dmopen(dev,flag)70539061Smarc dmopen(dev, flag)
7062468Swnj dev_t dev;
7072468Swnj {
7082468Swnj register struct tty *tp;
7092468Swnj register struct dmdevice *addr;
7102974Swnj register struct uba_device *ui;
7112468Swnj register int unit;
7122468Swnj register int dm;
71340729Skarels int s, error = 0;
7142468Swnj
7152468Swnj unit = minor(dev);
7162479Swnj dm = unit >> 4;
7172468Swnj tp = &dh11[unit];
7182566Swnj unit &= 0xf;
71916942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
7205406Swnj tp->t_state |= TS_CARR_ON;
72140729Skarels return (0);
7222468Swnj }
7232468Swnj addr = (struct dmdevice *)ui->ui_addr;
7243792Swnj s = spl5();
72530341Skarels for (;;) {
72644393Smarc tp->t_state |= TS_WOPEN;
72730341Skarels addr->dmcsr &= ~DM_SE;
72830341Skarels while (addr->dmcsr & DM_BUSY)
72930341Skarels ;
73030341Skarels addr->dmcsr = unit;
73130341Skarels addr->dmlstat = DML_ON;
73230349Skarels if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit)))
73330341Skarels tp->t_state |= TS_CARR_ON;
73430341Skarels addr->dmcsr = DM_IE|DM_SE;
73539061Smarc if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK ||
73639061Smarc tp->t_cflag&CLOCAL)
73730341Skarels break;
73844393Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
73944393Smarc ttopen, 0))
74040729Skarels break;
74130341Skarels }
7423792Swnj splx(s);
74340729Skarels return (error);
7442468Swnj }
7452468Swnj
7462468Swnj /*
7472468Swnj * Dump control bits into the DM registers.
7482468Swnj */
dmctl(dev,bits,how)7492468Swnj dmctl(dev, bits, how)
7502468Swnj dev_t dev;
7512468Swnj int bits, how;
7522468Swnj {
7532974Swnj register struct uba_device *ui;
7542468Swnj register struct dmdevice *addr;
7552468Swnj register int unit, s;
7562468Swnj int dm;
7572468Swnj
7582468Swnj unit = minor(dev);
7592468Swnj dm = unit >> 4;
7602468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7612468Swnj return;
7622468Swnj addr = (struct dmdevice *)ui->ui_addr;
7632468Swnj s = spl5();
7642479Swnj addr->dmcsr &= ~DM_SE;
7652479Swnj while (addr->dmcsr & DM_BUSY)
7662468Swnj ;
7672468Swnj addr->dmcsr = unit & 0xf;
7682468Swnj switch(how) {
7692468Swnj case DMSET:
7702468Swnj addr->dmlstat = bits;
7712468Swnj break;
7722468Swnj case DMBIS:
7732468Swnj addr->dmlstat |= bits;
7742468Swnj break;
7752468Swnj case DMBIC:
7762468Swnj addr->dmlstat &= ~bits;
7772468Swnj break;
7782468Swnj }
7793792Swnj addr->dmcsr = DM_IE|DM_SE;
7802468Swnj splx(s);
7812468Swnj }
7822468Swnj
7832468Swnj /*
7842468Swnj * DM11 interrupt; deal with carrier transitions.
7852468Swnj */
dmintr(dm)7862468Swnj dmintr(dm)
7872468Swnj register int dm;
7882468Swnj {
7892974Swnj register struct uba_device *ui;
7902468Swnj register struct tty *tp;
7912468Swnj register struct dmdevice *addr;
79216942Skarels int unit;
7932468Swnj
7942468Swnj ui = dminfo[dm];
7952479Swnj if (ui == 0)
7962479Swnj return;
7972468Swnj addr = (struct dmdevice *)ui->ui_addr;
7983997Sroot if (addr->dmcsr&DM_DONE) {
7993997Sroot if (addr->dmcsr&DM_CF) {
80016942Skarels unit = addr->dmcsr & 0xf;
80116942Skarels tp = &dh11[(dm << 4) + unit];
80225394Skarels if (addr->dmlstat & DML_CAR)
80325394Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1);
80425394Skarels else if ((dhsoftCAR[dm] & (1<<unit)) == 0 &&
80525394Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
80625394Skarels addr->dmlstat = 0;
8073997Sroot }
8083997Sroot addr->dmcsr = DM_IE|DM_SE;
8092468Swnj }
8102468Swnj }
8112625Swnj #endif
812