141480Smckusick /* 241480Smckusick * Copyright (c) 1988 University of Utah. 341480Smckusick * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 441480Smckusick * 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 * 1249301Shibler * from: $Hdr: dcm.c 1.26 91/01/21$ 1341480Smckusick * 14*50220Skarels * @(#)dcm.c 7.14 (Berkeley) 06/27/91 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 */ 2845788Sbostic #include "sys/param.h" 2945788Sbostic #include "sys/systm.h" 3045788Sbostic #include "sys/ioctl.h" 3145788Sbostic #include "sys/tty.h" 3249130Skarels #include "sys/proc.h" 3345788Sbostic #include "sys/conf.h" 3445788Sbostic #include "sys/file.h" 3545788Sbostic #include "sys/uio.h" 3645788Sbostic #include "sys/kernel.h" 3745788Sbostic #include "sys/syslog.h" 3845788Sbostic #include "sys/time.h" 3941480Smckusick 4041480Smckusick #include "device.h" 4141480Smckusick #include "dcmreg.h" 4249130Skarels #include "machine/cpu.h" 4345788Sbostic #include "../hp300/isr.h" 4441480Smckusick 4542354Smckusick #ifndef DEFAULT_BAUD_RATE 4642354Smckusick #define DEFAULT_BAUD_RATE 9600 4742354Smckusick #endif 4842354Smckusick 4942354Smckusick int ttrstrt(); 5042354Smckusick int dcmprobe(), dcmstart(), dcmintr(), dcmparam(); 5142354Smckusick 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 92*50220Skarels * (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 */ 12549130Skarels #include "machine/remote-sl.h" 12649130Skarels 127*50220Skarels extern dev_t kgdb_dev; 12842354Smckusick extern int kgdb_rate; 12942354Smckusick extern int kgdb_debug_init; 13042354Smckusick #endif 13142354Smckusick 13242354Smckusick /* #define IOSTATS */ 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 14742354Smckusick #ifdef IOSTATS 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 168*50220Skarels /* 169*50220Skarels * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux, 170*50220Skarels * the distribution panel uses "HP DCE" conventions. If requested via 171*50220Skarels * the device flags, we swap the inputs to something closer to normal DCE, 172*50220Skarels * allowing a straight-through cable to a DTE or a reversed cable 173*50220Skarels * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected; 174*50220Skarels * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect 175*50220Skarels * DSR or make RTS work, though). The following gives the full 176*50220Skarels * details of a cable from this mux panel to a modem: 177*50220Skarels * 178*50220Skarels * HP modem 179*50220Skarels * name pin pin name 180*50220Skarels * HP inputs: 181*50220Skarels * "Rx" 2 3 Tx 182*50220Skarels * CTS 4 5 CTS (only needed for CCTS_OFLOW) 183*50220Skarels * DCD 20 8 DCD 184*50220Skarels * "DSR" 9 6 DSR (unneeded) 185*50220Skarels * RI 22 22 RI (unneeded) 186*50220Skarels * 187*50220Skarels * HP outputs: 188*50220Skarels * "Tx" 3 2 Rx 189*50220Skarels * "DTR" 6 not connected 190*50220Skarels * "RTS" 8 20 DTR 191*50220Skarels * "SR" 23 4 RTS (often not needed) 192*50220Skarels */ 193*50220Skarels #define FLAG_STDDCE 0x10 /* map inputs if this bit is set in flags */ 194*50220Skarels #define hp2dce_in(ibits) (iconv[(ibits) & 0xf]) 195*50220Skarels static char iconv[16] = { 196*50220Skarels 0, MI_DM, MI_CTS, MI_CTS|MI_DM, 197*50220Skarels MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM, 198*50220Skarels MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM, 199*50220Skarels MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS, 200*50220Skarels MI_RI|MI_CD|MI_CTS|MI_DM 201*50220Skarels }; 202*50220Skarels 20341480Smckusick dcmprobe(hd) 20441480Smckusick register struct hp_device *hd; 20541480Smckusick { 20641480Smckusick register struct dcmdevice *dcm; 20741480Smckusick register int i; 20841480Smckusick register int timo = 0; 209*50220Skarels 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)]) 223*50220Skarels 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) 236*50220Skarels return (0); 23741480Smckusick DELAY(50000) /* XXX why is this needed ???? */ 23842354Smckusick while ((dcm->dcm_iir & IIR_SELFT) == 0) 23942354Smckusick if (++timo == 400000) 240*50220Skarels 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); 246*50220Skarels 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)) 262*50220Skarels 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 */ 291*50220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE) 292*50220Skarels mbits = hp2dce_in(MI_CD|MI_CTS); 293*50220Skarels else 294*50220Skarels mbits = MI_CD|MI_CTS; 29545750Smckusick for (i = 0; i < 4; i++) 296*50220Skarels 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; 322*50220Skarels 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); 346*50220Skarels mbits = MO_ON; 347*50220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE) 348*50220Skarels mbits |= MO_SR; /* pin 23, could be used as RTS */ 349*50220Skarels (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 && 360*50220Skarels (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); 390*50220Skarels if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 391*50220Skarels (tp->t_state&TS_ISOPEN) == 0) 392*50220Skarels (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); 399*50220Skarels return (0); 40041480Smckusick } 40141480Smckusick 40241480Smckusick dcmread(dev, uio, flag) 40341480Smckusick dev_t dev; 40441480Smckusick struct uio *uio; 40541480Smckusick { 40641480Smckusick register struct tty *tp; 40741480Smckusick 40841480Smckusick tp = &dcm_tty[UNIT(dev)]; 40941480Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 41041480Smckusick } 41141480Smckusick 41241480Smckusick dcmwrite(dev, uio, flag) 41341480Smckusick dev_t dev; 41441480Smckusick struct uio *uio; 41541480Smckusick { 41641480Smckusick int unit = UNIT(dev); 41741480Smckusick register struct tty *tp; 41841480Smckusick 41941480Smckusick tp = &dcm_tty[unit]; 42042354Smckusick /* 42142354Smckusick * XXX we disallow virtual consoles if the physical console is 42242354Smckusick * a serial port. This is in case there is a display attached that 42342354Smckusick * is not the console. In that situation we don't need/want the X 42442354Smckusick * server taking over the console. 42542354Smckusick */ 42642354Smckusick if (constty && unit == dcmconsole) 42742354Smckusick constty = NULL; 42841480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 42941480Smckusick } 43041480Smckusick 43141480Smckusick dcmintr(brd) 43241480Smckusick register int brd; 43341480Smckusick { 43442354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 43542354Smckusick register struct dcmischeme *dis; 43645750Smckusick register int unit = MKUNIT(brd, 0); 43745750Smckusick register int code, i; 43845750Smckusick int pcnd[4], mcode, mcnd[4]; 43941480Smckusick 44042354Smckusick /* 44142354Smckusick * Do all guarded register accesses right off to minimize 44242354Smckusick * block out of hardware. 44342354Smckusick */ 44441480Smckusick SEM_LOCK(dcm); 44541480Smckusick if ((dcm->dcm_ic & IC_IR) == 0) { 44641480Smckusick SEM_UNLOCK(dcm); 447*50220Skarels return (0); 44841480Smckusick } 44941480Smckusick for (i = 0; i < 4; i++) { 45041480Smckusick pcnd[i] = dcm->dcm_icrtab[i].dcm_data; 45141480Smckusick dcm->dcm_icrtab[i].dcm_data = 0; 452*50220Skarels code = dcm_modem[unit+i]->mdmin; 453*50220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE) 454*50220Skarels code = hp2dce_in(code); 455*50220Skarels mcnd[i] = code; 45641480Smckusick } 45741480Smckusick code = dcm->dcm_iir & IIR_MASK; 45842354Smckusick dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ 45945750Smckusick mcode = dcm->dcm_modemintr; 46045750Smckusick dcm->dcm_modemintr = 0; 46141480Smckusick SEM_UNLOCK(dcm); 46241480Smckusick 46341480Smckusick #ifdef DEBUG 46445750Smckusick if (dcmdebug & DDB_INTR) { 46545750Smckusick printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ", 46645750Smckusick brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); 46745750Smckusick printf("miir %x mc %x/%x/%x/%x\n", 46845750Smckusick mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); 46945750Smckusick } 47041480Smckusick #endif 47142354Smckusick if (code & IIR_TIMEO) 47242354Smckusick dcmrint(brd, dcm); 47341480Smckusick if (code & IIR_PORT0) 47445750Smckusick dcmpint(unit+0, pcnd[0], dcm); 47541480Smckusick if (code & IIR_PORT1) 47645750Smckusick dcmpint(unit+1, pcnd[1], dcm); 47741480Smckusick if (code & IIR_PORT2) 47845750Smckusick dcmpint(unit+2, pcnd[2], dcm); 47941480Smckusick if (code & IIR_PORT3) 48045750Smckusick dcmpint(unit+3, pcnd[3], dcm); 48145750Smckusick if (code & IIR_MODM) { 48245750Smckusick if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ 48345750Smckusick dcmmint(unit+0, mcnd[0], dcm); 48445750Smckusick if (mcode & 0x2) 48545750Smckusick dcmmint(unit+1, mcnd[1], dcm); 48645750Smckusick if (mcode & 0x4) 48745750Smckusick dcmmint(unit+2, mcnd[2], dcm); 48845750Smckusick if (mcode & 0x8) 48945750Smckusick dcmmint(unit+3, mcnd[3], dcm); 49045750Smckusick } 49141480Smckusick 49242354Smckusick dis = &dcmischeme[brd]; 49341480Smckusick /* 49442354Smckusick * Chalk up a receiver interrupt if the timer running or one of 49542354Smckusick * the ports reports a special character interrupt. 49641480Smckusick */ 49742354Smckusick if ((code & IIR_TIMEO) || 49842354Smckusick ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) 49942354Smckusick dis->dis_intr++; 50042354Smckusick /* 50142354Smckusick * See if it is time to check/change the interrupt rate. 50242354Smckusick */ 50342354Smckusick if (dcmistype < 0 && 50445750Smckusick (i = time.tv_sec - dis->dis_time) >= dcminterval) { 50541480Smckusick /* 50642354Smckusick * If currently per-character and averaged over 70 interrupts 50742354Smckusick * per-second (66 is threshold of 600 baud) in last interval, 50842354Smckusick * switch to timer mode. 50942354Smckusick * 51042354Smckusick * XXX decay counts ala load average to avoid spikes? 51141480Smckusick */ 51245750Smckusick if (dis->dis_perchar && dis->dis_intr > 70 * i) 51342354Smckusick dcmsetischeme(brd, DIS_TIMER); 51442354Smckusick /* 51542354Smckusick * If currently using timer and had more interrupts than 51642354Smckusick * received characters in the last interval, switch back 51742354Smckusick * to per-character. Note that after changing to per-char 51842354Smckusick * we must process any characters already in the queue 51942354Smckusick * since they may have arrived before the bitmap was setup. 52042354Smckusick * 52142354Smckusick * XXX decay counts? 52242354Smckusick */ 52342354Smckusick else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { 52442354Smckusick dcmsetischeme(brd, DIS_PERCHAR); 52541480Smckusick dcmrint(brd, dcm); 52641480Smckusick } 52742354Smckusick dis->dis_intr = dis->dis_char = 0; 52842354Smckusick dis->dis_time = time.tv_sec; 52942354Smckusick } 530*50220Skarels return (1); 53141480Smckusick } 53241480Smckusick 53341480Smckusick /* 53441480Smckusick * Port interrupt. Can be two things: 53541480Smckusick * First, it might be a special character (exception interrupt); 53641480Smckusick * Second, it may be a buffer empty (transmit interrupt); 53741480Smckusick */ 53841480Smckusick dcmpint(unit, code, dcm) 53941480Smckusick int unit, code; 54042354Smckusick struct dcmdevice *dcm; 54141480Smckusick { 54242354Smckusick struct tty *tp = &dcm_tty[unit]; 54341480Smckusick 54442354Smckusick if (code & IT_SPEC) 54542354Smckusick dcmreadbuf(unit, dcm, tp); 54641480Smckusick if (code & IT_TX) 54742354Smckusick dcmxint(unit, dcm, tp); 54841480Smckusick } 54941480Smckusick 55041480Smckusick dcmrint(brd, dcm) 55141480Smckusick int brd; 55241480Smckusick register struct dcmdevice *dcm; 55341480Smckusick { 55442354Smckusick register int i, unit; 55541480Smckusick register struct tty *tp; 55641480Smckusick 55741480Smckusick unit = MKUNIT(brd, 0); 55841480Smckusick tp = &dcm_tty[unit]; 55942354Smckusick for (i = 0; i < 4; i++, tp++, unit++) 56042354Smckusick dcmreadbuf(unit, dcm, tp); 56141480Smckusick } 56241480Smckusick 56342354Smckusick dcmreadbuf(unit, dcm, tp) 56441480Smckusick int unit; 56541480Smckusick register struct dcmdevice *dcm; 56641480Smckusick register struct tty *tp; 56741480Smckusick { 56842354Smckusick int port = PORT(unit); 56942354Smckusick register struct dcmpreg *pp = dcm_preg(dcm, port); 57042354Smckusick register struct dcmrfifo *fifo; 57141480Smckusick register int c, stat; 57241480Smckusick register unsigned head; 57342354Smckusick int nch = 0; 57442354Smckusick #ifdef IOSTATS 57542354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(unit)]; 57641480Smckusick 57742354Smckusick dsp->rints++; 57842354Smckusick #endif 57943407Shibler if ((tp->t_state & TS_ISOPEN) == 0) { 58042354Smckusick #ifdef KGDB 58149130Skarels if ((makedev(dcmmajor, unit) == kgdb_dev) && 58242354Smckusick (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && 58349130Skarels dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_END) { 58442354Smckusick pp->r_head = (head + 2) & RX_MASK; 58549130Skarels kgdb_connect(0); /* trap into kgdb */ 58642354Smckusick return; 58742354Smckusick } 58849130Skarels #endif /* KGDB */ 58942354Smckusick pp->r_head = pp->r_tail & RX_MASK; 59042354Smckusick return; 59142354Smckusick } 59241480Smckusick 59342354Smckusick head = pp->r_head & RX_MASK; 59442354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 59542354Smckusick /* 59642354Smckusick * XXX upper bound on how many chars we will take in one swallow? 59742354Smckusick */ 59842354Smckusick while (head != (pp->r_tail & RX_MASK)) { 59942354Smckusick /* 60042354Smckusick * Get character/status and update head pointer as fast 60142354Smckusick * as possible to make room for more characters. 60242354Smckusick */ 60342354Smckusick c = fifo->data_char; 60442354Smckusick stat = fifo->data_stat; 60541480Smckusick head = (head + 2) & RX_MASK; 60642354Smckusick pp->r_head = head; 60742354Smckusick fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; 60842354Smckusick nch++; 60941480Smckusick 61041480Smckusick #ifdef DEBUG 61141480Smckusick if (dcmdebug & DDB_INPUT) 61242354Smckusick printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n", 61342354Smckusick unit, c&0xFF, c, stat&0xFF, 61442354Smckusick tp->t_flags, head, pp->r_tail); 61541480Smckusick #endif 61642354Smckusick /* 61742354Smckusick * Check for and handle errors 61842354Smckusick */ 61942354Smckusick if (stat & RD_MASK) { 62041480Smckusick #ifdef DEBUG 62142354Smckusick if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) 62242354Smckusick printf("dcmreadbuf(%d): err: c%x('%c') s%x\n", 62342354Smckusick unit, stat, c&0xFF, c); 62441480Smckusick #endif 62541480Smckusick if (stat & (RD_BD | RD_FE)) 62641480Smckusick c |= TTY_FE; 62741480Smckusick else if (stat & RD_PE) 62841480Smckusick c |= TTY_PE; 62941480Smckusick else if (stat & RD_OVF) 63041480Smckusick log(LOG_WARNING, 63142354Smckusick "dcm%d: silo overflow\n", unit); 63241480Smckusick else if (stat & RD_OE) 63341480Smckusick log(LOG_WARNING, 63442354Smckusick "dcm%d: uart overflow\n", unit); 63541480Smckusick } 63641480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 63741480Smckusick } 63842354Smckusick dcmischeme[BOARD(unit)].dis_char += nch; 63942354Smckusick #ifdef IOSTATS 64042354Smckusick dsp->rchars += nch; 64142354Smckusick if (nch <= DCMRBSIZE) 64242354Smckusick dsp->rsilo[nch]++; 64341480Smckusick else 64442354Smckusick dsp->rsilo[DCMRBSIZE+1]++; 64541480Smckusick #endif 64641480Smckusick } 64741480Smckusick 64842354Smckusick dcmxint(unit, dcm, tp) 64941480Smckusick int unit; 65041480Smckusick struct dcmdevice *dcm; 65142354Smckusick register struct tty *tp; 65241480Smckusick { 65341480Smckusick tp->t_state &= ~TS_BUSY; 65441480Smckusick if (tp->t_state & TS_FLUSH) 65541480Smckusick tp->t_state &= ~TS_FLUSH; 65649130Skarels (*linesw[tp->t_line].l_start)(tp); 65741480Smckusick } 65841480Smckusick 65941480Smckusick dcmmint(unit, mcnd, dcm) 66041480Smckusick register int unit; 66141480Smckusick register struct dcmdevice *dcm; 66241480Smckusick int mcnd; 66341480Smckusick { 66441480Smckusick register struct tty *tp; 66544317Shibler int delta; 66641480Smckusick 66741480Smckusick #ifdef DEBUG 66842354Smckusick if (dcmdebug & DDB_MODEM) 66945750Smckusick printf("dcmmint: port %d mcnd %x mcndlast %x\n", 67044317Shibler unit, mcnd, mcndlast[unit]); 67142354Smckusick #endif 67241480Smckusick tp = &dcm_tty[unit]; 67344317Shibler delta = mcnd ^ mcndlast[unit]; 67444317Shibler mcndlast[unit] = mcnd; 67549130Skarels if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && 676*50220Skarels (tp->t_flags & CCTS_OFLOW)) { 67749130Skarels if (mcnd & MI_CTS) { 67849130Skarels tp->t_state &= ~TS_TTSTOP; 67949130Skarels ttstart(tp); 68049130Skarels } else 68149130Skarels tp->t_state |= TS_TTSTOP; /* inline dcmstop */ 68249130Skarels } 683*50220Skarels if (delta & MI_CD) { 68441480Smckusick if (mcnd & MI_CD) 68544317Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1); 686*50220Skarels else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 && 687*50220Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 688*50220Skarels dcm_modem[unit]->mdmout = MO_OFF; 68941480Smckusick SEM_LOCK(dcm); 69045750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 69141480Smckusick dcm->dcm_cr |= CR_MODM; 69241480Smckusick SEM_UNLOCK(dcm); 69342354Smckusick DELAY(10); /* time to change lines */ 69441480Smckusick } 69541480Smckusick } 69641480Smckusick } 69741480Smckusick 69841480Smckusick dcmioctl(dev, cmd, data, flag) 69941480Smckusick dev_t dev; 70041480Smckusick caddr_t data; 70141480Smckusick { 70241480Smckusick register struct tty *tp; 70341480Smckusick register int unit = UNIT(dev); 70441480Smckusick register struct dcmdevice *dcm; 70541480Smckusick register int port; 70642354Smckusick int error, s; 70741480Smckusick 70841480Smckusick #ifdef DEBUG 70941480Smckusick if (dcmdebug & DDB_IOCTL) 71041480Smckusick printf("dcmioctl: unit %d cmd %x data %x flag %x\n", 71141480Smckusick unit, cmd, *data, flag); 71241480Smckusick #endif 71341480Smckusick tp = &dcm_tty[unit]; 71441480Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 71541480Smckusick if (error >= 0) 71641480Smckusick return (error); 71741480Smckusick error = ttioctl(tp, cmd, data, flag); 71841480Smckusick if (error >= 0) 71941480Smckusick return (error); 72041480Smckusick 72141480Smckusick port = PORT(unit); 72241480Smckusick dcm = dcm_addr[BOARD(unit)]; 72341480Smckusick switch (cmd) { 72441480Smckusick case TIOCSBRK: 72542354Smckusick /* 72642354Smckusick * Wait for transmitter buffer to empty 72742354Smckusick */ 72842354Smckusick s = spltty(); 72942354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 73042354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed)); 73141480Smckusick SEM_LOCK(dcm); 73242354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 73342354Smckusick dcm->dcm_cr |= (1 << port); /* start break */ 73441480Smckusick SEM_UNLOCK(dcm); 73542354Smckusick splx(s); 73641480Smckusick break; 73741480Smckusick 73841480Smckusick case TIOCCBRK: 73941480Smckusick SEM_LOCK(dcm); 74042354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 74142354Smckusick dcm->dcm_cr |= (1 << port); /* end break */ 74241480Smckusick SEM_UNLOCK(dcm); 74341480Smckusick break; 74441480Smckusick 74541480Smckusick case TIOCSDTR: 74641480Smckusick (void) dcmmctl(dev, MO_ON, DMBIS); 74741480Smckusick break; 74841480Smckusick 74941480Smckusick case TIOCCDTR: 75041480Smckusick (void) dcmmctl(dev, MO_ON, DMBIC); 75141480Smckusick break; 75241480Smckusick 75341480Smckusick case TIOCMSET: 75441480Smckusick (void) dcmmctl(dev, *(int *)data, DMSET); 75541480Smckusick break; 75641480Smckusick 75741480Smckusick case TIOCMBIS: 75841480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIS); 75941480Smckusick break; 76041480Smckusick 76141480Smckusick case TIOCMBIC: 76241480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIC); 76341480Smckusick break; 76441480Smckusick 76541480Smckusick case TIOCMGET: 76641480Smckusick *(int *)data = dcmmctl(dev, 0, DMGET); 76741480Smckusick break; 76841480Smckusick 76941480Smckusick default: 77041480Smckusick return (ENOTTY); 77141480Smckusick } 77241480Smckusick return (0); 77341480Smckusick } 77441480Smckusick 77541480Smckusick dcmparam(tp, t) 77641480Smckusick register struct tty *tp; 77741480Smckusick register struct termios *t; 77841480Smckusick { 77941480Smckusick register struct dcmdevice *dcm; 78042354Smckusick register int port, mode, cflag = t->c_cflag; 78141480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); 78242354Smckusick 78341480Smckusick /* check requested parameters */ 78441480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 785*50220Skarels return (EINVAL); 78641480Smckusick /* and copy to tty */ 78741480Smckusick tp->t_ispeed = t->c_ispeed; 78841480Smckusick tp->t_ospeed = t->c_ospeed; 78941480Smckusick tp->t_cflag = cflag; 79041480Smckusick if (ospeed == 0) { 79142354Smckusick (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET); 792*50220Skarels return (0); 79341480Smckusick } 79442354Smckusick 79542354Smckusick mode = 0; 79641480Smckusick switch (cflag&CSIZE) { 79741480Smckusick case CS5: 79841480Smckusick mode = LC_5BITS; break; 79941480Smckusick case CS6: 80041480Smckusick mode = LC_6BITS; break; 80141480Smckusick case CS7: 80241480Smckusick mode = LC_7BITS; break; 80341480Smckusick case CS8: 80441480Smckusick mode = LC_8BITS; break; 80541480Smckusick } 80641480Smckusick if (cflag&PARENB) { 80741480Smckusick if (cflag&PARODD) 80841480Smckusick mode |= LC_PODD; 80941480Smckusick else 81041480Smckusick mode |= LC_PEVEN; 81141480Smckusick } 81241480Smckusick if (cflag&CSTOPB) 81341480Smckusick mode |= LC_2STOP; 81441480Smckusick else 81541480Smckusick mode |= LC_1STOP; 81641480Smckusick #ifdef DEBUG 81741480Smckusick if (dcmdebug & DDB_PARAM) 81842354Smckusick printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n", 81942354Smckusick UNIT(tp->t_dev), cflag, mode, tp->t_ospeed, 82042354Smckusick DCM_USPERCH(tp->t_ospeed)); 82141480Smckusick #endif 82242354Smckusick 82342354Smckusick port = PORT(tp->t_dev); 82442354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)]; 82542354Smckusick /* 82642354Smckusick * Wait for transmitter buffer to empty. 82742354Smckusick */ 82841480Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 82942354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed)); 83042354Smckusick /* 83142354Smckusick * Make changes known to hardware. 83242354Smckusick */ 83342354Smckusick dcm->dcm_data[port].dcm_baud = ospeed; 83441480Smckusick dcm->dcm_data[port].dcm_conf = mode; 83541480Smckusick SEM_LOCK(dcm); 83642354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 83742354Smckusick dcm->dcm_cr |= (1 << port); 83841480Smckusick SEM_UNLOCK(dcm); 83942354Smckusick /* 84049130Skarels * Delay for config change to take place. Weighted by baud. 84142354Smckusick * XXX why do we do this? 84242354Smckusick */ 84342354Smckusick DELAY(16 * DCM_USPERCH(tp->t_ospeed)); 844*50220Skarels return (0); 84541480Smckusick } 84641480Smckusick 84741480Smckusick dcmstart(tp) 84841480Smckusick register struct tty *tp; 84941480Smckusick { 85041480Smckusick register struct dcmdevice *dcm; 85142354Smckusick register struct dcmpreg *pp; 85242354Smckusick register struct dcmtfifo *fifo; 85342354Smckusick register char *bp; 85442354Smckusick register unsigned tail, next; 85542354Smckusick register int port, nch; 85642354Smckusick unsigned head; 85742354Smckusick char buf[16]; 85842354Smckusick int s; 85942354Smckusick #ifdef IOSTATS 86042354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)]; 86142354Smckusick int tch = 0; 86242354Smckusick #endif 86342354Smckusick 86441480Smckusick s = spltty(); 86542354Smckusick #ifdef IOSTATS 86642354Smckusick dsp->xints++; 86742354Smckusick #endif 86841480Smckusick #ifdef DEBUG 86941480Smckusick if (dcmdebug & DDB_OUTPUT) 87042354Smckusick printf("dcmstart(%d): state %x flags %x outcc %d\n", 87142354Smckusick UNIT(tp->t_dev), tp->t_state, tp->t_flags, 87242354Smckusick tp->t_outq.c_cc); 87341480Smckusick #endif 87441480Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 87541480Smckusick goto out; 87641480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 87741480Smckusick if (tp->t_state&TS_ASLEEP) { 87841480Smckusick tp->t_state &= ~TS_ASLEEP; 87941480Smckusick wakeup((caddr_t)&tp->t_outq); 88041480Smckusick } 88141480Smckusick if (tp->t_wsel) { 88241480Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 88341480Smckusick tp->t_wsel = 0; 88441480Smckusick tp->t_state &= ~TS_WCOLL; 88541480Smckusick } 88641480Smckusick } 88742354Smckusick if (tp->t_outq.c_cc == 0) { 88842354Smckusick #ifdef IOSTATS 88942354Smckusick dsp->xempty++; 89042354Smckusick #endif 89142354Smckusick goto out; 89242354Smckusick } 89342354Smckusick 89442354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)]; 89542354Smckusick port = PORT(tp->t_dev); 89642354Smckusick pp = dcm_preg(dcm, port); 89742354Smckusick tail = pp->t_tail & TX_MASK; 89842354Smckusick next = (tail + 1) & TX_MASK; 89942354Smckusick head = pp->t_head & TX_MASK; 90042354Smckusick if (head == next) 90142354Smckusick goto out; 90242354Smckusick fifo = &dcm->dcm_tfifos[3-port][tail]; 90342354Smckusick again: 90442354Smckusick nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK); 90542354Smckusick #ifdef IOSTATS 90642354Smckusick tch += nch; 90742354Smckusick #endif 90841480Smckusick #ifdef DEBUG 90942354Smckusick if (dcmdebug & DDB_OUTPUT) 91042354Smckusick printf("\thead %x tail %x nch %d\n", head, tail, nch); 91141480Smckusick #endif 91242354Smckusick /* 91342354Smckusick * Loop transmitting all the characters we can. 91442354Smckusick */ 91542354Smckusick for (bp = buf; --nch >= 0; bp++) { 91642354Smckusick fifo->data_char = *bp; 91742354Smckusick pp->t_tail = next; 91842354Smckusick /* 91942354Smckusick * If this is the first character, 92042354Smckusick * get the hardware moving right now. 92142354Smckusick */ 92242354Smckusick if (bp == buf) { 92342354Smckusick tp->t_state |= TS_BUSY; 92442354Smckusick SEM_LOCK(dcm); 92542354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 92642354Smckusick dcm->dcm_cr |= (1 << port); 92742354Smckusick SEM_UNLOCK(dcm); 92842354Smckusick } 92941480Smckusick tail = next; 93042354Smckusick fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; 93142354Smckusick next = (next + 1) & TX_MASK; 93241480Smckusick } 93342354Smckusick /* 93442354Smckusick * Head changed while we were loading the buffer, 93542354Smckusick * go back and load some more if we can. 93642354Smckusick */ 93742354Smckusick if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) { 93842354Smckusick #ifdef IOSTATS 93942354Smckusick dsp->xrestarts++; 94042354Smckusick #endif 94142354Smckusick head = pp->t_head & TX_MASK; 94242354Smckusick goto again; 94342354Smckusick } 94449130Skarels 94542354Smckusick /* 94642354Smckusick * Kick it one last time in case it finished while we were 94744317Shibler * loading the last bunch. 94842354Smckusick */ 94942354Smckusick if (bp > &buf[1]) { 95041480Smckusick tp->t_state |= TS_BUSY; 95141480Smckusick SEM_LOCK(dcm); 95242354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 95342354Smckusick dcm->dcm_cr |= (1 << port); 95442354Smckusick SEM_UNLOCK(dcm); 95542354Smckusick } 95641480Smckusick #ifdef DEBUG 95741480Smckusick if (dcmdebug & DDB_INTR) 95843407Shibler printf("dcmstart(%d): head %x tail %x outqcc %d\n", 95943407Shibler UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc); 96041480Smckusick #endif 96141480Smckusick out: 96242354Smckusick #ifdef IOSTATS 96342354Smckusick dsp->xchars += tch; 96442354Smckusick if (tch <= DCMXBSIZE) 96542354Smckusick dsp->xsilo[tch]++; 96642354Smckusick else 96742354Smckusick dsp->xsilo[DCMXBSIZE+1]++; 96842354Smckusick #endif 96941480Smckusick splx(s); 97041480Smckusick } 97141480Smckusick 97241480Smckusick /* 97341480Smckusick * Stop output on a line. 97441480Smckusick */ 97541480Smckusick dcmstop(tp, flag) 97641480Smckusick register struct tty *tp; 97741480Smckusick { 97841480Smckusick int s; 97941480Smckusick 98041480Smckusick s = spltty(); 98141480Smckusick if (tp->t_state & TS_BUSY) { 98242354Smckusick /* XXX is there some way to safely stop transmission? */ 98344317Shibler if ((tp->t_state&TS_TTSTOP) == 0) 98441480Smckusick tp->t_state |= TS_FLUSH; 98541480Smckusick } 98641480Smckusick splx(s); 98741480Smckusick } 98841480Smckusick 98945750Smckusick /* 99045750Smckusick * Modem control 99145750Smckusick */ 99241480Smckusick dcmmctl(dev, bits, how) 99341480Smckusick dev_t dev; 99441480Smckusick int bits, how; 99541480Smckusick { 99641480Smckusick register struct dcmdevice *dcm; 997*50220Skarels int s, unit, brd, hit = 0; 99841480Smckusick 99945750Smckusick unit = UNIT(dev); 100045750Smckusick #ifdef DEBUG 100145750Smckusick if (dcmdebug & DDB_MODEM) 100245750Smckusick printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", 100345750Smckusick BOARD(unit), unit, bits, how); 100445750Smckusick #endif 100541480Smckusick 1006*50220Skarels brd = BOARD(unit); 1007*50220Skarels dcm = dcm_addr[brd]; 100841480Smckusick s = spltty(); 100941480Smckusick switch (how) { 101041480Smckusick 101141480Smckusick case DMSET: 101245750Smckusick dcm_modem[unit]->mdmout = bits; 101341480Smckusick hit++; 101441480Smckusick break; 101541480Smckusick 101641480Smckusick case DMBIS: 101745750Smckusick dcm_modem[unit]->mdmout |= bits; 101841480Smckusick hit++; 101941480Smckusick break; 102041480Smckusick 102141480Smckusick case DMBIC: 102245750Smckusick dcm_modem[unit]->mdmout &= ~bits; 102341480Smckusick hit++; 102441480Smckusick break; 102541480Smckusick 102641480Smckusick case DMGET: 102745750Smckusick bits = dcm_modem[unit]->mdmin; 1028*50220Skarels if (dcmsoftCAR[brd] & FLAG_STDDCE) 1029*50220Skarels bits = hp2dce_in(bits); 103041480Smckusick break; 103141480Smckusick } 103241480Smckusick if (hit) { 103341480Smckusick SEM_LOCK(dcm); 103445750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 103541480Smckusick dcm->dcm_cr |= CR_MODM; 103641480Smckusick SEM_UNLOCK(dcm); 103742354Smckusick DELAY(10); /* delay until done */ 103841480Smckusick (void) splx(s); 103941480Smckusick } 1040*50220Skarels return (bits); 104141480Smckusick } 104241480Smckusick 104342354Smckusick /* 104442354Smckusick * Set board to either interrupt per-character or at a fixed interval. 104542354Smckusick */ 104642354Smckusick dcmsetischeme(brd, flags) 104742354Smckusick int brd, flags; 104841480Smckusick { 104942354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 105042354Smckusick register struct dcmischeme *dis = &dcmischeme[brd]; 105141480Smckusick register int i; 105242354Smckusick u_char mask; 105342354Smckusick int perchar = flags & DIS_PERCHAR; 105441480Smckusick 105541480Smckusick #ifdef DEBUG 105642354Smckusick if (dcmdebug & DDB_INTSCHM) 105742354Smckusick printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", 105842354Smckusick brd, perchar, dis->dis_perchar, 105942354Smckusick dis->dis_intr, dis->dis_char); 106042354Smckusick if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { 106142354Smckusick printf("dcmsetischeme(%d): redundent request %d\n", 106242354Smckusick brd, perchar); 106342354Smckusick return; 106442354Smckusick } 106542354Smckusick #endif 106642354Smckusick /* 106742354Smckusick * If perchar is non-zero, we enable interrupts on all characters 106842354Smckusick * otherwise we disable perchar interrupts and use periodic 106942354Smckusick * polling interrupts. 107042354Smckusick */ 107142354Smckusick dis->dis_perchar = perchar; 107242354Smckusick mask = perchar ? 0xf : 0x0; 107342354Smckusick for (i = 0; i < 256; i++) 107442354Smckusick dcm->dcm_bmap[i].data_data = mask; 107542354Smckusick /* 107642354Smckusick * Don't slow down tandem mode, interrupt on flow control 107742354Smckusick * chars for any port on the board. 107842354Smckusick */ 107942354Smckusick if (!perchar) { 108042354Smckusick register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)]; 108142354Smckusick int c; 108242354Smckusick 108342354Smckusick for (i = 0; i < 4; i++, tp++) { 108442354Smckusick if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) 108542354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 108642354Smckusick if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) 108742354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 108841480Smckusick } 108941480Smckusick } 109042354Smckusick /* 109142354Smckusick * Board starts with timer disabled so if first call is to 109242354Smckusick * set perchar mode then we don't want to toggle the timer. 109342354Smckusick */ 109442354Smckusick if (flags == (DIS_RESET|DIS_PERCHAR)) 109541480Smckusick return; 109642354Smckusick /* 109742354Smckusick * Toggle card 16.7ms interrupts (we first make sure that card 109842354Smckusick * has cleared the bit so it will see the toggle). 109942354Smckusick */ 110042354Smckusick while (dcm->dcm_cr & CR_TIMER) 110142354Smckusick ; 110241480Smckusick SEM_LOCK(dcm); 110342354Smckusick dcm->dcm_cr |= CR_TIMER; 110441480Smckusick SEM_UNLOCK(dcm); 110541480Smckusick } 110641480Smckusick 110741480Smckusick /* 110841480Smckusick * Following are all routines needed for DCM to act as console 110941480Smckusick */ 111045788Sbostic #include "../hp300/cons.h" 111141480Smckusick 111242354Smckusick dcmcnprobe(cp) 111342354Smckusick struct consdev *cp; 111441480Smckusick { 111542354Smckusick register struct hp_hw *hw; 111649130Skarels int unit; 111741480Smckusick 111849130Skarels /* locate the major number */ 111949130Skarels for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) 112049130Skarels if (cdevsw[dcmmajor].d_open == dcmopen) 112149130Skarels break; 112249130Skarels 112342354Smckusick /* 112442354Smckusick * Implicitly assigns the lowest select code DCM card found to be 112542354Smckusick * logical unit 0 (actually CONUNIT). If your config file does 112642354Smckusick * anything different, you're screwed. 112742354Smckusick */ 112842354Smckusick for (hw = sc_table; hw->hw_type; hw++) 112949301Shibler if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva)) 113042354Smckusick break; 113149301Shibler if (!HW_ISDEV(hw, D_COMMDCM)) { 113242354Smckusick cp->cn_pri = CN_DEAD; 113342354Smckusick return; 113442354Smckusick } 113542354Smckusick unit = CONUNIT; 113649301Shibler dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva; 113741480Smckusick 113842354Smckusick /* initialize required fields */ 113949130Skarels cp->cn_dev = makedev(dcmmajor, unit); 114042354Smckusick cp->cn_tp = &dcm_tty[unit]; 114142354Smckusick switch (dcm_addr[BOARD(unit)]->dcm_rsid) { 114242354Smckusick case DCMID: 114342354Smckusick cp->cn_pri = CN_NORMAL; 114442354Smckusick break; 114542354Smckusick case DCMID|DCMCON: 114642354Smckusick cp->cn_pri = CN_REMOTE; 114742354Smckusick break; 114842354Smckusick default: 114942354Smckusick cp->cn_pri = CN_DEAD; 115049130Skarels return; 115142354Smckusick } 115249130Skarels /* 115349130Skarels * If dcmconsole is initialized, raise our priority. 115449130Skarels */ 115549130Skarels if (dcmconsole == UNIT(unit)) 115649130Skarels cp->cn_pri = CN_REMOTE; 115749301Shibler #ifdef KGDB_CHEAT 115849130Skarels /* 115949130Skarels * This doesn't currently work, at least not with ite consoles; 116049130Skarels * the console hasn't been initialized yet. 116149130Skarels */ 116249130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { 116349130Skarels (void) dcminit(kgdb_dev, kgdb_rate); 116449130Skarels if (kgdb_debug_init) { 116549130Skarels /* 116649130Skarels * We assume that console is ready for us... 116749130Skarels * this assumes that a dca or ite console 116849130Skarels * has been selected already and will init 116949130Skarels * on the first putc. 117049130Skarels */ 117149130Skarels printf("dcm%d: ", UNIT(kgdb_dev)); 117249130Skarels kgdb_connect(1); 117349130Skarels } 117449130Skarels } 117549130Skarels #endif 117642354Smckusick } 117742354Smckusick 117842354Smckusick dcmcninit(cp) 117942354Smckusick struct consdev *cp; 118042354Smckusick { 118142354Smckusick dcminit(cp->cn_dev, dcmdefaultrate); 118249130Skarels dcmconsinit = 1; 118342354Smckusick dcmconsole = UNIT(cp->cn_dev); 118442354Smckusick } 118542354Smckusick 118642354Smckusick dcminit(dev, rate) 118742354Smckusick dev_t dev; 118842354Smckusick int rate; 118942354Smckusick { 119042354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 119142354Smckusick int s, mode, port; 119242354Smckusick 119342354Smckusick port = PORT(dev); 119442354Smckusick mode = LC_8BITS | LC_1STOP; 119541480Smckusick s = splhigh(); 119642354Smckusick /* 119742354Smckusick * Wait for transmitter buffer to empty. 119842354Smckusick */ 119942354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 120042354Smckusick DELAY(DCM_USPERCH(rate)); 120142354Smckusick /* 120242354Smckusick * Make changes known to hardware. 120342354Smckusick */ 120442354Smckusick dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); 120542354Smckusick dcm->dcm_data[port].dcm_conf = mode; 120642354Smckusick SEM_LOCK(dcm); 120742354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 120842354Smckusick dcm->dcm_cr |= (1 << port); 120942354Smckusick SEM_UNLOCK(dcm); 121042354Smckusick /* 121149130Skarels * Delay for config change to take place. Weighted by baud. 121242354Smckusick * XXX why do we do this? 121342354Smckusick */ 121442354Smckusick DELAY(16 * DCM_USPERCH(rate)); 121541480Smckusick splx(s); 121641480Smckusick } 121741480Smckusick 121841480Smckusick dcmcngetc(dev) 121942354Smckusick dev_t dev; 122041480Smckusick { 122142354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 122242354Smckusick register struct dcmrfifo *fifo; 122342354Smckusick register struct dcmpreg *pp; 122442354Smckusick register unsigned head; 122542354Smckusick int s, c, stat, port; 122642354Smckusick 122742354Smckusick port = PORT(dev); 122842354Smckusick pp = dcm_preg(dcm, port); 122942354Smckusick s = splhigh(); 123042354Smckusick head = pp->r_head & RX_MASK; 123142354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 123242354Smckusick while (head == (pp->r_tail & RX_MASK)) 123342354Smckusick ; 123442354Smckusick /* 123542354Smckusick * If board interrupts are enabled, just let our received char 123642354Smckusick * interrupt through in case some other port on the board was 123742354Smckusick * busy. Otherwise we must clear the interrupt. 123842354Smckusick */ 123942354Smckusick SEM_LOCK(dcm); 124042354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) 124142354Smckusick stat = dcm->dcm_iir; 124242354Smckusick SEM_UNLOCK(dcm); 124342354Smckusick c = fifo->data_char; 124442354Smckusick stat = fifo->data_stat; 124542354Smckusick pp->r_head = (head + 2) & RX_MASK; 124642354Smckusick splx(s); 1247*50220Skarels return (c); 124841480Smckusick } 124941480Smckusick 125041480Smckusick /* 125141480Smckusick * Console kernel output character routine. 125241480Smckusick */ 125341480Smckusick dcmcnputc(dev, c) 125441480Smckusick dev_t dev; 125542354Smckusick int c; 125641480Smckusick { 125741480Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 125842354Smckusick register struct dcmpreg *pp; 125942354Smckusick unsigned tail; 126042354Smckusick int s, port, stat; 126141480Smckusick 126242354Smckusick port = PORT(dev); 126342354Smckusick pp = dcm_preg(dcm, port); 126442354Smckusick s = splhigh(); 126542354Smckusick #ifdef KGDB 126642354Smckusick if (dev != kgdb_dev) 126742354Smckusick #endif 126849130Skarels if (dcmconsinit == 0) { 126942354Smckusick (void) dcminit(dev, dcmdefaultrate); 127049130Skarels dcmconsinit = 1; 127142354Smckusick } 127242354Smckusick tail = pp->t_tail & TX_MASK; 127342354Smckusick while (tail != (pp->t_head & TX_MASK)) 127442354Smckusick ; 127542354Smckusick dcm->dcm_tfifos[3-port][tail].data_char = c; 127642354Smckusick pp->t_tail = tail = (tail + 1) & TX_MASK; 127741480Smckusick SEM_LOCK(dcm); 127842354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 127942354Smckusick dcm->dcm_cr |= (1 << port); 128041480Smckusick SEM_UNLOCK(dcm); 128142354Smckusick while (tail != (pp->t_head & TX_MASK)) 128242354Smckusick ; 128342354Smckusick /* 128442354Smckusick * If board interrupts are enabled, just let our completion 128542354Smckusick * interrupt through in case some other port on the board 128642354Smckusick * was busy. Otherwise we must clear the interrupt. 128742354Smckusick */ 128842354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) { 128942354Smckusick SEM_LOCK(dcm); 129042354Smckusick stat = dcm->dcm_iir; 129142354Smckusick SEM_UNLOCK(dcm); 129242354Smckusick } 129341480Smckusick splx(s); 129441480Smckusick } 129541480Smckusick #endif 1296