141480Smckusick /*
241480Smckusick * Copyright (c) 1988 University of Utah.
363151Sbostic * Copyright (c) 1982, 1986, 1990, 1993
463151Sbostic * The Regents of the University of California. All rights reserved.
541480Smckusick *
641480Smckusick * This code is derived from software contributed to Berkeley by
741480Smckusick * the Systems Programming Group of the University of Utah Computer
841480Smckusick * Science Department.
941480Smckusick *
1041480Smckusick * %sccs.include.redist.c%
1141480Smckusick *
1253929Shibler * from Utah: $Hdr: dcm.c 1.29 92/01/21$
1341480Smckusick *
14*68179Scgd * @(#)dcm.c 8.5 (Berkeley) 01/09/95
1541480Smckusick */
1641480Smckusick
1741480Smckusick /*
1842354Smckusick * TODO:
1942354Smckusick * Timeouts
2049130Skarels * Test console support.
2141480Smckusick */
2241480Smckusick
2341480Smckusick #include "dcm.h"
2441480Smckusick #if NDCM > 0
2541480Smckusick /*
2641480Smckusick * 98642/MUX
2741480Smckusick */
2856507Sbostic #include <sys/param.h>
2956507Sbostic #include <sys/systm.h>
3056507Sbostic #include <sys/ioctl.h>
3156507Sbostic #include <sys/proc.h>
3256507Sbostic #include <sys/tty.h>
3356507Sbostic #include <sys/conf.h>
3456507Sbostic #include <sys/file.h>
3556507Sbostic #include <sys/uio.h>
3656507Sbostic #include <sys/kernel.h>
3756507Sbostic #include <sys/syslog.h>
3856507Sbostic #include <sys/time.h>
3941480Smckusick
4056507Sbostic #include <hp/dev/device.h>
4141480Smckusick
4256507Sbostic #include <hp300/dev/dcmreg.h>
4356507Sbostic #include <machine/cpu.h>
4456507Sbostic #include <hp300/hp300/isr.h>
4556507Sbostic
4642354Smckusick #ifndef DEFAULT_BAUD_RATE
4742354Smckusick #define DEFAULT_BAUD_RATE 9600
4842354Smckusick #endif
4942354Smckusick
5052388Smckusick int dcmprobe(), dcmintr(), dcmparam();
5152388Smckusick void dcmstart();
5241480Smckusick struct driver dcmdriver = {
5341480Smckusick dcmprobe, "dcm",
5441480Smckusick };
5541480Smckusick
5641480Smckusick #define NDCMLINE (NDCM*4)
5741480Smckusick
5842354Smckusick struct tty dcm_tty[NDCMLINE];
5945750Smckusick struct modemreg *dcm_modem[NDCMLINE];
6044317Shibler char mcndlast[NDCMLINE]; /* XXX last modem status for line */
6142354Smckusick int ndcm = NDCMLINE;
6242354Smckusick
6342354Smckusick int dcm_active;
6441480Smckusick int dcmsoftCAR[NDCM];
6541480Smckusick struct dcmdevice *dcm_addr[NDCM];
6641480Smckusick struct isr dcmisr[NDCM];
6741480Smckusick
6841480Smckusick struct speedtab dcmspeedtab[] = {
6941480Smckusick 0, BR_0,
7041480Smckusick 50, BR_50,
7141480Smckusick 75, BR_75,
7241480Smckusick 110, BR_110,
7341480Smckusick 134, BR_134,
7441480Smckusick 150, BR_150,
7541480Smckusick 300, BR_300,
7641480Smckusick 600, BR_600,
7741480Smckusick 1200, BR_1200,
7841480Smckusick 1800, BR_1800,
7941480Smckusick 2400, BR_2400,
8041480Smckusick 4800, BR_4800,
8141480Smckusick 9600, BR_9600,
8241480Smckusick 19200, BR_19200,
8341480Smckusick 38400, BR_38400,
8441480Smckusick -1, -1
8541480Smckusick };
8641480Smckusick
8742354Smckusick /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
8842354Smckusick #define DCM_USPERCH(s) (10000000 / (s))
8942354Smckusick
9042354Smckusick /*
9142354Smckusick * Per board interrupt scheme. 16.7ms is the polling interrupt rate
9250220Skarels * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
9342354Smckusick */
9442354Smckusick #define DIS_TIMER 0
9542354Smckusick #define DIS_PERCHAR 1
9642354Smckusick #define DIS_RESET 2
9742354Smckusick
9842354Smckusick int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
9942354Smckusick int dcminterval = 5; /* interval (secs) between checks */
10042354Smckusick struct dcmischeme {
10142354Smckusick int dis_perchar; /* non-zero if interrupting per char */
10242354Smckusick long dis_time; /* last time examined */
10342354Smckusick int dis_intr; /* recv interrupts during last interval */
10442354Smckusick int dis_char; /* characters read during last interval */
10542354Smckusick } dcmischeme[NDCM];
10642354Smckusick
10742354Smckusick /*
10842354Smckusick * Console support
10942354Smckusick */
11049130Skarels #ifdef DCMCONSOLE
11149130Skarels int dcmconsole = DCMCONSOLE;
11249130Skarels #else
11342354Smckusick int dcmconsole = -1;
11449130Skarels #endif
11549130Skarels int dcmconsinit;
11642354Smckusick int dcmdefaultrate = DEFAULT_BAUD_RATE;
11742354Smckusick int dcmconbrdbusy = 0;
11849130Skarels int dcmmajor;
11942354Smckusick extern struct tty *constty;
12042354Smckusick
12142354Smckusick #ifdef KGDB
12242354Smckusick /*
12342354Smckusick * Kernel GDB support
12442354Smckusick */
12556507Sbostic #include <machine/remote-sl.h>
12649130Skarels
12750220Skarels extern dev_t kgdb_dev;
12842354Smckusick extern int kgdb_rate;
12942354Smckusick extern int kgdb_debug_init;
13042354Smckusick #endif
13142354Smckusick
13258053Shibler /* #define DCMSTATS */
13342354Smckusick
13441480Smckusick #ifdef DEBUG
13545750Smckusick int dcmdebug = 0x0;
13641480Smckusick #define DDB_SIOERR 0x01
13741480Smckusick #define DDB_PARAM 0x02
13841480Smckusick #define DDB_INPUT 0x04
13941480Smckusick #define DDB_OUTPUT 0x08
14041480Smckusick #define DDB_INTR 0x10
14142354Smckusick #define DDB_IOCTL 0x20
14242354Smckusick #define DDB_INTSCHM 0x40
14342354Smckusick #define DDB_MODEM 0x80
14441480Smckusick #define DDB_OPENCLOSE 0x100
14542354Smckusick #endif
14641480Smckusick
14758053Shibler #ifdef DCMSTATS
14842354Smckusick #define DCMRBSIZE 94
14942354Smckusick #define DCMXBSIZE 24
15042354Smckusick
15142354Smckusick struct dcmstats {
15242354Smckusick long xints; /* # of xmit ints */
15342354Smckusick long xchars; /* # of xmit chars */
15442354Smckusick long xempty; /* times outq is empty in dcmstart */
15542354Smckusick long xrestarts; /* times completed while xmitting */
15642354Smckusick long rints; /* # of recv ints */
15742354Smckusick long rchars; /* # of recv chars */
15842354Smckusick long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
15942354Smckusick long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
16042354Smckusick } dcmstats[NDCM];
16141480Smckusick #endif
16241480Smckusick
16341480Smckusick #define UNIT(x) minor(x)
16442354Smckusick #define BOARD(x) (((x) >> 2) & 0x3f)
16541480Smckusick #define PORT(x) ((x) & 3)
16641480Smckusick #define MKUNIT(b,p) (((b) << 2) | (p))
16741480Smckusick
16850220Skarels /*
16950220Skarels * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
17050220Skarels * the distribution panel uses "HP DCE" conventions. If requested via
17150220Skarels * the device flags, we swap the inputs to something closer to normal DCE,
17250220Skarels * allowing a straight-through cable to a DTE or a reversed cable
17350220Skarels * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
17450220Skarels * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
17550220Skarels * DSR or make RTS work, though). The following gives the full
17650220Skarels * details of a cable from this mux panel to a modem:
17750220Skarels *
17850220Skarels * HP modem
17950220Skarels * name pin pin name
18050220Skarels * HP inputs:
18150220Skarels * "Rx" 2 3 Tx
18250220Skarels * CTS 4 5 CTS (only needed for CCTS_OFLOW)
18350220Skarels * DCD 20 8 DCD
18450220Skarels * "DSR" 9 6 DSR (unneeded)
18550220Skarels * RI 22 22 RI (unneeded)
18650220Skarels *
18750220Skarels * HP outputs:
18850220Skarels * "Tx" 3 2 Rx
18950220Skarels * "DTR" 6 not connected
19050220Skarels * "RTS" 8 20 DTR
19150220Skarels * "SR" 23 4 RTS (often not needed)
19250220Skarels */
19350220Skarels #define FLAG_STDDCE 0x10 /* map inputs if this bit is set in flags */
19450220Skarels #define hp2dce_in(ibits) (iconv[(ibits) & 0xf])
19550220Skarels static char iconv[16] = {
19650220Skarels 0, MI_DM, MI_CTS, MI_CTS|MI_DM,
19750220Skarels MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM,
19850220Skarels MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM,
19950220Skarels MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
20050220Skarels MI_RI|MI_CD|MI_CTS|MI_DM
20150220Skarels };
20250220Skarels
dcmprobe(hd)20341480Smckusick dcmprobe(hd)
20441480Smckusick register struct hp_device *hd;
20541480Smckusick {
20641480Smckusick register struct dcmdevice *dcm;
20741480Smckusick register int i;
20841480Smckusick register int timo = 0;
20950220Skarels int s, brd, isconsole, mbits;
21041480Smckusick
21141480Smckusick dcm = (struct dcmdevice *)hd->hp_addr;
21241480Smckusick if ((dcm->dcm_rsid & 0x1f) != DCMID)
21341480Smckusick return (0);
21441480Smckusick brd = hd->hp_unit;
21542354Smckusick isconsole = (brd == BOARD(dcmconsole));
21642354Smckusick /*
21742354Smckusick * XXX selected console device (CONSUNIT) as determined by
21842354Smckusick * dcmcnprobe does not agree with logical numbering imposed
21942354Smckusick * by the config file (i.e. lowest address DCM is not unit
22042354Smckusick * CONSUNIT). Don't recognize this card.
22142354Smckusick */
22242354Smckusick if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)])
22350220Skarels return (0);
22442354Smckusick
22542354Smckusick /*
22642354Smckusick * Empirically derived self-test magic
22742354Smckusick */
22841480Smckusick s = spltty();
22941480Smckusick dcm->dcm_rsid = DCMRS;
23041480Smckusick DELAY(50000); /* 5000 is not long enough */
23141480Smckusick dcm->dcm_rsid = 0;
23241480Smckusick dcm->dcm_ic = IC_IE;
23341480Smckusick dcm->dcm_cr = CR_SELFT;
23442354Smckusick while ((dcm->dcm_ic & IC_IR) == 0)
23542354Smckusick if (++timo == 20000)
23650220Skarels return (0);
23741480Smckusick DELAY(50000) /* XXX why is this needed ???? */
23842354Smckusick while ((dcm->dcm_iir & IIR_SELFT) == 0)
23942354Smckusick if (++timo == 400000)
24050220Skarels return (0);
24141480Smckusick DELAY(50000) /* XXX why is this needed ???? */
24241480Smckusick if (dcm->dcm_stcon != ST_OK) {
24342354Smckusick if (!isconsole)
24442354Smckusick printf("dcm%d: self test failed: %x\n",
24542354Smckusick brd, dcm->dcm_stcon);
24650220Skarels return (0);
24741480Smckusick }
24841480Smckusick dcm->dcm_ic = IC_ID;
24941480Smckusick splx(s);
25041480Smckusick
25141480Smckusick hd->hp_ipl = DCMIPL(dcm->dcm_ic);
25242354Smckusick dcm_addr[brd] = dcm;
25342354Smckusick dcm_active |= 1 << brd;
25442354Smckusick dcmsoftCAR[brd] = hd->hp_flags;
25541480Smckusick dcmisr[brd].isr_ipl = hd->hp_ipl;
25641480Smckusick dcmisr[brd].isr_arg = brd;
25741480Smckusick dcmisr[brd].isr_intr = dcmintr;
25841480Smckusick isrlink(&dcmisr[brd]);
25942354Smckusick #ifdef KGDB
26049130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) {
26142354Smckusick if (dcmconsole == UNIT(kgdb_dev))
26250220Skarels kgdb_dev = NODEV; /* can't debug over console port */
26349301Shibler #ifndef KGDB_CHEAT
26449130Skarels /*
26549130Skarels * The following could potentially be replaced
26649130Skarels * by the corresponding code in dcmcnprobe.
26749130Skarels */
26842354Smckusick else {
26942354Smckusick (void) dcminit(kgdb_dev, kgdb_rate);
27042354Smckusick if (kgdb_debug_init) {
27149130Skarels printf("dcm%d: ", UNIT(kgdb_dev));
27249130Skarels kgdb_connect(1);
27342354Smckusick } else
27449130Skarels printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev));
27542354Smckusick }
27649130Skarels /* end could be replaced */
27749301Shibler #endif
27842354Smckusick }
27942354Smckusick #endif
28042354Smckusick if (dcmistype == DIS_TIMER)
28142354Smckusick dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
28242354Smckusick else
28342354Smckusick dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
28445750Smckusick
28545750Smckusick /* load pointers to modem control */
28645750Smckusick dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0;
28745750Smckusick dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1;
28845750Smckusick dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2;
28945750Smckusick dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3;
29045750Smckusick /* set DCD (modem) and CTS (flow control) on all ports */
29150220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE)
29250220Skarels mbits = hp2dce_in(MI_CD|MI_CTS);
29350220Skarels else
29450220Skarels mbits = MI_CD|MI_CTS;
29545750Smckusick for (i = 0; i < 4; i++)
29650220Skarels dcm_modem[MKUNIT(brd, i)]->mdmmsk = mbits;
29745750Smckusick
29842354Smckusick dcm->dcm_ic = IC_IE; /* turn all interrupts on */
29941480Smckusick /*
30041480Smckusick * Need to reset baud rate, etc. of next print so reset dcmconsole.
30141480Smckusick * Also make sure console is always "hardwired"
30241480Smckusick */
30342354Smckusick if (isconsole) {
30449130Skarels dcmconsinit = 0;
30541480Smckusick dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
30641480Smckusick }
30741480Smckusick return (1);
30841480Smckusick }
30941480Smckusick
31049130Skarels /* ARGSUSED */
31149130Skarels #ifdef __STDC__
dcmopen(dev_t dev,int flag,int mode,struct proc * p)31249130Skarels dcmopen(dev_t dev, int flag, int mode, struct proc *p)
31349130Skarels #else
31449130Skarels dcmopen(dev, flag, mode, p)
31541480Smckusick dev_t dev;
31649130Skarels int flag, mode;
31749130Skarels struct proc *p;
31849130Skarels #endif
31941480Smckusick {
32041480Smckusick register struct tty *tp;
32141480Smckusick register int unit, brd;
32250220Skarels int error = 0, mbits;
32341480Smckusick
32441480Smckusick unit = UNIT(dev);
32541480Smckusick brd = BOARD(unit);
32642354Smckusick if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0)
32741480Smckusick return (ENXIO);
32841480Smckusick tp = &dcm_tty[unit];
32941480Smckusick tp->t_oproc = dcmstart;
33042354Smckusick tp->t_param = dcmparam;
33141480Smckusick tp->t_dev = dev;
33241480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) {
33342950Smarc tp->t_state |= TS_WOPEN;
33441480Smckusick ttychars(tp);
33549130Skarels if (tp->t_ispeed == 0) {
33649130Skarels tp->t_iflag = TTYDEF_IFLAG;
33749130Skarels tp->t_oflag = TTYDEF_OFLAG;
33849130Skarels tp->t_cflag = TTYDEF_CFLAG;
33949130Skarels tp->t_lflag = TTYDEF_LFLAG;
34049130Skarels tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
34149130Skarels }
34242354Smckusick (void) dcmparam(tp, &tp->t_termios);
34341480Smckusick ttsetwater(tp);
34449130Skarels } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
34541480Smckusick return (EBUSY);
34650220Skarels mbits = MO_ON;
34750220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE)
34850220Skarels mbits |= MO_SR; /* pin 23, could be used as RTS */
34950220Skarels (void) dcmmctl(dev, mbits, DMSET); /* enable port */
35049130Skarels if ((dcmsoftCAR[brd] & (1 << PORT(unit))) ||
35149130Skarels (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
35241480Smckusick tp->t_state |= TS_CARR_ON;
35345750Smckusick #ifdef DEBUG
35445750Smckusick if (dcmdebug & DDB_MODEM)
35545750Smckusick printf("dcm%d: dcmopen port %d softcarr %c\n",
35645750Smckusick brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0');
35745750Smckusick #endif
35841480Smckusick (void) spltty();
35944295Shibler while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
36050220Skarels (tp->t_state & TS_CARR_ON) == 0) {
36141480Smckusick tp->t_state |= TS_WOPEN;
36244295Shibler if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
36344295Shibler ttopen, 0))
36444295Shibler break;
36541480Smckusick }
36641480Smckusick (void) spl0();
36745750Smckusick
36841480Smckusick #ifdef DEBUG
36941480Smckusick if (dcmdebug & DDB_OPENCLOSE)
37041480Smckusick printf("dcmopen: u %x st %x fl %x\n",
37141480Smckusick unit, tp->t_state, tp->t_flags);
37241480Smckusick #endif
37344295Shibler if (error == 0)
37444295Shibler error = (*linesw[tp->t_line].l_open)(dev, tp);
37544295Shibler return (error);
37641480Smckusick }
37741480Smckusick
37841480Smckusick /*ARGSUSED*/
dcmclose(dev,flag,mode,p)37949750Smarc dcmclose(dev, flag, mode, p)
38041480Smckusick dev_t dev;
38149750Smarc int flag, mode;
38249750Smarc struct proc *p;
38341480Smckusick {
38441480Smckusick register struct tty *tp;
38541480Smckusick int unit;
38641480Smckusick
38741480Smckusick unit = UNIT(dev);
38841480Smckusick tp = &dcm_tty[unit];
38949750Smarc (*linesw[tp->t_line].l_close)(tp, flag);
39050220Skarels if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
39150220Skarels (tp->t_state&TS_ISOPEN) == 0)
39250220Skarels (void) dcmmctl(dev, MO_OFF, DMSET);
39341480Smckusick #ifdef DEBUG
39441480Smckusick if (dcmdebug & DDB_OPENCLOSE)
39541480Smckusick printf("dcmclose: u %x st %x fl %x\n",
39641480Smckusick unit, tp->t_state, tp->t_flags);
39741480Smckusick #endif
39841480Smckusick ttyclose(tp);
39950220Skarels return (0);
40041480Smckusick }
40141480Smckusick
dcmread(dev,uio,flag)40241480Smckusick dcmread(dev, uio, flag)
40341480Smckusick dev_t dev;
40441480Smckusick struct uio *uio;
40565634Sbostic int flag;
40641480Smckusick {
40741480Smckusick register struct tty *tp;
40841480Smckusick
40941480Smckusick tp = &dcm_tty[UNIT(dev)];
41041480Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
41141480Smckusick }
41241480Smckusick
dcmwrite(dev,uio,flag)41341480Smckusick dcmwrite(dev, uio, flag)
41441480Smckusick dev_t dev;
41541480Smckusick struct uio *uio;
41665634Sbostic int flag;
41741480Smckusick {
41841480Smckusick int unit = UNIT(dev);
41941480Smckusick register struct tty *tp;
42041480Smckusick
42141480Smckusick tp = &dcm_tty[unit];
42242354Smckusick /*
42342354Smckusick * XXX we disallow virtual consoles if the physical console is
42442354Smckusick * a serial port. This is in case there is a display attached that
42542354Smckusick * is not the console. In that situation we don't need/want the X
42642354Smckusick * server taking over the console.
42742354Smckusick */
42842354Smckusick if (constty && unit == dcmconsole)
42942354Smckusick constty = NULL;
43041480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
43141480Smckusick }
43241480Smckusick
dcmintr(brd)43341480Smckusick dcmintr(brd)
43441480Smckusick register int brd;
43541480Smckusick {
43642354Smckusick register struct dcmdevice *dcm = dcm_addr[brd];
43742354Smckusick register struct dcmischeme *dis;
43845750Smckusick register int unit = MKUNIT(brd, 0);
43945750Smckusick register int code, i;
44045750Smckusick int pcnd[4], mcode, mcnd[4];
44141480Smckusick
44242354Smckusick /*
44342354Smckusick * Do all guarded register accesses right off to minimize
44442354Smckusick * block out of hardware.
44542354Smckusick */
44641480Smckusick SEM_LOCK(dcm);
44741480Smckusick if ((dcm->dcm_ic & IC_IR) == 0) {
44841480Smckusick SEM_UNLOCK(dcm);
44950220Skarels return (0);
45041480Smckusick }
45141480Smckusick for (i = 0; i < 4; i++) {
45241480Smckusick pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
45341480Smckusick dcm->dcm_icrtab[i].dcm_data = 0;
45450220Skarels code = dcm_modem[unit+i]->mdmin;
45550220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE)
45650220Skarels code = hp2dce_in(code);
45750220Skarels mcnd[i] = code;
45841480Smckusick }
45941480Smckusick code = dcm->dcm_iir & IIR_MASK;
46042354Smckusick dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */
46145750Smckusick mcode = dcm->dcm_modemintr;
46245750Smckusick dcm->dcm_modemintr = 0;
46341480Smckusick SEM_UNLOCK(dcm);
46441480Smckusick
46541480Smckusick #ifdef DEBUG
46645750Smckusick if (dcmdebug & DDB_INTR) {
46745750Smckusick printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ",
46845750Smckusick brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]);
46945750Smckusick printf("miir %x mc %x/%x/%x/%x\n",
47045750Smckusick mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
47145750Smckusick }
47241480Smckusick #endif
47342354Smckusick if (code & IIR_TIMEO)
47442354Smckusick dcmrint(brd, dcm);
47541480Smckusick if (code & IIR_PORT0)
47645750Smckusick dcmpint(unit+0, pcnd[0], dcm);
47741480Smckusick if (code & IIR_PORT1)
47845750Smckusick dcmpint(unit+1, pcnd[1], dcm);
47941480Smckusick if (code & IIR_PORT2)
48045750Smckusick dcmpint(unit+2, pcnd[2], dcm);
48141480Smckusick if (code & IIR_PORT3)
48245750Smckusick dcmpint(unit+3, pcnd[3], dcm);
48345750Smckusick if (code & IIR_MODM) {
48445750Smckusick if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */
48545750Smckusick dcmmint(unit+0, mcnd[0], dcm);
48645750Smckusick if (mcode & 0x2)
48745750Smckusick dcmmint(unit+1, mcnd[1], dcm);
48845750Smckusick if (mcode & 0x4)
48945750Smckusick dcmmint(unit+2, mcnd[2], dcm);
49045750Smckusick if (mcode & 0x8)
49145750Smckusick dcmmint(unit+3, mcnd[3], dcm);
49245750Smckusick }
49341480Smckusick
49442354Smckusick dis = &dcmischeme[brd];
49541480Smckusick /*
49642354Smckusick * Chalk up a receiver interrupt if the timer running or one of
49742354Smckusick * the ports reports a special character interrupt.
49841480Smckusick */
49942354Smckusick if ((code & IIR_TIMEO) ||
50042354Smckusick ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
50142354Smckusick dis->dis_intr++;
50242354Smckusick /*
50342354Smckusick * See if it is time to check/change the interrupt rate.
50442354Smckusick */
50542354Smckusick if (dcmistype < 0 &&
50645750Smckusick (i = time.tv_sec - dis->dis_time) >= dcminterval) {
50741480Smckusick /*
50842354Smckusick * If currently per-character and averaged over 70 interrupts
50942354Smckusick * per-second (66 is threshold of 600 baud) in last interval,
51042354Smckusick * switch to timer mode.
51142354Smckusick *
51242354Smckusick * XXX decay counts ala load average to avoid spikes?
51341480Smckusick */
51445750Smckusick if (dis->dis_perchar && dis->dis_intr > 70 * i)
51542354Smckusick dcmsetischeme(brd, DIS_TIMER);
51642354Smckusick /*
51742354Smckusick * If currently using timer and had more interrupts than
51842354Smckusick * received characters in the last interval, switch back
51942354Smckusick * to per-character. Note that after changing to per-char
52042354Smckusick * we must process any characters already in the queue
52142354Smckusick * since they may have arrived before the bitmap was setup.
52242354Smckusick *
52342354Smckusick * XXX decay counts?
52442354Smckusick */
52542354Smckusick else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
52642354Smckusick dcmsetischeme(brd, DIS_PERCHAR);
52741480Smckusick dcmrint(brd, dcm);
52841480Smckusick }
52942354Smckusick dis->dis_intr = dis->dis_char = 0;
53042354Smckusick dis->dis_time = time.tv_sec;
53142354Smckusick }
53250220Skarels return (1);
53341480Smckusick }
53441480Smckusick
53541480Smckusick /*
53641480Smckusick * Port interrupt. Can be two things:
53741480Smckusick * First, it might be a special character (exception interrupt);
53841480Smckusick * Second, it may be a buffer empty (transmit interrupt);
53941480Smckusick */
dcmpint(unit,code,dcm)54041480Smckusick dcmpint(unit, code, dcm)
54141480Smckusick int unit, code;
54242354Smckusick struct dcmdevice *dcm;
54341480Smckusick {
54442354Smckusick struct tty *tp = &dcm_tty[unit];
54541480Smckusick
54642354Smckusick if (code & IT_SPEC)
54742354Smckusick dcmreadbuf(unit, dcm, tp);
54841480Smckusick if (code & IT_TX)
54942354Smckusick dcmxint(unit, dcm, tp);
55041480Smckusick }
55141480Smckusick
dcmrint(brd,dcm)55241480Smckusick dcmrint(brd, dcm)
55341480Smckusick int brd;
55441480Smckusick register struct dcmdevice *dcm;
55541480Smckusick {
55642354Smckusick register int i, unit;
55741480Smckusick register struct tty *tp;
55841480Smckusick
55941480Smckusick unit = MKUNIT(brd, 0);
56041480Smckusick tp = &dcm_tty[unit];
56142354Smckusick for (i = 0; i < 4; i++, tp++, unit++)
56242354Smckusick dcmreadbuf(unit, dcm, tp);
56341480Smckusick }
56441480Smckusick
dcmreadbuf(unit,dcm,tp)56542354Smckusick dcmreadbuf(unit, dcm, tp)
56641480Smckusick int unit;
56741480Smckusick register struct dcmdevice *dcm;
56841480Smckusick register struct tty *tp;
56941480Smckusick {
57042354Smckusick int port = PORT(unit);
57142354Smckusick register struct dcmpreg *pp = dcm_preg(dcm, port);
57242354Smckusick register struct dcmrfifo *fifo;
57341480Smckusick register int c, stat;
57441480Smckusick register unsigned head;
57542354Smckusick int nch = 0;
57658053Shibler #ifdef DCMSTATS
57742354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(unit)];
57841480Smckusick
57942354Smckusick dsp->rints++;
58042354Smckusick #endif
58143407Shibler if ((tp->t_state & TS_ISOPEN) == 0) {
58242354Smckusick #ifdef KGDB
58349130Skarels if ((makedev(dcmmajor, unit) == kgdb_dev) &&
58442354Smckusick (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
58555683Smccanne dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
58642354Smckusick pp->r_head = (head + 2) & RX_MASK;
58749130Skarels kgdb_connect(0); /* trap into kgdb */
58842354Smckusick return;
58942354Smckusick }
59049130Skarels #endif /* KGDB */
59142354Smckusick pp->r_head = pp->r_tail & RX_MASK;
59242354Smckusick return;
59342354Smckusick }
59441480Smckusick
59542354Smckusick head = pp->r_head & RX_MASK;
59642354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1];
59742354Smckusick /*
59842354Smckusick * XXX upper bound on how many chars we will take in one swallow?
59942354Smckusick */
60042354Smckusick while (head != (pp->r_tail & RX_MASK)) {
60142354Smckusick /*
60242354Smckusick * Get character/status and update head pointer as fast
60342354Smckusick * as possible to make room for more characters.
60442354Smckusick */
60542354Smckusick c = fifo->data_char;
60642354Smckusick stat = fifo->data_stat;
60741480Smckusick head = (head + 2) & RX_MASK;
60842354Smckusick pp->r_head = head;
60942354Smckusick fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
61042354Smckusick nch++;
61141480Smckusick
61241480Smckusick #ifdef DEBUG
61341480Smckusick if (dcmdebug & DDB_INPUT)
61442354Smckusick printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n",
61542354Smckusick unit, c&0xFF, c, stat&0xFF,
61642354Smckusick tp->t_flags, head, pp->r_tail);
61741480Smckusick #endif
61842354Smckusick /*
61942354Smckusick * Check for and handle errors
62042354Smckusick */
62142354Smckusick if (stat & RD_MASK) {
62241480Smckusick #ifdef DEBUG
62342354Smckusick if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
62442354Smckusick printf("dcmreadbuf(%d): err: c%x('%c') s%x\n",
62542354Smckusick unit, stat, c&0xFF, c);
62641480Smckusick #endif
62741480Smckusick if (stat & (RD_BD | RD_FE))
62841480Smckusick c |= TTY_FE;
62941480Smckusick else if (stat & RD_PE)
63041480Smckusick c |= TTY_PE;
63141480Smckusick else if (stat & RD_OVF)
63241480Smckusick log(LOG_WARNING,
63342354Smckusick "dcm%d: silo overflow\n", unit);
63441480Smckusick else if (stat & RD_OE)
63541480Smckusick log(LOG_WARNING,
63642354Smckusick "dcm%d: uart overflow\n", unit);
63741480Smckusick }
63841480Smckusick (*linesw[tp->t_line].l_rint)(c, tp);
63941480Smckusick }
64042354Smckusick dcmischeme[BOARD(unit)].dis_char += nch;
64158053Shibler #ifdef DCMSTATS
64242354Smckusick dsp->rchars += nch;
64342354Smckusick if (nch <= DCMRBSIZE)
64442354Smckusick dsp->rsilo[nch]++;
64541480Smckusick else
64642354Smckusick dsp->rsilo[DCMRBSIZE+1]++;
64741480Smckusick #endif
64841480Smckusick }
64941480Smckusick
dcmxint(unit,dcm,tp)65042354Smckusick dcmxint(unit, dcm, tp)
65141480Smckusick int unit;
65241480Smckusick struct dcmdevice *dcm;
65342354Smckusick register struct tty *tp;
65441480Smckusick {
65541480Smckusick tp->t_state &= ~TS_BUSY;
65641480Smckusick if (tp->t_state & TS_FLUSH)
65741480Smckusick tp->t_state &= ~TS_FLUSH;
65849130Skarels (*linesw[tp->t_line].l_start)(tp);
65941480Smckusick }
66041480Smckusick
dcmmint(unit,mcnd,dcm)66141480Smckusick dcmmint(unit, mcnd, dcm)
66241480Smckusick register int unit;
66341480Smckusick register struct dcmdevice *dcm;
66441480Smckusick int mcnd;
66541480Smckusick {
66641480Smckusick register struct tty *tp;
66744317Shibler int delta;
66841480Smckusick
66941480Smckusick #ifdef DEBUG
67042354Smckusick if (dcmdebug & DDB_MODEM)
67145750Smckusick printf("dcmmint: port %d mcnd %x mcndlast %x\n",
67244317Shibler unit, mcnd, mcndlast[unit]);
67342354Smckusick #endif
67441480Smckusick tp = &dcm_tty[unit];
67544317Shibler delta = mcnd ^ mcndlast[unit];
67644317Shibler mcndlast[unit] = mcnd;
67749130Skarels if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
67850220Skarels (tp->t_flags & CCTS_OFLOW)) {
67949130Skarels if (mcnd & MI_CTS) {
68049130Skarels tp->t_state &= ~TS_TTSTOP;
68149130Skarels ttstart(tp);
68249130Skarels } else
68349130Skarels tp->t_state |= TS_TTSTOP; /* inline dcmstop */
68449130Skarels }
68550220Skarels if (delta & MI_CD) {
68641480Smckusick if (mcnd & MI_CD)
68744317Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1);
68850220Skarels else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 &&
68950220Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
69050220Skarels dcm_modem[unit]->mdmout = MO_OFF;
69141480Smckusick SEM_LOCK(dcm);
69245750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3);
69341480Smckusick dcm->dcm_cr |= CR_MODM;
69441480Smckusick SEM_UNLOCK(dcm);
69542354Smckusick DELAY(10); /* time to change lines */
69641480Smckusick }
69741480Smckusick }
69841480Smckusick }
69941480Smckusick
dcmioctl(dev,cmd,data,flag,p)70052422Smckusick dcmioctl(dev, cmd, data, flag, p)
70141480Smckusick dev_t dev;
702*68179Scgd u_long cmd;
70341480Smckusick caddr_t data;
70452422Smckusick int flag;
70552422Smckusick struct proc *p;
70641480Smckusick {
70741480Smckusick register struct tty *tp;
70841480Smckusick register int unit = UNIT(dev);
70941480Smckusick register struct dcmdevice *dcm;
71041480Smckusick register int port;
71142354Smckusick int error, s;
71241480Smckusick
71341480Smckusick #ifdef DEBUG
71441480Smckusick if (dcmdebug & DDB_IOCTL)
71541480Smckusick printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
71641480Smckusick unit, cmd, *data, flag);
71741480Smckusick #endif
71841480Smckusick tp = &dcm_tty[unit];
71952422Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
72041480Smckusick if (error >= 0)
72141480Smckusick return (error);
72241480Smckusick error = ttioctl(tp, cmd, data, flag);
72341480Smckusick if (error >= 0)
72441480Smckusick return (error);
72541480Smckusick
72641480Smckusick port = PORT(unit);
72741480Smckusick dcm = dcm_addr[BOARD(unit)];
72841480Smckusick switch (cmd) {
72941480Smckusick case TIOCSBRK:
73042354Smckusick /*
73142354Smckusick * Wait for transmitter buffer to empty
73242354Smckusick */
73342354Smckusick s = spltty();
73442354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
73542354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed));
73641480Smckusick SEM_LOCK(dcm);
73742354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
73842354Smckusick dcm->dcm_cr |= (1 << port); /* start break */
73941480Smckusick SEM_UNLOCK(dcm);
74042354Smckusick splx(s);
74141480Smckusick break;
74241480Smckusick
74341480Smckusick case TIOCCBRK:
74441480Smckusick SEM_LOCK(dcm);
74542354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
74642354Smckusick dcm->dcm_cr |= (1 << port); /* end break */
74741480Smckusick SEM_UNLOCK(dcm);
74841480Smckusick break;
74941480Smckusick
75041480Smckusick case TIOCSDTR:
75141480Smckusick (void) dcmmctl(dev, MO_ON, DMBIS);
75241480Smckusick break;
75341480Smckusick
75441480Smckusick case TIOCCDTR:
75541480Smckusick (void) dcmmctl(dev, MO_ON, DMBIC);
75641480Smckusick break;
75741480Smckusick
75841480Smckusick case TIOCMSET:
75941480Smckusick (void) dcmmctl(dev, *(int *)data, DMSET);
76041480Smckusick break;
76141480Smckusick
76241480Smckusick case TIOCMBIS:
76341480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIS);
76441480Smckusick break;
76541480Smckusick
76641480Smckusick case TIOCMBIC:
76741480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIC);
76841480Smckusick break;
76941480Smckusick
77041480Smckusick case TIOCMGET:
77141480Smckusick *(int *)data = dcmmctl(dev, 0, DMGET);
77241480Smckusick break;
77341480Smckusick
77441480Smckusick default:
77541480Smckusick return (ENOTTY);
77641480Smckusick }
77741480Smckusick return (0);
77841480Smckusick }
77941480Smckusick
dcmparam(tp,t)78041480Smckusick dcmparam(tp, t)
78141480Smckusick register struct tty *tp;
78241480Smckusick register struct termios *t;
78341480Smckusick {
78441480Smckusick register struct dcmdevice *dcm;
78542354Smckusick register int port, mode, cflag = t->c_cflag;
78641480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
78742354Smckusick
78841480Smckusick /* check requested parameters */
78941480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
79050220Skarels return (EINVAL);
79141480Smckusick /* and copy to tty */
79241480Smckusick tp->t_ispeed = t->c_ispeed;
79341480Smckusick tp->t_ospeed = t->c_ospeed;
79441480Smckusick tp->t_cflag = cflag;
79541480Smckusick if (ospeed == 0) {
79642354Smckusick (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET);
79750220Skarels return (0);
79841480Smckusick }
79942354Smckusick
80042354Smckusick mode = 0;
80141480Smckusick switch (cflag&CSIZE) {
80241480Smckusick case CS5:
80341480Smckusick mode = LC_5BITS; break;
80441480Smckusick case CS6:
80541480Smckusick mode = LC_6BITS; break;
80641480Smckusick case CS7:
80741480Smckusick mode = LC_7BITS; break;
80841480Smckusick case CS8:
80941480Smckusick mode = LC_8BITS; break;
81041480Smckusick }
81141480Smckusick if (cflag&PARENB) {
81241480Smckusick if (cflag&PARODD)
81341480Smckusick mode |= LC_PODD;
81441480Smckusick else
81541480Smckusick mode |= LC_PEVEN;
81641480Smckusick }
81741480Smckusick if (cflag&CSTOPB)
81841480Smckusick mode |= LC_2STOP;
81941480Smckusick else
82041480Smckusick mode |= LC_1STOP;
82141480Smckusick #ifdef DEBUG
82241480Smckusick if (dcmdebug & DDB_PARAM)
82342354Smckusick printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n",
82442354Smckusick UNIT(tp->t_dev), cflag, mode, tp->t_ospeed,
82542354Smckusick DCM_USPERCH(tp->t_ospeed));
82641480Smckusick #endif
82742354Smckusick
82842354Smckusick port = PORT(tp->t_dev);
82942354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)];
83042354Smckusick /*
83142354Smckusick * Wait for transmitter buffer to empty.
83242354Smckusick */
83341480Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
83442354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed));
83542354Smckusick /*
83642354Smckusick * Make changes known to hardware.
83742354Smckusick */
83842354Smckusick dcm->dcm_data[port].dcm_baud = ospeed;
83941480Smckusick dcm->dcm_data[port].dcm_conf = mode;
84041480Smckusick SEM_LOCK(dcm);
84142354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
84242354Smckusick dcm->dcm_cr |= (1 << port);
84341480Smckusick SEM_UNLOCK(dcm);
84442354Smckusick /*
84549130Skarels * Delay for config change to take place. Weighted by baud.
84642354Smckusick * XXX why do we do this?
84742354Smckusick */
84842354Smckusick DELAY(16 * DCM_USPERCH(tp->t_ospeed));
84950220Skarels return (0);
85041480Smckusick }
85141480Smckusick
85252388Smckusick void
dcmstart(tp)85341480Smckusick dcmstart(tp)
85441480Smckusick register struct tty *tp;
85541480Smckusick {
85641480Smckusick register struct dcmdevice *dcm;
85742354Smckusick register struct dcmpreg *pp;
85842354Smckusick register struct dcmtfifo *fifo;
85942354Smckusick register char *bp;
86042354Smckusick register unsigned tail, next;
86142354Smckusick register int port, nch;
86242354Smckusick unsigned head;
86342354Smckusick char buf[16];
86442354Smckusick int s;
86558053Shibler #ifdef DCMSTATS
86642354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)];
86742354Smckusick int tch = 0;
86842354Smckusick #endif
86942354Smckusick
87041480Smckusick s = spltty();
87158053Shibler #ifdef DCMSTATS
87242354Smckusick dsp->xints++;
87342354Smckusick #endif
87441480Smckusick #ifdef DEBUG
87541480Smckusick if (dcmdebug & DDB_OUTPUT)
87642354Smckusick printf("dcmstart(%d): state %x flags %x outcc %d\n",
87742354Smckusick UNIT(tp->t_dev), tp->t_state, tp->t_flags,
87842354Smckusick tp->t_outq.c_cc);
87941480Smckusick #endif
88041480Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
88141480Smckusick goto out;
88241480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) {
88341480Smckusick if (tp->t_state&TS_ASLEEP) {
88441480Smckusick tp->t_state &= ~TS_ASLEEP;
88541480Smckusick wakeup((caddr_t)&tp->t_outq);
88641480Smckusick }
88752528Storek selwakeup(&tp->t_wsel);
88841480Smckusick }
88942354Smckusick if (tp->t_outq.c_cc == 0) {
89058053Shibler #ifdef DCMSTATS
89142354Smckusick dsp->xempty++;
89242354Smckusick #endif
89342354Smckusick goto out;
89442354Smckusick }
89542354Smckusick
89642354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)];
89742354Smckusick port = PORT(tp->t_dev);
89842354Smckusick pp = dcm_preg(dcm, port);
89942354Smckusick tail = pp->t_tail & TX_MASK;
90042354Smckusick next = (tail + 1) & TX_MASK;
90142354Smckusick head = pp->t_head & TX_MASK;
90242354Smckusick if (head == next)
90342354Smckusick goto out;
90442354Smckusick fifo = &dcm->dcm_tfifos[3-port][tail];
90542354Smckusick again:
90642354Smckusick nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
90758053Shibler #ifdef DCMSTATS
90842354Smckusick tch += nch;
90942354Smckusick #endif
91041480Smckusick #ifdef DEBUG
91142354Smckusick if (dcmdebug & DDB_OUTPUT)
91242354Smckusick printf("\thead %x tail %x nch %d\n", head, tail, nch);
91341480Smckusick #endif
91442354Smckusick /*
91542354Smckusick * Loop transmitting all the characters we can.
91642354Smckusick */
91742354Smckusick for (bp = buf; --nch >= 0; bp++) {
91842354Smckusick fifo->data_char = *bp;
91942354Smckusick pp->t_tail = next;
92042354Smckusick /*
92142354Smckusick * If this is the first character,
92242354Smckusick * get the hardware moving right now.
92342354Smckusick */
92442354Smckusick if (bp == buf) {
92542354Smckusick tp->t_state |= TS_BUSY;
92642354Smckusick SEM_LOCK(dcm);
92742354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
92842354Smckusick dcm->dcm_cr |= (1 << port);
92942354Smckusick SEM_UNLOCK(dcm);
93042354Smckusick }
93141480Smckusick tail = next;
93242354Smckusick fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
93342354Smckusick next = (next + 1) & TX_MASK;
93441480Smckusick }
93542354Smckusick /*
93642354Smckusick * Head changed while we were loading the buffer,
93742354Smckusick * go back and load some more if we can.
93842354Smckusick */
93942354Smckusick if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
94058053Shibler #ifdef DCMSTATS
94142354Smckusick dsp->xrestarts++;
94242354Smckusick #endif
94342354Smckusick head = pp->t_head & TX_MASK;
94442354Smckusick goto again;
94542354Smckusick }
94649130Skarels
94742354Smckusick /*
94842354Smckusick * Kick it one last time in case it finished while we were
94944317Shibler * loading the last bunch.
95042354Smckusick */
95142354Smckusick if (bp > &buf[1]) {
95241480Smckusick tp->t_state |= TS_BUSY;
95341480Smckusick SEM_LOCK(dcm);
95442354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
95542354Smckusick dcm->dcm_cr |= (1 << port);
95642354Smckusick SEM_UNLOCK(dcm);
95742354Smckusick }
95841480Smckusick #ifdef DEBUG
95941480Smckusick if (dcmdebug & DDB_INTR)
96043407Shibler printf("dcmstart(%d): head %x tail %x outqcc %d\n",
96143407Shibler UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc);
96241480Smckusick #endif
96341480Smckusick out:
96458053Shibler #ifdef DCMSTATS
96542354Smckusick dsp->xchars += tch;
96642354Smckusick if (tch <= DCMXBSIZE)
96742354Smckusick dsp->xsilo[tch]++;
96842354Smckusick else
96942354Smckusick dsp->xsilo[DCMXBSIZE+1]++;
97042354Smckusick #endif
97141480Smckusick splx(s);
97241480Smckusick }
97341480Smckusick
97441480Smckusick /*
97541480Smckusick * Stop output on a line.
97641480Smckusick */
dcmstop(tp,flag)97741480Smckusick dcmstop(tp, flag)
97841480Smckusick register struct tty *tp;
97965635Sbostic int flag;
98041480Smckusick {
98141480Smckusick int s;
98241480Smckusick
98341480Smckusick s = spltty();
98441480Smckusick if (tp->t_state & TS_BUSY) {
98542354Smckusick /* XXX is there some way to safely stop transmission? */
98644317Shibler if ((tp->t_state&TS_TTSTOP) == 0)
98741480Smckusick tp->t_state |= TS_FLUSH;
98841480Smckusick }
98941480Smckusick splx(s);
99041480Smckusick }
99141480Smckusick
99245750Smckusick /*
99345750Smckusick * Modem control
99445750Smckusick */
dcmmctl(dev,bits,how)99541480Smckusick dcmmctl(dev, bits, how)
99641480Smckusick dev_t dev;
99741480Smckusick int bits, how;
99841480Smckusick {
99941480Smckusick register struct dcmdevice *dcm;
100050220Skarels int s, unit, brd, hit = 0;
100141480Smckusick
100245750Smckusick unit = UNIT(dev);
100345750Smckusick #ifdef DEBUG
100445750Smckusick if (dcmdebug & DDB_MODEM)
100545750Smckusick printf("dcmmctl(%d) unit %d bits 0x%x how %x\n",
100645750Smckusick BOARD(unit), unit, bits, how);
100745750Smckusick #endif
100841480Smckusick
100950220Skarels brd = BOARD(unit);
101050220Skarels dcm = dcm_addr[brd];
101141480Smckusick s = spltty();
101241480Smckusick switch (how) {
101341480Smckusick
101441480Smckusick case DMSET:
101545750Smckusick dcm_modem[unit]->mdmout = bits;
101641480Smckusick hit++;
101741480Smckusick break;
101841480Smckusick
101941480Smckusick case DMBIS:
102045750Smckusick dcm_modem[unit]->mdmout |= bits;
102141480Smckusick hit++;
102241480Smckusick break;
102341480Smckusick
102441480Smckusick case DMBIC:
102545750Smckusick dcm_modem[unit]->mdmout &= ~bits;
102641480Smckusick hit++;
102741480Smckusick break;
102841480Smckusick
102941480Smckusick case DMGET:
103045750Smckusick bits = dcm_modem[unit]->mdmin;
103150220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE)
103250220Skarels bits = hp2dce_in(bits);
103341480Smckusick break;
103441480Smckusick }
103541480Smckusick if (hit) {
103641480Smckusick SEM_LOCK(dcm);
103745750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3);
103841480Smckusick dcm->dcm_cr |= CR_MODM;
103941480Smckusick SEM_UNLOCK(dcm);
104042354Smckusick DELAY(10); /* delay until done */
104141480Smckusick (void) splx(s);
104241480Smckusick }
104350220Skarels return (bits);
104441480Smckusick }
104541480Smckusick
104642354Smckusick /*
104742354Smckusick * Set board to either interrupt per-character or at a fixed interval.
104842354Smckusick */
dcmsetischeme(brd,flags)104942354Smckusick dcmsetischeme(brd, flags)
105042354Smckusick int brd, flags;
105141480Smckusick {
105242354Smckusick register struct dcmdevice *dcm = dcm_addr[brd];
105342354Smckusick register struct dcmischeme *dis = &dcmischeme[brd];
105441480Smckusick register int i;
105542354Smckusick u_char mask;
105642354Smckusick int perchar = flags & DIS_PERCHAR;
105741480Smckusick
105841480Smckusick #ifdef DEBUG
105942354Smckusick if (dcmdebug & DDB_INTSCHM)
106042354Smckusick printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",
106142354Smckusick brd, perchar, dis->dis_perchar,
106242354Smckusick dis->dis_intr, dis->dis_char);
106342354Smckusick if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
106442354Smckusick printf("dcmsetischeme(%d): redundent request %d\n",
106542354Smckusick brd, perchar);
106642354Smckusick return;
106742354Smckusick }
106842354Smckusick #endif
106942354Smckusick /*
107042354Smckusick * If perchar is non-zero, we enable interrupts on all characters
107142354Smckusick * otherwise we disable perchar interrupts and use periodic
107242354Smckusick * polling interrupts.
107342354Smckusick */
107442354Smckusick dis->dis_perchar = perchar;
107542354Smckusick mask = perchar ? 0xf : 0x0;
107642354Smckusick for (i = 0; i < 256; i++)
107742354Smckusick dcm->dcm_bmap[i].data_data = mask;
107842354Smckusick /*
107942354Smckusick * Don't slow down tandem mode, interrupt on flow control
108042354Smckusick * chars for any port on the board.
108142354Smckusick */
108242354Smckusick if (!perchar) {
108342354Smckusick register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)];
108442354Smckusick int c;
108542354Smckusick
108642354Smckusick for (i = 0; i < 4; i++, tp++) {
108742354Smckusick if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
108842354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i);
108942354Smckusick if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
109042354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i);
109141480Smckusick }
109241480Smckusick }
109342354Smckusick /*
109442354Smckusick * Board starts with timer disabled so if first call is to
109542354Smckusick * set perchar mode then we don't want to toggle the timer.
109642354Smckusick */
109742354Smckusick if (flags == (DIS_RESET|DIS_PERCHAR))
109841480Smckusick return;
109942354Smckusick /*
110042354Smckusick * Toggle card 16.7ms interrupts (we first make sure that card
110142354Smckusick * has cleared the bit so it will see the toggle).
110242354Smckusick */
110342354Smckusick while (dcm->dcm_cr & CR_TIMER)
110442354Smckusick ;
110541480Smckusick SEM_LOCK(dcm);
110642354Smckusick dcm->dcm_cr |= CR_TIMER;
110741480Smckusick SEM_UNLOCK(dcm);
110841480Smckusick }
110941480Smckusick
111041480Smckusick /*
111141480Smckusick * Following are all routines needed for DCM to act as console
111241480Smckusick */
111356507Sbostic #include <hp/dev/cons.h>
111441480Smckusick
111542354Smckusick dcmcnprobe(cp)
111642354Smckusick struct consdev *cp;
111741480Smckusick {
111842354Smckusick register struct hp_hw *hw;
111949130Skarels int unit;
112041480Smckusick
112149130Skarels /* locate the major number */
112249130Skarels for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)
112349130Skarels if (cdevsw[dcmmajor].d_open == dcmopen)
112449130Skarels break;
112549130Skarels
112642354Smckusick /*
112742354Smckusick * Implicitly assigns the lowest select code DCM card found to be
112842354Smckusick * logical unit 0 (actually CONUNIT). If your config file does
112942354Smckusick * anything different, you're screwed.
113042354Smckusick */
113142354Smckusick for (hw = sc_table; hw->hw_type; hw++)
113249301Shibler if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva))
113342354Smckusick break;
113449301Shibler if (!HW_ISDEV(hw, D_COMMDCM)) {
113542354Smckusick cp->cn_pri = CN_DEAD;
113642354Smckusick return;
113742354Smckusick }
113842354Smckusick unit = CONUNIT;
113949301Shibler dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva;
114041480Smckusick
114142354Smckusick /* initialize required fields */
114249130Skarels cp->cn_dev = makedev(dcmmajor, unit);
114342354Smckusick cp->cn_tp = &dcm_tty[unit];
114442354Smckusick switch (dcm_addr[BOARD(unit)]->dcm_rsid) {
114542354Smckusick case DCMID:
114642354Smckusick cp->cn_pri = CN_NORMAL;
114742354Smckusick break;
114842354Smckusick case DCMID|DCMCON:
114942354Smckusick cp->cn_pri = CN_REMOTE;
115042354Smckusick break;
115142354Smckusick default:
115242354Smckusick cp->cn_pri = CN_DEAD;
115349130Skarels return;
115442354Smckusick }
115549130Skarels /*
115649130Skarels * If dcmconsole is initialized, raise our priority.
115749130Skarels */
115849130Skarels if (dcmconsole == UNIT(unit))
115949130Skarels cp->cn_pri = CN_REMOTE;
116049301Shibler #ifdef KGDB_CHEAT
116149130Skarels /*
116249130Skarels * This doesn't currently work, at least not with ite consoles;
116349130Skarels * the console hasn't been initialized yet.
116449130Skarels */
116549130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) {
116649130Skarels (void) dcminit(kgdb_dev, kgdb_rate);
116749130Skarels if (kgdb_debug_init) {
116849130Skarels /*
116949130Skarels * We assume that console is ready for us...
117049130Skarels * this assumes that a dca or ite console
117149130Skarels * has been selected already and will init
117249130Skarels * on the first putc.
117349130Skarels */
117449130Skarels printf("dcm%d: ", UNIT(kgdb_dev));
117549130Skarels kgdb_connect(1);
117649130Skarels }
117749130Skarels }
117849130Skarels #endif
117942354Smckusick }
118042354Smckusick
118142354Smckusick dcmcninit(cp)
118242354Smckusick struct consdev *cp;
118342354Smckusick {
118442354Smckusick dcminit(cp->cn_dev, dcmdefaultrate);
118549130Skarels dcmconsinit = 1;
118642354Smckusick dcmconsole = UNIT(cp->cn_dev);
118742354Smckusick }
118842354Smckusick
dcminit(dev,rate)118942354Smckusick dcminit(dev, rate)
119042354Smckusick dev_t dev;
119142354Smckusick int rate;
119242354Smckusick {
119342354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
119442354Smckusick int s, mode, port;
119542354Smckusick
119642354Smckusick port = PORT(dev);
119742354Smckusick mode = LC_8BITS | LC_1STOP;
119841480Smckusick s = splhigh();
119942354Smckusick /*
120042354Smckusick * Wait for transmitter buffer to empty.
120142354Smckusick */
120242354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
120342354Smckusick DELAY(DCM_USPERCH(rate));
120442354Smckusick /*
120542354Smckusick * Make changes known to hardware.
120642354Smckusick */
120742354Smckusick dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
120842354Smckusick dcm->dcm_data[port].dcm_conf = mode;
120942354Smckusick SEM_LOCK(dcm);
121042354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
121142354Smckusick dcm->dcm_cr |= (1 << port);
121242354Smckusick SEM_UNLOCK(dcm);
121342354Smckusick /*
121449130Skarels * Delay for config change to take place. Weighted by baud.
121542354Smckusick * XXX why do we do this?
121642354Smckusick */
121742354Smckusick DELAY(16 * DCM_USPERCH(rate));
121841480Smckusick splx(s);
121941480Smckusick }
122041480Smckusick
dcmcngetc(dev)122141480Smckusick dcmcngetc(dev)
122242354Smckusick dev_t dev;
122341480Smckusick {
122442354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
122542354Smckusick register struct dcmrfifo *fifo;
122642354Smckusick register struct dcmpreg *pp;
122742354Smckusick register unsigned head;
122842354Smckusick int s, c, stat, port;
122942354Smckusick
123042354Smckusick port = PORT(dev);
123142354Smckusick pp = dcm_preg(dcm, port);
123242354Smckusick s = splhigh();
123342354Smckusick head = pp->r_head & RX_MASK;
123442354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1];
123542354Smckusick while (head == (pp->r_tail & RX_MASK))
123642354Smckusick ;
123742354Smckusick /*
123842354Smckusick * If board interrupts are enabled, just let our received char
123942354Smckusick * interrupt through in case some other port on the board was
124042354Smckusick * busy. Otherwise we must clear the interrupt.
124142354Smckusick */
124242354Smckusick SEM_LOCK(dcm);
124342354Smckusick if ((dcm->dcm_ic & IC_IE) == 0)
124442354Smckusick stat = dcm->dcm_iir;
124542354Smckusick SEM_UNLOCK(dcm);
124642354Smckusick c = fifo->data_char;
124742354Smckusick stat = fifo->data_stat;
124842354Smckusick pp->r_head = (head + 2) & RX_MASK;
124942354Smckusick splx(s);
125050220Skarels return (c);
125141480Smckusick }
125241480Smckusick
125341480Smckusick /*
125441480Smckusick * Console kernel output character routine.
125541480Smckusick */
dcmcnputc(dev,c)125641480Smckusick dcmcnputc(dev, c)
125741480Smckusick dev_t dev;
125842354Smckusick int c;
125941480Smckusick {
126041480Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
126142354Smckusick register struct dcmpreg *pp;
126242354Smckusick unsigned tail;
126342354Smckusick int s, port, stat;
126441480Smckusick
126542354Smckusick port = PORT(dev);
126642354Smckusick pp = dcm_preg(dcm, port);
126742354Smckusick s = splhigh();
126842354Smckusick #ifdef KGDB
126942354Smckusick if (dev != kgdb_dev)
127042354Smckusick #endif
127149130Skarels if (dcmconsinit == 0) {
127242354Smckusick (void) dcminit(dev, dcmdefaultrate);
127349130Skarels dcmconsinit = 1;
127442354Smckusick }
127542354Smckusick tail = pp->t_tail & TX_MASK;
127642354Smckusick while (tail != (pp->t_head & TX_MASK))
127742354Smckusick ;
127842354Smckusick dcm->dcm_tfifos[3-port][tail].data_char = c;
127942354Smckusick pp->t_tail = tail = (tail + 1) & TX_MASK;
128041480Smckusick SEM_LOCK(dcm);
128142354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
128242354Smckusick dcm->dcm_cr |= (1 << port);
128341480Smckusick SEM_UNLOCK(dcm);
128442354Smckusick while (tail != (pp->t_head & TX_MASK))
128542354Smckusick ;
128642354Smckusick /*
128742354Smckusick * If board interrupts are enabled, just let our completion
128842354Smckusick * interrupt through in case some other port on the board
128942354Smckusick * was busy. Otherwise we must clear the interrupt.
129042354Smckusick */
129142354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) {
129242354Smckusick SEM_LOCK(dcm);
129342354Smckusick stat = dcm->dcm_iir;
129442354Smckusick SEM_UNLOCK(dcm);
129542354Smckusick }
129641480Smckusick splx(s);
129741480Smckusick }
129841480Smckusick #endif
1299