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*65634Sbostic * @(#)dcm.c 8.3 (Berkeley) 01/12/94 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 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__ 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*/ 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 40241480Smckusick dcmread(dev, uio, flag) 40341480Smckusick dev_t dev; 40441480Smckusick struct uio *uio; 405*65634Sbostic 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 41341480Smckusick dcmwrite(dev, uio, flag) 41441480Smckusick dev_t dev; 41541480Smckusick struct uio *uio; 416*65634Sbostic 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 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 */ 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 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 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 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 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 70052422Smckusick dcmioctl(dev, cmd, data, flag, p) 70141480Smckusick dev_t dev; 70252422Smckusick int 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 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 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 */ 97741480Smckusick dcmstop(tp, flag) 97841480Smckusick register struct tty *tp; 97941480Smckusick { 98041480Smckusick int s; 98141480Smckusick 98241480Smckusick s = spltty(); 98341480Smckusick if (tp->t_state & TS_BUSY) { 98442354Smckusick /* XXX is there some way to safely stop transmission? */ 98544317Shibler if ((tp->t_state&TS_TTSTOP) == 0) 98641480Smckusick tp->t_state |= TS_FLUSH; 98741480Smckusick } 98841480Smckusick splx(s); 98941480Smckusick } 99041480Smckusick 99145750Smckusick /* 99245750Smckusick * Modem control 99345750Smckusick */ 99441480Smckusick dcmmctl(dev, bits, how) 99541480Smckusick dev_t dev; 99641480Smckusick int bits, how; 99741480Smckusick { 99841480Smckusick register struct dcmdevice *dcm; 99950220Skarels int s, unit, brd, hit = 0; 100041480Smckusick 100145750Smckusick unit = UNIT(dev); 100245750Smckusick #ifdef DEBUG 100345750Smckusick if (dcmdebug & DDB_MODEM) 100445750Smckusick printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", 100545750Smckusick BOARD(unit), unit, bits, how); 100645750Smckusick #endif 100741480Smckusick 100850220Skarels brd = BOARD(unit); 100950220Skarels dcm = dcm_addr[brd]; 101041480Smckusick s = spltty(); 101141480Smckusick switch (how) { 101241480Smckusick 101341480Smckusick case DMSET: 101445750Smckusick dcm_modem[unit]->mdmout = bits; 101541480Smckusick hit++; 101641480Smckusick break; 101741480Smckusick 101841480Smckusick case DMBIS: 101945750Smckusick dcm_modem[unit]->mdmout |= bits; 102041480Smckusick hit++; 102141480Smckusick break; 102241480Smckusick 102341480Smckusick case DMBIC: 102445750Smckusick dcm_modem[unit]->mdmout &= ~bits; 102541480Smckusick hit++; 102641480Smckusick break; 102741480Smckusick 102841480Smckusick case DMGET: 102945750Smckusick bits = dcm_modem[unit]->mdmin; 103050220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE) 103150220Skarels bits = hp2dce_in(bits); 103241480Smckusick break; 103341480Smckusick } 103441480Smckusick if (hit) { 103541480Smckusick SEM_LOCK(dcm); 103645750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 103741480Smckusick dcm->dcm_cr |= CR_MODM; 103841480Smckusick SEM_UNLOCK(dcm); 103942354Smckusick DELAY(10); /* delay until done */ 104041480Smckusick (void) splx(s); 104141480Smckusick } 104250220Skarels return (bits); 104341480Smckusick } 104441480Smckusick 104542354Smckusick /* 104642354Smckusick * Set board to either interrupt per-character or at a fixed interval. 104742354Smckusick */ 104842354Smckusick dcmsetischeme(brd, flags) 104942354Smckusick int brd, flags; 105041480Smckusick { 105142354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 105242354Smckusick register struct dcmischeme *dis = &dcmischeme[brd]; 105341480Smckusick register int i; 105442354Smckusick u_char mask; 105542354Smckusick int perchar = flags & DIS_PERCHAR; 105641480Smckusick 105741480Smckusick #ifdef DEBUG 105842354Smckusick if (dcmdebug & DDB_INTSCHM) 105942354Smckusick printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", 106042354Smckusick brd, perchar, dis->dis_perchar, 106142354Smckusick dis->dis_intr, dis->dis_char); 106242354Smckusick if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { 106342354Smckusick printf("dcmsetischeme(%d): redundent request %d\n", 106442354Smckusick brd, perchar); 106542354Smckusick return; 106642354Smckusick } 106742354Smckusick #endif 106842354Smckusick /* 106942354Smckusick * If perchar is non-zero, we enable interrupts on all characters 107042354Smckusick * otherwise we disable perchar interrupts and use periodic 107142354Smckusick * polling interrupts. 107242354Smckusick */ 107342354Smckusick dis->dis_perchar = perchar; 107442354Smckusick mask = perchar ? 0xf : 0x0; 107542354Smckusick for (i = 0; i < 256; i++) 107642354Smckusick dcm->dcm_bmap[i].data_data = mask; 107742354Smckusick /* 107842354Smckusick * Don't slow down tandem mode, interrupt on flow control 107942354Smckusick * chars for any port on the board. 108042354Smckusick */ 108142354Smckusick if (!perchar) { 108242354Smckusick register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)]; 108342354Smckusick int c; 108442354Smckusick 108542354Smckusick for (i = 0; i < 4; i++, tp++) { 108642354Smckusick if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) 108742354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 108842354Smckusick if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) 108942354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 109041480Smckusick } 109141480Smckusick } 109242354Smckusick /* 109342354Smckusick * Board starts with timer disabled so if first call is to 109442354Smckusick * set perchar mode then we don't want to toggle the timer. 109542354Smckusick */ 109642354Smckusick if (flags == (DIS_RESET|DIS_PERCHAR)) 109741480Smckusick return; 109842354Smckusick /* 109942354Smckusick * Toggle card 16.7ms interrupts (we first make sure that card 110042354Smckusick * has cleared the bit so it will see the toggle). 110142354Smckusick */ 110242354Smckusick while (dcm->dcm_cr & CR_TIMER) 110342354Smckusick ; 110441480Smckusick SEM_LOCK(dcm); 110542354Smckusick dcm->dcm_cr |= CR_TIMER; 110641480Smckusick SEM_UNLOCK(dcm); 110741480Smckusick } 110841480Smckusick 110941480Smckusick /* 111041480Smckusick * Following are all routines needed for DCM to act as console 111141480Smckusick */ 111256507Sbostic #include <hp/dev/cons.h> 111341480Smckusick 111442354Smckusick dcmcnprobe(cp) 111542354Smckusick struct consdev *cp; 111641480Smckusick { 111742354Smckusick register struct hp_hw *hw; 111849130Skarels int unit; 111941480Smckusick 112049130Skarels /* locate the major number */ 112149130Skarels for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) 112249130Skarels if (cdevsw[dcmmajor].d_open == dcmopen) 112349130Skarels break; 112449130Skarels 112542354Smckusick /* 112642354Smckusick * Implicitly assigns the lowest select code DCM card found to be 112742354Smckusick * logical unit 0 (actually CONUNIT). If your config file does 112842354Smckusick * anything different, you're screwed. 112942354Smckusick */ 113042354Smckusick for (hw = sc_table; hw->hw_type; hw++) 113149301Shibler if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva)) 113242354Smckusick break; 113349301Shibler if (!HW_ISDEV(hw, D_COMMDCM)) { 113442354Smckusick cp->cn_pri = CN_DEAD; 113542354Smckusick return; 113642354Smckusick } 113742354Smckusick unit = CONUNIT; 113849301Shibler dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva; 113941480Smckusick 114042354Smckusick /* initialize required fields */ 114149130Skarels cp->cn_dev = makedev(dcmmajor, unit); 114242354Smckusick cp->cn_tp = &dcm_tty[unit]; 114342354Smckusick switch (dcm_addr[BOARD(unit)]->dcm_rsid) { 114442354Smckusick case DCMID: 114542354Smckusick cp->cn_pri = CN_NORMAL; 114642354Smckusick break; 114742354Smckusick case DCMID|DCMCON: 114842354Smckusick cp->cn_pri = CN_REMOTE; 114942354Smckusick break; 115042354Smckusick default: 115142354Smckusick cp->cn_pri = CN_DEAD; 115249130Skarels return; 115342354Smckusick } 115449130Skarels /* 115549130Skarels * If dcmconsole is initialized, raise our priority. 115649130Skarels */ 115749130Skarels if (dcmconsole == UNIT(unit)) 115849130Skarels cp->cn_pri = CN_REMOTE; 115949301Shibler #ifdef KGDB_CHEAT 116049130Skarels /* 116149130Skarels * This doesn't currently work, at least not with ite consoles; 116249130Skarels * the console hasn't been initialized yet. 116349130Skarels */ 116449130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { 116549130Skarels (void) dcminit(kgdb_dev, kgdb_rate); 116649130Skarels if (kgdb_debug_init) { 116749130Skarels /* 116849130Skarels * We assume that console is ready for us... 116949130Skarels * this assumes that a dca or ite console 117049130Skarels * has been selected already and will init 117149130Skarels * on the first putc. 117249130Skarels */ 117349130Skarels printf("dcm%d: ", UNIT(kgdb_dev)); 117449130Skarels kgdb_connect(1); 117549130Skarels } 117649130Skarels } 117749130Skarels #endif 117842354Smckusick } 117942354Smckusick 118042354Smckusick dcmcninit(cp) 118142354Smckusick struct consdev *cp; 118242354Smckusick { 118342354Smckusick dcminit(cp->cn_dev, dcmdefaultrate); 118449130Skarels dcmconsinit = 1; 118542354Smckusick dcmconsole = UNIT(cp->cn_dev); 118642354Smckusick } 118742354Smckusick 118842354Smckusick dcminit(dev, rate) 118942354Smckusick dev_t dev; 119042354Smckusick int rate; 119142354Smckusick { 119242354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 119342354Smckusick int s, mode, port; 119442354Smckusick 119542354Smckusick port = PORT(dev); 119642354Smckusick mode = LC_8BITS | LC_1STOP; 119741480Smckusick s = splhigh(); 119842354Smckusick /* 119942354Smckusick * Wait for transmitter buffer to empty. 120042354Smckusick */ 120142354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 120242354Smckusick DELAY(DCM_USPERCH(rate)); 120342354Smckusick /* 120442354Smckusick * Make changes known to hardware. 120542354Smckusick */ 120642354Smckusick dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); 120742354Smckusick dcm->dcm_data[port].dcm_conf = mode; 120842354Smckusick SEM_LOCK(dcm); 120942354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 121042354Smckusick dcm->dcm_cr |= (1 << port); 121142354Smckusick SEM_UNLOCK(dcm); 121242354Smckusick /* 121349130Skarels * Delay for config change to take place. Weighted by baud. 121442354Smckusick * XXX why do we do this? 121542354Smckusick */ 121642354Smckusick DELAY(16 * DCM_USPERCH(rate)); 121741480Smckusick splx(s); 121841480Smckusick } 121941480Smckusick 122041480Smckusick dcmcngetc(dev) 122142354Smckusick dev_t dev; 122241480Smckusick { 122342354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 122442354Smckusick register struct dcmrfifo *fifo; 122542354Smckusick register struct dcmpreg *pp; 122642354Smckusick register unsigned head; 122742354Smckusick int s, c, stat, port; 122842354Smckusick 122942354Smckusick port = PORT(dev); 123042354Smckusick pp = dcm_preg(dcm, port); 123142354Smckusick s = splhigh(); 123242354Smckusick head = pp->r_head & RX_MASK; 123342354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 123442354Smckusick while (head == (pp->r_tail & RX_MASK)) 123542354Smckusick ; 123642354Smckusick /* 123742354Smckusick * If board interrupts are enabled, just let our received char 123842354Smckusick * interrupt through in case some other port on the board was 123942354Smckusick * busy. Otherwise we must clear the interrupt. 124042354Smckusick */ 124142354Smckusick SEM_LOCK(dcm); 124242354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) 124342354Smckusick stat = dcm->dcm_iir; 124442354Smckusick SEM_UNLOCK(dcm); 124542354Smckusick c = fifo->data_char; 124642354Smckusick stat = fifo->data_stat; 124742354Smckusick pp->r_head = (head + 2) & RX_MASK; 124842354Smckusick splx(s); 124950220Skarels return (c); 125041480Smckusick } 125141480Smckusick 125241480Smckusick /* 125341480Smckusick * Console kernel output character routine. 125441480Smckusick */ 125541480Smckusick dcmcnputc(dev, c) 125641480Smckusick dev_t dev; 125742354Smckusick int c; 125841480Smckusick { 125941480Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 126042354Smckusick register struct dcmpreg *pp; 126142354Smckusick unsigned tail; 126242354Smckusick int s, port, stat; 126341480Smckusick 126442354Smckusick port = PORT(dev); 126542354Smckusick pp = dcm_preg(dcm, port); 126642354Smckusick s = splhigh(); 126742354Smckusick #ifdef KGDB 126842354Smckusick if (dev != kgdb_dev) 126942354Smckusick #endif 127049130Skarels if (dcmconsinit == 0) { 127142354Smckusick (void) dcminit(dev, dcmdefaultrate); 127249130Skarels dcmconsinit = 1; 127342354Smckusick } 127442354Smckusick tail = pp->t_tail & TX_MASK; 127542354Smckusick while (tail != (pp->t_head & TX_MASK)) 127642354Smckusick ; 127742354Smckusick dcm->dcm_tfifos[3-port][tail].data_char = c; 127842354Smckusick pp->t_tail = tail = (tail + 1) & TX_MASK; 127941480Smckusick SEM_LOCK(dcm); 128042354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 128142354Smckusick dcm->dcm_cr |= (1 << port); 128241480Smckusick SEM_UNLOCK(dcm); 128342354Smckusick while (tail != (pp->t_head & TX_MASK)) 128442354Smckusick ; 128542354Smckusick /* 128642354Smckusick * If board interrupts are enabled, just let our completion 128742354Smckusick * interrupt through in case some other port on the board 128842354Smckusick * was busy. Otherwise we must clear the interrupt. 128942354Smckusick */ 129042354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) { 129142354Smckusick SEM_LOCK(dcm); 129242354Smckusick stat = dcm->dcm_iir; 129342354Smckusick SEM_UNLOCK(dcm); 129442354Smckusick } 129541480Smckusick splx(s); 129641480Smckusick } 129741480Smckusick #endif 1298