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*49750Smarc * @(#)dcm.c 7.13 (Berkeley) 05/16/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 9242354Smckusick * (16.7ms is about 550 buad, 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 12742354Smckusick extern int 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 16841480Smckusick dcmprobe(hd) 16941480Smckusick register struct hp_device *hd; 17041480Smckusick { 17141480Smckusick register struct dcmdevice *dcm; 17241480Smckusick register int i; 17341480Smckusick register int timo = 0; 17442354Smckusick int s, brd, isconsole; 17541480Smckusick 17641480Smckusick dcm = (struct dcmdevice *)hd->hp_addr; 17741480Smckusick if ((dcm->dcm_rsid & 0x1f) != DCMID) 17841480Smckusick return (0); 17941480Smckusick brd = hd->hp_unit; 18042354Smckusick isconsole = (brd == BOARD(dcmconsole)); 18142354Smckusick /* 18242354Smckusick * XXX selected console device (CONSUNIT) as determined by 18342354Smckusick * dcmcnprobe does not agree with logical numbering imposed 18442354Smckusick * by the config file (i.e. lowest address DCM is not unit 18542354Smckusick * CONSUNIT). Don't recognize this card. 18642354Smckusick */ 18742354Smckusick if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)]) 18842354Smckusick return(0); 18942354Smckusick 19042354Smckusick /* 19142354Smckusick * Empirically derived self-test magic 19242354Smckusick */ 19341480Smckusick s = spltty(); 19441480Smckusick dcm->dcm_rsid = DCMRS; 19541480Smckusick DELAY(50000); /* 5000 is not long enough */ 19641480Smckusick dcm->dcm_rsid = 0; 19741480Smckusick dcm->dcm_ic = IC_IE; 19841480Smckusick dcm->dcm_cr = CR_SELFT; 19942354Smckusick while ((dcm->dcm_ic & IC_IR) == 0) 20042354Smckusick if (++timo == 20000) 20141480Smckusick return(0); 20241480Smckusick DELAY(50000) /* XXX why is this needed ???? */ 20342354Smckusick while ((dcm->dcm_iir & IIR_SELFT) == 0) 20442354Smckusick if (++timo == 400000) 20541480Smckusick return(0); 20641480Smckusick DELAY(50000) /* XXX why is this needed ???? */ 20741480Smckusick if (dcm->dcm_stcon != ST_OK) { 20842354Smckusick if (!isconsole) 20942354Smckusick printf("dcm%d: self test failed: %x\n", 21042354Smckusick brd, dcm->dcm_stcon); 21141480Smckusick return(0); 21241480Smckusick } 21341480Smckusick dcm->dcm_ic = IC_ID; 21441480Smckusick splx(s); 21541480Smckusick 21641480Smckusick hd->hp_ipl = DCMIPL(dcm->dcm_ic); 21742354Smckusick dcm_addr[brd] = dcm; 21842354Smckusick dcm_active |= 1 << brd; 21942354Smckusick dcmsoftCAR[brd] = hd->hp_flags; 22041480Smckusick dcmisr[brd].isr_ipl = hd->hp_ipl; 22141480Smckusick dcmisr[brd].isr_arg = brd; 22241480Smckusick dcmisr[brd].isr_intr = dcmintr; 22341480Smckusick isrlink(&dcmisr[brd]); 22442354Smckusick #ifdef KGDB 22549130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) { 22642354Smckusick if (dcmconsole == UNIT(kgdb_dev)) 22742354Smckusick kgdb_dev = -1; /* can't debug over console port */ 22849301Shibler #ifndef KGDB_CHEAT 22949130Skarels /* 23049130Skarels * The following could potentially be replaced 23149130Skarels * by the corresponding code in dcmcnprobe. 23249130Skarels */ 23342354Smckusick else { 23442354Smckusick (void) dcminit(kgdb_dev, kgdb_rate); 23542354Smckusick if (kgdb_debug_init) { 23649130Skarels printf("dcm%d: ", UNIT(kgdb_dev)); 23749130Skarels kgdb_connect(1); 23842354Smckusick } else 23949130Skarels printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev)); 24042354Smckusick } 24149130Skarels /* end could be replaced */ 24249301Shibler #endif 24342354Smckusick } 24442354Smckusick #endif 24542354Smckusick if (dcmistype == DIS_TIMER) 24642354Smckusick dcmsetischeme(brd, DIS_RESET|DIS_TIMER); 24742354Smckusick else 24842354Smckusick dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR); 24945750Smckusick 25045750Smckusick /* load pointers to modem control */ 25145750Smckusick dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0; 25245750Smckusick dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1; 25345750Smckusick dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2; 25445750Smckusick dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3; 25545750Smckusick /* set DCD (modem) and CTS (flow control) on all ports */ 25645750Smckusick for (i = 0; i < 4; i++) 25745750Smckusick dcm_modem[MKUNIT(brd, i)]->mdmmsk = MI_CD|MI_CTS; 25845750Smckusick 25942354Smckusick dcm->dcm_ic = IC_IE; /* turn all interrupts on */ 26041480Smckusick /* 26141480Smckusick * Need to reset baud rate, etc. of next print so reset dcmconsole. 26241480Smckusick * Also make sure console is always "hardwired" 26341480Smckusick */ 26442354Smckusick if (isconsole) { 26549130Skarels dcmconsinit = 0; 26641480Smckusick dcmsoftCAR[brd] |= (1 << PORT(dcmconsole)); 26741480Smckusick } 26841480Smckusick return (1); 26941480Smckusick } 27041480Smckusick 27149130Skarels /* ARGSUSED */ 27249130Skarels #ifdef __STDC__ 27349130Skarels dcmopen(dev_t dev, int flag, int mode, struct proc *p) 27449130Skarels #else 27549130Skarels dcmopen(dev, flag, mode, p) 27641480Smckusick dev_t dev; 27749130Skarels int flag, mode; 27849130Skarels struct proc *p; 27949130Skarels #endif 28041480Smckusick { 28141480Smckusick register struct tty *tp; 28241480Smckusick register int unit, brd; 28344762Skarels int error = 0; 28441480Smckusick 28541480Smckusick unit = UNIT(dev); 28641480Smckusick brd = BOARD(unit); 28742354Smckusick if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0) 28841480Smckusick return (ENXIO); 28941480Smckusick tp = &dcm_tty[unit]; 29041480Smckusick tp->t_oproc = dcmstart; 29142354Smckusick tp->t_param = dcmparam; 29241480Smckusick tp->t_dev = dev; 29341480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 29442950Smarc tp->t_state |= TS_WOPEN; 29541480Smckusick ttychars(tp); 29649130Skarels if (tp->t_ispeed == 0) { 29749130Skarels tp->t_iflag = TTYDEF_IFLAG; 29849130Skarels tp->t_oflag = TTYDEF_OFLAG; 29949130Skarels tp->t_cflag = TTYDEF_CFLAG; 30049130Skarels tp->t_lflag = TTYDEF_LFLAG; 30149130Skarels tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 30249130Skarels } 30342354Smckusick (void) dcmparam(tp, &tp->t_termios); 30441480Smckusick ttsetwater(tp); 30549130Skarels } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 30641480Smckusick return (EBUSY); 30745750Smckusick (void) dcmmctl(dev, MO_ON, DMSET); /* enable port */ 30849130Skarels if ((dcmsoftCAR[brd] & (1 << PORT(unit))) || 30949130Skarels (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)) 31041480Smckusick tp->t_state |= TS_CARR_ON; 31145750Smckusick #ifdef DEBUG 31245750Smckusick if (dcmdebug & DDB_MODEM) 31345750Smckusick printf("dcm%d: dcmopen port %d softcarr %c\n", 31445750Smckusick brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0'); 31545750Smckusick #endif 31641480Smckusick (void) spltty(); 31744295Shibler while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 31841480Smckusick (tp->t_state & TS_CARR_ON) == 0) { 31941480Smckusick tp->t_state |= TS_WOPEN; 32044295Shibler if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 32144295Shibler ttopen, 0)) 32244295Shibler break; 32341480Smckusick } 32441480Smckusick (void) spl0(); 32545750Smckusick 32641480Smckusick #ifdef DEBUG 32741480Smckusick if (dcmdebug & DDB_OPENCLOSE) 32841480Smckusick printf("dcmopen: u %x st %x fl %x\n", 32941480Smckusick unit, tp->t_state, tp->t_flags); 33041480Smckusick #endif 33144295Shibler if (error == 0) 33244295Shibler error = (*linesw[tp->t_line].l_open)(dev, tp); 33344295Shibler return (error); 33441480Smckusick } 33541480Smckusick 33641480Smckusick /*ARGSUSED*/ 337*49750Smarc dcmclose(dev, flag, mode, p) 33841480Smckusick dev_t dev; 339*49750Smarc int flag, mode; 340*49750Smarc struct proc *p; 34141480Smckusick { 34241480Smckusick register struct tty *tp; 34341480Smckusick int unit; 34441480Smckusick 34541480Smckusick unit = UNIT(dev); 34641480Smckusick tp = &dcm_tty[unit]; 347*49750Smarc (*linesw[tp->t_line].l_close)(tp, flag); 34849130Skarels #ifdef KGDB 34949130Skarels if (dev != kgdb_dev) 35049130Skarels #endif 35149130Skarels (void) dcmmctl(dev, MO_OFF, DMSET); 35249130Skarels if (tp->t_state & TS_HUPCLS) 35349130Skarels (*linesw[tp->t_line].l_modem)(tp, 0); 35441480Smckusick #ifdef DEBUG 35541480Smckusick if (dcmdebug & DDB_OPENCLOSE) 35641480Smckusick printf("dcmclose: u %x st %x fl %x\n", 35741480Smckusick unit, tp->t_state, tp->t_flags); 35841480Smckusick #endif 35941480Smckusick ttyclose(tp); 36041480Smckusick return(0); 36141480Smckusick } 36241480Smckusick 36341480Smckusick dcmread(dev, uio, flag) 36441480Smckusick dev_t dev; 36541480Smckusick struct uio *uio; 36641480Smckusick { 36741480Smckusick register struct tty *tp; 36841480Smckusick 36941480Smckusick tp = &dcm_tty[UNIT(dev)]; 37041480Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 37141480Smckusick } 37241480Smckusick 37341480Smckusick dcmwrite(dev, uio, flag) 37441480Smckusick dev_t dev; 37541480Smckusick struct uio *uio; 37641480Smckusick { 37741480Smckusick int unit = UNIT(dev); 37841480Smckusick register struct tty *tp; 37941480Smckusick 38041480Smckusick tp = &dcm_tty[unit]; 38142354Smckusick /* 38242354Smckusick * XXX we disallow virtual consoles if the physical console is 38342354Smckusick * a serial port. This is in case there is a display attached that 38442354Smckusick * is not the console. In that situation we don't need/want the X 38542354Smckusick * server taking over the console. 38642354Smckusick */ 38742354Smckusick if (constty && unit == dcmconsole) 38842354Smckusick constty = NULL; 38941480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 39041480Smckusick } 39141480Smckusick 39241480Smckusick dcmintr(brd) 39341480Smckusick register int brd; 39441480Smckusick { 39542354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 39642354Smckusick register struct dcmischeme *dis; 39745750Smckusick register int unit = MKUNIT(brd, 0); 39845750Smckusick register int code, i; 39945750Smckusick int pcnd[4], mcode, mcnd[4]; 40041480Smckusick 40142354Smckusick /* 40242354Smckusick * Do all guarded register accesses right off to minimize 40342354Smckusick * block out of hardware. 40442354Smckusick */ 40541480Smckusick SEM_LOCK(dcm); 40641480Smckusick if ((dcm->dcm_ic & IC_IR) == 0) { 40741480Smckusick SEM_UNLOCK(dcm); 40841480Smckusick return(0); 40941480Smckusick } 41041480Smckusick for (i = 0; i < 4; i++) { 41141480Smckusick pcnd[i] = dcm->dcm_icrtab[i].dcm_data; 41241480Smckusick dcm->dcm_icrtab[i].dcm_data = 0; 41345750Smckusick mcnd[i] = dcm_modem[unit+i]->mdmin; 41441480Smckusick } 41541480Smckusick code = dcm->dcm_iir & IIR_MASK; 41642354Smckusick dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ 41745750Smckusick mcode = dcm->dcm_modemintr; 41845750Smckusick dcm->dcm_modemintr = 0; 41941480Smckusick SEM_UNLOCK(dcm); 42041480Smckusick 42141480Smckusick #ifdef DEBUG 42245750Smckusick if (dcmdebug & DDB_INTR) { 42345750Smckusick printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ", 42445750Smckusick brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); 42545750Smckusick printf("miir %x mc %x/%x/%x/%x\n", 42645750Smckusick mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); 42745750Smckusick } 42841480Smckusick #endif 42942354Smckusick if (code & IIR_TIMEO) 43042354Smckusick dcmrint(brd, dcm); 43141480Smckusick if (code & IIR_PORT0) 43245750Smckusick dcmpint(unit+0, pcnd[0], dcm); 43341480Smckusick if (code & IIR_PORT1) 43445750Smckusick dcmpint(unit+1, pcnd[1], dcm); 43541480Smckusick if (code & IIR_PORT2) 43645750Smckusick dcmpint(unit+2, pcnd[2], dcm); 43741480Smckusick if (code & IIR_PORT3) 43845750Smckusick dcmpint(unit+3, pcnd[3], dcm); 43945750Smckusick if (code & IIR_MODM) { 44045750Smckusick if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ 44145750Smckusick dcmmint(unit+0, mcnd[0], dcm); 44245750Smckusick if (mcode & 0x2) 44345750Smckusick dcmmint(unit+1, mcnd[1], dcm); 44445750Smckusick if (mcode & 0x4) 44545750Smckusick dcmmint(unit+2, mcnd[2], dcm); 44645750Smckusick if (mcode & 0x8) 44745750Smckusick dcmmint(unit+3, mcnd[3], dcm); 44845750Smckusick } 44941480Smckusick 45042354Smckusick dis = &dcmischeme[brd]; 45141480Smckusick /* 45242354Smckusick * Chalk up a receiver interrupt if the timer running or one of 45342354Smckusick * the ports reports a special character interrupt. 45441480Smckusick */ 45542354Smckusick if ((code & IIR_TIMEO) || 45642354Smckusick ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) 45742354Smckusick dis->dis_intr++; 45842354Smckusick /* 45942354Smckusick * See if it is time to check/change the interrupt rate. 46042354Smckusick */ 46142354Smckusick if (dcmistype < 0 && 46245750Smckusick (i = time.tv_sec - dis->dis_time) >= dcminterval) { 46341480Smckusick /* 46442354Smckusick * If currently per-character and averaged over 70 interrupts 46542354Smckusick * per-second (66 is threshold of 600 baud) in last interval, 46642354Smckusick * switch to timer mode. 46742354Smckusick * 46842354Smckusick * XXX decay counts ala load average to avoid spikes? 46941480Smckusick */ 47045750Smckusick if (dis->dis_perchar && dis->dis_intr > 70 * i) 47142354Smckusick dcmsetischeme(brd, DIS_TIMER); 47242354Smckusick /* 47342354Smckusick * If currently using timer and had more interrupts than 47442354Smckusick * received characters in the last interval, switch back 47542354Smckusick * to per-character. Note that after changing to per-char 47642354Smckusick * we must process any characters already in the queue 47742354Smckusick * since they may have arrived before the bitmap was setup. 47842354Smckusick * 47942354Smckusick * XXX decay counts? 48042354Smckusick */ 48142354Smckusick else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { 48242354Smckusick dcmsetischeme(brd, DIS_PERCHAR); 48341480Smckusick dcmrint(brd, dcm); 48441480Smckusick } 48542354Smckusick dis->dis_intr = dis->dis_char = 0; 48642354Smckusick dis->dis_time = time.tv_sec; 48742354Smckusick } 48841480Smckusick return(1); 48941480Smckusick } 49041480Smckusick 49141480Smckusick /* 49241480Smckusick * Port interrupt. Can be two things: 49341480Smckusick * First, it might be a special character (exception interrupt); 49441480Smckusick * Second, it may be a buffer empty (transmit interrupt); 49541480Smckusick */ 49641480Smckusick dcmpint(unit, code, dcm) 49741480Smckusick int unit, code; 49842354Smckusick struct dcmdevice *dcm; 49941480Smckusick { 50042354Smckusick struct tty *tp = &dcm_tty[unit]; 50141480Smckusick 50242354Smckusick if (code & IT_SPEC) 50342354Smckusick dcmreadbuf(unit, dcm, tp); 50441480Smckusick if (code & IT_TX) 50542354Smckusick dcmxint(unit, dcm, tp); 50641480Smckusick } 50741480Smckusick 50841480Smckusick dcmrint(brd, dcm) 50941480Smckusick int brd; 51041480Smckusick register struct dcmdevice *dcm; 51141480Smckusick { 51242354Smckusick register int i, unit; 51341480Smckusick register struct tty *tp; 51441480Smckusick 51541480Smckusick unit = MKUNIT(brd, 0); 51641480Smckusick tp = &dcm_tty[unit]; 51742354Smckusick for (i = 0; i < 4; i++, tp++, unit++) 51842354Smckusick dcmreadbuf(unit, dcm, tp); 51941480Smckusick } 52041480Smckusick 52142354Smckusick dcmreadbuf(unit, dcm, tp) 52241480Smckusick int unit; 52341480Smckusick register struct dcmdevice *dcm; 52441480Smckusick register struct tty *tp; 52541480Smckusick { 52642354Smckusick int port = PORT(unit); 52742354Smckusick register struct dcmpreg *pp = dcm_preg(dcm, port); 52842354Smckusick register struct dcmrfifo *fifo; 52941480Smckusick register int c, stat; 53041480Smckusick register unsigned head; 53142354Smckusick int nch = 0; 53242354Smckusick #ifdef IOSTATS 53342354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(unit)]; 53441480Smckusick 53542354Smckusick dsp->rints++; 53642354Smckusick #endif 53743407Shibler if ((tp->t_state & TS_ISOPEN) == 0) { 53842354Smckusick #ifdef KGDB 53949130Skarels if ((makedev(dcmmajor, unit) == kgdb_dev) && 54042354Smckusick (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && 54149130Skarels dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_END) { 54242354Smckusick pp->r_head = (head + 2) & RX_MASK; 54349130Skarels kgdb_connect(0); /* trap into kgdb */ 54442354Smckusick return; 54542354Smckusick } 54649130Skarels #endif /* KGDB */ 54742354Smckusick pp->r_head = pp->r_tail & RX_MASK; 54842354Smckusick return; 54942354Smckusick } 55041480Smckusick 55142354Smckusick head = pp->r_head & RX_MASK; 55242354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 55342354Smckusick /* 55442354Smckusick * XXX upper bound on how many chars we will take in one swallow? 55542354Smckusick */ 55642354Smckusick while (head != (pp->r_tail & RX_MASK)) { 55742354Smckusick /* 55842354Smckusick * Get character/status and update head pointer as fast 55942354Smckusick * as possible to make room for more characters. 56042354Smckusick */ 56142354Smckusick c = fifo->data_char; 56242354Smckusick stat = fifo->data_stat; 56341480Smckusick head = (head + 2) & RX_MASK; 56442354Smckusick pp->r_head = head; 56542354Smckusick fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; 56642354Smckusick nch++; 56741480Smckusick 56841480Smckusick #ifdef DEBUG 56941480Smckusick if (dcmdebug & DDB_INPUT) 57042354Smckusick printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n", 57142354Smckusick unit, c&0xFF, c, stat&0xFF, 57242354Smckusick tp->t_flags, head, pp->r_tail); 57341480Smckusick #endif 57442354Smckusick /* 57542354Smckusick * Check for and handle errors 57642354Smckusick */ 57742354Smckusick if (stat & RD_MASK) { 57841480Smckusick #ifdef DEBUG 57942354Smckusick if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) 58042354Smckusick printf("dcmreadbuf(%d): err: c%x('%c') s%x\n", 58142354Smckusick unit, stat, c&0xFF, c); 58241480Smckusick #endif 58341480Smckusick if (stat & (RD_BD | RD_FE)) 58441480Smckusick c |= TTY_FE; 58541480Smckusick else if (stat & RD_PE) 58641480Smckusick c |= TTY_PE; 58741480Smckusick else if (stat & RD_OVF) 58841480Smckusick log(LOG_WARNING, 58942354Smckusick "dcm%d: silo overflow\n", unit); 59041480Smckusick else if (stat & RD_OE) 59141480Smckusick log(LOG_WARNING, 59242354Smckusick "dcm%d: uart overflow\n", unit); 59341480Smckusick } 59441480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 59541480Smckusick } 59642354Smckusick dcmischeme[BOARD(unit)].dis_char += nch; 59742354Smckusick #ifdef IOSTATS 59842354Smckusick dsp->rchars += nch; 59942354Smckusick if (nch <= DCMRBSIZE) 60042354Smckusick dsp->rsilo[nch]++; 60141480Smckusick else 60242354Smckusick dsp->rsilo[DCMRBSIZE+1]++; 60341480Smckusick #endif 60441480Smckusick } 60541480Smckusick 60642354Smckusick dcmxint(unit, dcm, tp) 60741480Smckusick int unit; 60841480Smckusick struct dcmdevice *dcm; 60942354Smckusick register struct tty *tp; 61041480Smckusick { 61141480Smckusick tp->t_state &= ~TS_BUSY; 61241480Smckusick if (tp->t_state & TS_FLUSH) 61341480Smckusick tp->t_state &= ~TS_FLUSH; 61449130Skarels (*linesw[tp->t_line].l_start)(tp); 61541480Smckusick } 61641480Smckusick 61741480Smckusick dcmmint(unit, mcnd, dcm) 61841480Smckusick register int unit; 61941480Smckusick register struct dcmdevice *dcm; 62041480Smckusick int mcnd; 62141480Smckusick { 62241480Smckusick register struct tty *tp; 62344317Shibler int delta; 62441480Smckusick 62541480Smckusick #ifdef DEBUG 62642354Smckusick if (dcmdebug & DDB_MODEM) 62745750Smckusick printf("dcmmint: port %d mcnd %x mcndlast %x\n", 62844317Shibler unit, mcnd, mcndlast[unit]); 62942354Smckusick #endif 63041480Smckusick tp = &dcm_tty[unit]; 63144317Shibler delta = mcnd ^ mcndlast[unit]; 63244317Shibler mcndlast[unit] = mcnd; 63349130Skarels if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && 63449130Skarels (tp->t_flags & CRTSCTS)) { 63549130Skarels if (mcnd & MI_CTS) { 63649130Skarels tp->t_state &= ~TS_TTSTOP; 63749130Skarels ttstart(tp); 63849130Skarels } else 63949130Skarels tp->t_state |= TS_TTSTOP; /* inline dcmstop */ 64049130Skarels } 64144317Shibler if ((delta & MI_CD) && 64244317Shibler (dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) { 64341480Smckusick if (mcnd & MI_CD) 64444317Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1); 64541480Smckusick else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 64645750Smckusick dcm_modem[unit]->mdmout &= ~(MO_DTR|MO_RTS); 64741480Smckusick SEM_LOCK(dcm); 64845750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 64941480Smckusick dcm->dcm_cr |= CR_MODM; 65041480Smckusick SEM_UNLOCK(dcm); 65142354Smckusick DELAY(10); /* time to change lines */ 65241480Smckusick } 65341480Smckusick } 65441480Smckusick } 65541480Smckusick 65641480Smckusick dcmioctl(dev, cmd, data, flag) 65741480Smckusick dev_t dev; 65841480Smckusick caddr_t data; 65941480Smckusick { 66041480Smckusick register struct tty *tp; 66141480Smckusick register int unit = UNIT(dev); 66241480Smckusick register struct dcmdevice *dcm; 66341480Smckusick register int port; 66442354Smckusick int error, s; 66541480Smckusick 66641480Smckusick #ifdef DEBUG 66741480Smckusick if (dcmdebug & DDB_IOCTL) 66841480Smckusick printf("dcmioctl: unit %d cmd %x data %x flag %x\n", 66941480Smckusick unit, cmd, *data, flag); 67041480Smckusick #endif 67141480Smckusick tp = &dcm_tty[unit]; 67241480Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 67341480Smckusick if (error >= 0) 67441480Smckusick return (error); 67541480Smckusick error = ttioctl(tp, cmd, data, flag); 67641480Smckusick if (error >= 0) 67741480Smckusick return (error); 67841480Smckusick 67941480Smckusick port = PORT(unit); 68041480Smckusick dcm = dcm_addr[BOARD(unit)]; 68141480Smckusick switch (cmd) { 68241480Smckusick case TIOCSBRK: 68342354Smckusick /* 68442354Smckusick * Wait for transmitter buffer to empty 68542354Smckusick */ 68642354Smckusick s = spltty(); 68742354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 68842354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed)); 68941480Smckusick SEM_LOCK(dcm); 69042354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 69142354Smckusick dcm->dcm_cr |= (1 << port); /* start break */ 69241480Smckusick SEM_UNLOCK(dcm); 69342354Smckusick splx(s); 69441480Smckusick break; 69541480Smckusick 69641480Smckusick case TIOCCBRK: 69741480Smckusick SEM_LOCK(dcm); 69842354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 69942354Smckusick dcm->dcm_cr |= (1 << port); /* end break */ 70041480Smckusick SEM_UNLOCK(dcm); 70141480Smckusick break; 70241480Smckusick 70341480Smckusick case TIOCSDTR: 70441480Smckusick (void) dcmmctl(dev, MO_ON, DMBIS); 70541480Smckusick break; 70641480Smckusick 70741480Smckusick case TIOCCDTR: 70841480Smckusick (void) dcmmctl(dev, MO_ON, DMBIC); 70941480Smckusick break; 71041480Smckusick 71141480Smckusick case TIOCMSET: 71241480Smckusick (void) dcmmctl(dev, *(int *)data, DMSET); 71341480Smckusick break; 71441480Smckusick 71541480Smckusick case TIOCMBIS: 71641480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIS); 71741480Smckusick break; 71841480Smckusick 71941480Smckusick case TIOCMBIC: 72041480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIC); 72141480Smckusick break; 72241480Smckusick 72341480Smckusick case TIOCMGET: 72441480Smckusick *(int *)data = dcmmctl(dev, 0, DMGET); 72541480Smckusick break; 72641480Smckusick 72741480Smckusick default: 72841480Smckusick return (ENOTTY); 72941480Smckusick } 73041480Smckusick return (0); 73141480Smckusick } 73241480Smckusick 73341480Smckusick dcmparam(tp, t) 73441480Smckusick register struct tty *tp; 73541480Smckusick register struct termios *t; 73641480Smckusick { 73741480Smckusick register struct dcmdevice *dcm; 73842354Smckusick register int port, mode, cflag = t->c_cflag; 73941480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); 74042354Smckusick 74141480Smckusick /* check requested parameters */ 74241480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 74341480Smckusick return(EINVAL); 74441480Smckusick /* and copy to tty */ 74541480Smckusick tp->t_ispeed = t->c_ispeed; 74641480Smckusick tp->t_ospeed = t->c_ospeed; 74741480Smckusick tp->t_cflag = cflag; 74841480Smckusick if (ospeed == 0) { 74942354Smckusick (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET); 75042354Smckusick return(0); 75141480Smckusick } 75242354Smckusick 75342354Smckusick mode = 0; 75441480Smckusick switch (cflag&CSIZE) { 75541480Smckusick case CS5: 75641480Smckusick mode = LC_5BITS; break; 75741480Smckusick case CS6: 75841480Smckusick mode = LC_6BITS; break; 75941480Smckusick case CS7: 76041480Smckusick mode = LC_7BITS; break; 76141480Smckusick case CS8: 76241480Smckusick mode = LC_8BITS; break; 76341480Smckusick } 76441480Smckusick if (cflag&PARENB) { 76541480Smckusick if (cflag&PARODD) 76641480Smckusick mode |= LC_PODD; 76741480Smckusick else 76841480Smckusick mode |= LC_PEVEN; 76941480Smckusick } 77041480Smckusick if (cflag&CSTOPB) 77141480Smckusick mode |= LC_2STOP; 77241480Smckusick else 77341480Smckusick mode |= LC_1STOP; 77441480Smckusick #ifdef DEBUG 77541480Smckusick if (dcmdebug & DDB_PARAM) 77642354Smckusick printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n", 77742354Smckusick UNIT(tp->t_dev), cflag, mode, tp->t_ospeed, 77842354Smckusick DCM_USPERCH(tp->t_ospeed)); 77941480Smckusick #endif 78042354Smckusick 78142354Smckusick port = PORT(tp->t_dev); 78242354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)]; 78342354Smckusick /* 78442354Smckusick * Wait for transmitter buffer to empty. 78542354Smckusick */ 78641480Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 78742354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed)); 78842354Smckusick /* 78942354Smckusick * Make changes known to hardware. 79042354Smckusick */ 79142354Smckusick dcm->dcm_data[port].dcm_baud = ospeed; 79241480Smckusick dcm->dcm_data[port].dcm_conf = mode; 79341480Smckusick SEM_LOCK(dcm); 79442354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 79542354Smckusick dcm->dcm_cr |= (1 << port); 79641480Smckusick SEM_UNLOCK(dcm); 79742354Smckusick /* 79849130Skarels * Delay for config change to take place. Weighted by baud. 79942354Smckusick * XXX why do we do this? 80042354Smckusick */ 80142354Smckusick DELAY(16 * DCM_USPERCH(tp->t_ospeed)); 80242354Smckusick return(0); 80341480Smckusick } 80441480Smckusick 80541480Smckusick dcmstart(tp) 80641480Smckusick register struct tty *tp; 80741480Smckusick { 80841480Smckusick register struct dcmdevice *dcm; 80942354Smckusick register struct dcmpreg *pp; 81042354Smckusick register struct dcmtfifo *fifo; 81142354Smckusick register char *bp; 81242354Smckusick register unsigned tail, next; 81342354Smckusick register int port, nch; 81442354Smckusick unsigned head; 81542354Smckusick char buf[16]; 81642354Smckusick int s; 81742354Smckusick #ifdef IOSTATS 81842354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)]; 81942354Smckusick int tch = 0; 82042354Smckusick #endif 82142354Smckusick 82241480Smckusick s = spltty(); 82342354Smckusick #ifdef IOSTATS 82442354Smckusick dsp->xints++; 82542354Smckusick #endif 82641480Smckusick #ifdef DEBUG 82741480Smckusick if (dcmdebug & DDB_OUTPUT) 82842354Smckusick printf("dcmstart(%d): state %x flags %x outcc %d\n", 82942354Smckusick UNIT(tp->t_dev), tp->t_state, tp->t_flags, 83042354Smckusick tp->t_outq.c_cc); 83141480Smckusick #endif 83241480Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 83341480Smckusick goto out; 83441480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 83541480Smckusick if (tp->t_state&TS_ASLEEP) { 83641480Smckusick tp->t_state &= ~TS_ASLEEP; 83741480Smckusick wakeup((caddr_t)&tp->t_outq); 83841480Smckusick } 83941480Smckusick if (tp->t_wsel) { 84041480Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 84141480Smckusick tp->t_wsel = 0; 84241480Smckusick tp->t_state &= ~TS_WCOLL; 84341480Smckusick } 84441480Smckusick } 84542354Smckusick if (tp->t_outq.c_cc == 0) { 84642354Smckusick #ifdef IOSTATS 84742354Smckusick dsp->xempty++; 84842354Smckusick #endif 84942354Smckusick goto out; 85042354Smckusick } 85142354Smckusick 85242354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)]; 85342354Smckusick port = PORT(tp->t_dev); 85442354Smckusick pp = dcm_preg(dcm, port); 85542354Smckusick tail = pp->t_tail & TX_MASK; 85642354Smckusick next = (tail + 1) & TX_MASK; 85742354Smckusick head = pp->t_head & TX_MASK; 85842354Smckusick if (head == next) 85942354Smckusick goto out; 86042354Smckusick fifo = &dcm->dcm_tfifos[3-port][tail]; 86142354Smckusick again: 86242354Smckusick nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK); 86342354Smckusick #ifdef IOSTATS 86442354Smckusick tch += nch; 86542354Smckusick #endif 86641480Smckusick #ifdef DEBUG 86742354Smckusick if (dcmdebug & DDB_OUTPUT) 86842354Smckusick printf("\thead %x tail %x nch %d\n", head, tail, nch); 86941480Smckusick #endif 87042354Smckusick /* 87142354Smckusick * Loop transmitting all the characters we can. 87242354Smckusick */ 87342354Smckusick for (bp = buf; --nch >= 0; bp++) { 87442354Smckusick fifo->data_char = *bp; 87542354Smckusick pp->t_tail = next; 87642354Smckusick /* 87742354Smckusick * If this is the first character, 87842354Smckusick * get the hardware moving right now. 87942354Smckusick */ 88042354Smckusick if (bp == buf) { 88142354Smckusick tp->t_state |= TS_BUSY; 88242354Smckusick SEM_LOCK(dcm); 88342354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 88442354Smckusick dcm->dcm_cr |= (1 << port); 88542354Smckusick SEM_UNLOCK(dcm); 88642354Smckusick } 88741480Smckusick tail = next; 88842354Smckusick fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; 88942354Smckusick next = (next + 1) & TX_MASK; 89041480Smckusick } 89142354Smckusick /* 89242354Smckusick * Head changed while we were loading the buffer, 89342354Smckusick * go back and load some more if we can. 89442354Smckusick */ 89542354Smckusick if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) { 89642354Smckusick #ifdef IOSTATS 89742354Smckusick dsp->xrestarts++; 89842354Smckusick #endif 89942354Smckusick head = pp->t_head & TX_MASK; 90042354Smckusick goto again; 90142354Smckusick } 90249130Skarels 90342354Smckusick /* 90442354Smckusick * Kick it one last time in case it finished while we were 90544317Shibler * loading the last bunch. 90642354Smckusick */ 90742354Smckusick if (bp > &buf[1]) { 90841480Smckusick tp->t_state |= TS_BUSY; 90941480Smckusick SEM_LOCK(dcm); 91042354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 91142354Smckusick dcm->dcm_cr |= (1 << port); 91242354Smckusick SEM_UNLOCK(dcm); 91342354Smckusick } 91441480Smckusick #ifdef DEBUG 91541480Smckusick if (dcmdebug & DDB_INTR) 91643407Shibler printf("dcmstart(%d): head %x tail %x outqcc %d\n", 91743407Shibler UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc); 91841480Smckusick #endif 91941480Smckusick out: 92042354Smckusick #ifdef IOSTATS 92142354Smckusick dsp->xchars += tch; 92242354Smckusick if (tch <= DCMXBSIZE) 92342354Smckusick dsp->xsilo[tch]++; 92442354Smckusick else 92542354Smckusick dsp->xsilo[DCMXBSIZE+1]++; 92642354Smckusick #endif 92741480Smckusick splx(s); 92841480Smckusick } 92941480Smckusick 93041480Smckusick /* 93141480Smckusick * Stop output on a line. 93241480Smckusick */ 93341480Smckusick dcmstop(tp, flag) 93441480Smckusick register struct tty *tp; 93541480Smckusick { 93641480Smckusick int s; 93741480Smckusick 93841480Smckusick s = spltty(); 93941480Smckusick if (tp->t_state & TS_BUSY) { 94042354Smckusick /* XXX is there some way to safely stop transmission? */ 94144317Shibler if ((tp->t_state&TS_TTSTOP) == 0) 94241480Smckusick tp->t_state |= TS_FLUSH; 94341480Smckusick } 94441480Smckusick splx(s); 94541480Smckusick } 94641480Smckusick 94745750Smckusick /* 94845750Smckusick * Modem control 94945750Smckusick */ 95041480Smckusick dcmmctl(dev, bits, how) 95141480Smckusick dev_t dev; 95241480Smckusick int bits, how; 95341480Smckusick { 95441480Smckusick register struct dcmdevice *dcm; 95545750Smckusick int s, unit, hit = 0; 95641480Smckusick 95745750Smckusick unit = UNIT(dev); 95845750Smckusick #ifdef DEBUG 95945750Smckusick if (dcmdebug & DDB_MODEM) 96045750Smckusick printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", 96145750Smckusick BOARD(unit), unit, bits, how); 96245750Smckusick #endif 96341480Smckusick 96445750Smckusick dcm = dcm_addr[BOARD(unit)]; 96541480Smckusick s = spltty(); 96641480Smckusick switch (how) { 96741480Smckusick 96841480Smckusick case DMSET: 96945750Smckusick dcm_modem[unit]->mdmout = bits; 97041480Smckusick hit++; 97141480Smckusick break; 97241480Smckusick 97341480Smckusick case DMBIS: 97445750Smckusick dcm_modem[unit]->mdmout |= bits; 97541480Smckusick hit++; 97641480Smckusick break; 97741480Smckusick 97841480Smckusick case DMBIC: 97945750Smckusick dcm_modem[unit]->mdmout &= ~bits; 98041480Smckusick hit++; 98141480Smckusick break; 98241480Smckusick 98341480Smckusick case DMGET: 98445750Smckusick bits = dcm_modem[unit]->mdmin; 98541480Smckusick break; 98641480Smckusick } 98741480Smckusick if (hit) { 98841480Smckusick SEM_LOCK(dcm); 98945750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 99041480Smckusick dcm->dcm_cr |= CR_MODM; 99141480Smckusick SEM_UNLOCK(dcm); 99242354Smckusick DELAY(10); /* delay until done */ 99341480Smckusick (void) splx(s); 99441480Smckusick } 99541480Smckusick return(bits); 99641480Smckusick } 99741480Smckusick 99842354Smckusick /* 99942354Smckusick * Set board to either interrupt per-character or at a fixed interval. 100042354Smckusick */ 100142354Smckusick dcmsetischeme(brd, flags) 100242354Smckusick int brd, flags; 100341480Smckusick { 100442354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 100542354Smckusick register struct dcmischeme *dis = &dcmischeme[brd]; 100641480Smckusick register int i; 100742354Smckusick u_char mask; 100842354Smckusick int perchar = flags & DIS_PERCHAR; 100941480Smckusick 101041480Smckusick #ifdef DEBUG 101142354Smckusick if (dcmdebug & DDB_INTSCHM) 101242354Smckusick printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", 101342354Smckusick brd, perchar, dis->dis_perchar, 101442354Smckusick dis->dis_intr, dis->dis_char); 101542354Smckusick if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { 101642354Smckusick printf("dcmsetischeme(%d): redundent request %d\n", 101742354Smckusick brd, perchar); 101842354Smckusick return; 101942354Smckusick } 102042354Smckusick #endif 102142354Smckusick /* 102242354Smckusick * If perchar is non-zero, we enable interrupts on all characters 102342354Smckusick * otherwise we disable perchar interrupts and use periodic 102442354Smckusick * polling interrupts. 102542354Smckusick */ 102642354Smckusick dis->dis_perchar = perchar; 102742354Smckusick mask = perchar ? 0xf : 0x0; 102842354Smckusick for (i = 0; i < 256; i++) 102942354Smckusick dcm->dcm_bmap[i].data_data = mask; 103042354Smckusick /* 103142354Smckusick * Don't slow down tandem mode, interrupt on flow control 103242354Smckusick * chars for any port on the board. 103342354Smckusick */ 103442354Smckusick if (!perchar) { 103542354Smckusick register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)]; 103642354Smckusick int c; 103742354Smckusick 103842354Smckusick for (i = 0; i < 4; i++, tp++) { 103942354Smckusick if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) 104042354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 104142354Smckusick if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) 104242354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 104341480Smckusick } 104441480Smckusick } 104542354Smckusick /* 104642354Smckusick * Board starts with timer disabled so if first call is to 104742354Smckusick * set perchar mode then we don't want to toggle the timer. 104842354Smckusick */ 104942354Smckusick if (flags == (DIS_RESET|DIS_PERCHAR)) 105041480Smckusick return; 105142354Smckusick /* 105242354Smckusick * Toggle card 16.7ms interrupts (we first make sure that card 105342354Smckusick * has cleared the bit so it will see the toggle). 105442354Smckusick */ 105542354Smckusick while (dcm->dcm_cr & CR_TIMER) 105642354Smckusick ; 105741480Smckusick SEM_LOCK(dcm); 105842354Smckusick dcm->dcm_cr |= CR_TIMER; 105941480Smckusick SEM_UNLOCK(dcm); 106041480Smckusick } 106141480Smckusick 106241480Smckusick /* 106341480Smckusick * Following are all routines needed for DCM to act as console 106441480Smckusick */ 106545788Sbostic #include "../hp300/cons.h" 106641480Smckusick 106742354Smckusick dcmcnprobe(cp) 106842354Smckusick struct consdev *cp; 106941480Smckusick { 107042354Smckusick register struct hp_hw *hw; 107149130Skarels int unit; 107241480Smckusick 107349130Skarels /* locate the major number */ 107449130Skarels for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) 107549130Skarels if (cdevsw[dcmmajor].d_open == dcmopen) 107649130Skarels break; 107749130Skarels 107842354Smckusick /* 107942354Smckusick * Implicitly assigns the lowest select code DCM card found to be 108042354Smckusick * logical unit 0 (actually CONUNIT). If your config file does 108142354Smckusick * anything different, you're screwed. 108242354Smckusick */ 108342354Smckusick for (hw = sc_table; hw->hw_type; hw++) 108449301Shibler if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva)) 108542354Smckusick break; 108649301Shibler if (!HW_ISDEV(hw, D_COMMDCM)) { 108742354Smckusick cp->cn_pri = CN_DEAD; 108842354Smckusick return; 108942354Smckusick } 109042354Smckusick unit = CONUNIT; 109149301Shibler dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva; 109241480Smckusick 109342354Smckusick /* initialize required fields */ 109449130Skarels cp->cn_dev = makedev(dcmmajor, unit); 109542354Smckusick cp->cn_tp = &dcm_tty[unit]; 109642354Smckusick switch (dcm_addr[BOARD(unit)]->dcm_rsid) { 109742354Smckusick case DCMID: 109842354Smckusick cp->cn_pri = CN_NORMAL; 109942354Smckusick break; 110042354Smckusick case DCMID|DCMCON: 110142354Smckusick cp->cn_pri = CN_REMOTE; 110242354Smckusick break; 110342354Smckusick default: 110442354Smckusick cp->cn_pri = CN_DEAD; 110549130Skarels return; 110642354Smckusick } 110749130Skarels /* 110849130Skarels * If dcmconsole is initialized, raise our priority. 110949130Skarels */ 111049130Skarels if (dcmconsole == UNIT(unit)) 111149130Skarels cp->cn_pri = CN_REMOTE; 111249130Skarels #ifdef KGDB 111349130Skarels if (major(kgdb_dev) == 2) /* XXX */ 111449130Skarels kgdb_dev = makedev(dcmmajor, minor(kgdb_dev)); 111549301Shibler #ifdef KGDB_CHEAT 111649130Skarels /* 111749130Skarels * This doesn't currently work, at least not with ite consoles; 111849130Skarels * the console hasn't been initialized yet. 111949130Skarels */ 112049130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { 112149130Skarels (void) dcminit(kgdb_dev, kgdb_rate); 112249130Skarels if (kgdb_debug_init) { 112349130Skarels /* 112449130Skarels * We assume that console is ready for us... 112549130Skarels * this assumes that a dca or ite console 112649130Skarels * has been selected already and will init 112749130Skarels * on the first putc. 112849130Skarels */ 112949130Skarels printf("dcm%d: ", UNIT(kgdb_dev)); 113049130Skarels kgdb_connect(1); 113149130Skarels } 113249130Skarels } 113349130Skarels #endif 113449130Skarels #endif 113542354Smckusick } 113642354Smckusick 113742354Smckusick dcmcninit(cp) 113842354Smckusick struct consdev *cp; 113942354Smckusick { 114042354Smckusick dcminit(cp->cn_dev, dcmdefaultrate); 114149130Skarels dcmconsinit = 1; 114242354Smckusick dcmconsole = UNIT(cp->cn_dev); 114342354Smckusick } 114442354Smckusick 114542354Smckusick dcminit(dev, rate) 114642354Smckusick dev_t dev; 114742354Smckusick int rate; 114842354Smckusick { 114942354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 115042354Smckusick int s, mode, port; 115142354Smckusick 115242354Smckusick port = PORT(dev); 115342354Smckusick mode = LC_8BITS | LC_1STOP; 115441480Smckusick s = splhigh(); 115542354Smckusick /* 115642354Smckusick * Wait for transmitter buffer to empty. 115742354Smckusick */ 115842354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 115942354Smckusick DELAY(DCM_USPERCH(rate)); 116042354Smckusick /* 116142354Smckusick * Make changes known to hardware. 116242354Smckusick */ 116342354Smckusick dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); 116442354Smckusick dcm->dcm_data[port].dcm_conf = mode; 116542354Smckusick SEM_LOCK(dcm); 116642354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 116742354Smckusick dcm->dcm_cr |= (1 << port); 116842354Smckusick SEM_UNLOCK(dcm); 116942354Smckusick /* 117049130Skarels * Delay for config change to take place. Weighted by baud. 117142354Smckusick * XXX why do we do this? 117242354Smckusick */ 117342354Smckusick DELAY(16 * DCM_USPERCH(rate)); 117441480Smckusick splx(s); 117541480Smckusick } 117641480Smckusick 117741480Smckusick dcmcngetc(dev) 117842354Smckusick dev_t dev; 117941480Smckusick { 118042354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 118142354Smckusick register struct dcmrfifo *fifo; 118242354Smckusick register struct dcmpreg *pp; 118342354Smckusick register unsigned head; 118442354Smckusick int s, c, stat, port; 118542354Smckusick 118642354Smckusick port = PORT(dev); 118742354Smckusick pp = dcm_preg(dcm, port); 118842354Smckusick s = splhigh(); 118942354Smckusick head = pp->r_head & RX_MASK; 119042354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 119142354Smckusick while (head == (pp->r_tail & RX_MASK)) 119242354Smckusick ; 119342354Smckusick /* 119442354Smckusick * If board interrupts are enabled, just let our received char 119542354Smckusick * interrupt through in case some other port on the board was 119642354Smckusick * busy. Otherwise we must clear the interrupt. 119742354Smckusick */ 119842354Smckusick SEM_LOCK(dcm); 119942354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) 120042354Smckusick stat = dcm->dcm_iir; 120142354Smckusick SEM_UNLOCK(dcm); 120242354Smckusick c = fifo->data_char; 120342354Smckusick stat = fifo->data_stat; 120442354Smckusick pp->r_head = (head + 2) & RX_MASK; 120542354Smckusick splx(s); 120642354Smckusick return(c); 120741480Smckusick } 120841480Smckusick 120941480Smckusick /* 121041480Smckusick * Console kernel output character routine. 121141480Smckusick */ 121241480Smckusick dcmcnputc(dev, c) 121341480Smckusick dev_t dev; 121442354Smckusick int c; 121541480Smckusick { 121641480Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 121742354Smckusick register struct dcmpreg *pp; 121842354Smckusick unsigned tail; 121942354Smckusick int s, port, stat; 122041480Smckusick 122142354Smckusick port = PORT(dev); 122242354Smckusick pp = dcm_preg(dcm, port); 122342354Smckusick s = splhigh(); 122442354Smckusick #ifdef KGDB 122542354Smckusick if (dev != kgdb_dev) 122642354Smckusick #endif 122749130Skarels if (dcmconsinit == 0) { 122842354Smckusick (void) dcminit(dev, dcmdefaultrate); 122949130Skarels dcmconsinit = 1; 123042354Smckusick } 123142354Smckusick tail = pp->t_tail & TX_MASK; 123242354Smckusick while (tail != (pp->t_head & TX_MASK)) 123342354Smckusick ; 123442354Smckusick dcm->dcm_tfifos[3-port][tail].data_char = c; 123542354Smckusick pp->t_tail = tail = (tail + 1) & TX_MASK; 123641480Smckusick SEM_LOCK(dcm); 123742354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 123842354Smckusick dcm->dcm_cr |= (1 << port); 123941480Smckusick SEM_UNLOCK(dcm); 124042354Smckusick while (tail != (pp->t_head & TX_MASK)) 124142354Smckusick ; 124242354Smckusick /* 124342354Smckusick * If board interrupts are enabled, just let our completion 124442354Smckusick * interrupt through in case some other port on the board 124542354Smckusick * was busy. Otherwise we must clear the interrupt. 124642354Smckusick */ 124742354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) { 124842354Smckusick SEM_LOCK(dcm); 124942354Smckusick stat = dcm->dcm_iir; 125042354Smckusick SEM_UNLOCK(dcm); 125142354Smckusick } 125241480Smckusick splx(s); 125341480Smckusick } 125441480Smckusick #endif 1255