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 * 1245750Smckusick * from: $Hdr: dcm.c 1.1 90/07/09$ 1341480Smckusick * 14*49130Skarels * @(#)dcm.c 7.11 (Berkeley) 05/04/91 1541480Smckusick */ 1641480Smckusick 1741480Smckusick /* 1842354Smckusick * TODO: 1942354Smckusick * Timeouts 20*49130Skarels * 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" 32*49130Skarels #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" 42*49130Skarels #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 */ 110*49130Skarels #ifdef DCMCONSOLE 111*49130Skarels int dcmconsole = DCMCONSOLE; 112*49130Skarels #else 11342354Smckusick int dcmconsole = -1; 114*49130Skarels #endif 115*49130Skarels int dcmconsinit; 11642354Smckusick int dcmdefaultrate = DEFAULT_BAUD_RATE; 11742354Smckusick int dcmconbrdbusy = 0; 118*49130Skarels int dcmmajor; 11942354Smckusick extern struct tty *constty; 12042354Smckusick 12142354Smckusick #ifdef KGDB 12242354Smckusick /* 12342354Smckusick * Kernel GDB support 12442354Smckusick */ 125*49130Skarels #include "machine/remote-sl.h" 126*49130Skarels 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 225*49130Skarels 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 */ 228*49130Skarels /* 229*49130Skarels * The following could potentially be replaced 230*49130Skarels * by the corresponding code in dcmcnprobe. 231*49130Skarels */ 23242354Smckusick else { 23342354Smckusick (void) dcminit(kgdb_dev, kgdb_rate); 23442354Smckusick if (kgdb_debug_init) { 235*49130Skarels printf("dcm%d: ", UNIT(kgdb_dev)); 236*49130Skarels kgdb_connect(1); 23742354Smckusick } else 238*49130Skarels printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev)); 23942354Smckusick } 240*49130Skarels /* end could be replaced */ 24142354Smckusick } 24242354Smckusick #endif 24342354Smckusick if (dcmistype == DIS_TIMER) 24442354Smckusick dcmsetischeme(brd, DIS_RESET|DIS_TIMER); 24542354Smckusick else 24642354Smckusick dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR); 24745750Smckusick 24845750Smckusick /* load pointers to modem control */ 24945750Smckusick dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0; 25045750Smckusick dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1; 25145750Smckusick dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2; 25245750Smckusick dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3; 25345750Smckusick /* set DCD (modem) and CTS (flow control) on all ports */ 25445750Smckusick for (i = 0; i < 4; i++) 25545750Smckusick dcm_modem[MKUNIT(brd, i)]->mdmmsk = MI_CD|MI_CTS; 25645750Smckusick 25742354Smckusick dcm->dcm_ic = IC_IE; /* turn all interrupts on */ 25841480Smckusick /* 25941480Smckusick * Need to reset baud rate, etc. of next print so reset dcmconsole. 26041480Smckusick * Also make sure console is always "hardwired" 26141480Smckusick */ 26242354Smckusick if (isconsole) { 263*49130Skarels dcmconsinit = 0; 26441480Smckusick dcmsoftCAR[brd] |= (1 << PORT(dcmconsole)); 26541480Smckusick } 26641480Smckusick return (1); 26741480Smckusick } 26841480Smckusick 269*49130Skarels /* ARGSUSED */ 270*49130Skarels #ifdef __STDC__ 271*49130Skarels dcmopen(dev_t dev, int flag, int mode, struct proc *p) 272*49130Skarels #else 273*49130Skarels dcmopen(dev, flag, mode, p) 27441480Smckusick dev_t dev; 275*49130Skarels int flag, mode; 276*49130Skarels struct proc *p; 277*49130Skarels #endif 27841480Smckusick { 27941480Smckusick register struct tty *tp; 28041480Smckusick register int unit, brd; 28144762Skarels int error = 0; 28241480Smckusick 28341480Smckusick unit = UNIT(dev); 28441480Smckusick brd = BOARD(unit); 28542354Smckusick if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0) 28641480Smckusick return (ENXIO); 28741480Smckusick tp = &dcm_tty[unit]; 28841480Smckusick tp->t_oproc = dcmstart; 28942354Smckusick tp->t_param = dcmparam; 29041480Smckusick tp->t_dev = dev; 29141480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 29242950Smarc tp->t_state |= TS_WOPEN; 29341480Smckusick ttychars(tp); 294*49130Skarels if (tp->t_ispeed == 0) { 295*49130Skarels tp->t_iflag = TTYDEF_IFLAG; 296*49130Skarels tp->t_oflag = TTYDEF_OFLAG; 297*49130Skarels tp->t_cflag = TTYDEF_CFLAG; 298*49130Skarels tp->t_lflag = TTYDEF_LFLAG; 299*49130Skarels tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 300*49130Skarels } 30142354Smckusick (void) dcmparam(tp, &tp->t_termios); 30241480Smckusick ttsetwater(tp); 303*49130Skarels } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 30441480Smckusick return (EBUSY); 30545750Smckusick (void) dcmmctl(dev, MO_ON, DMSET); /* enable port */ 306*49130Skarels if ((dcmsoftCAR[brd] & (1 << PORT(unit))) || 307*49130Skarels (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)) 30841480Smckusick tp->t_state |= TS_CARR_ON; 30945750Smckusick #ifdef DEBUG 31045750Smckusick if (dcmdebug & DDB_MODEM) 31145750Smckusick printf("dcm%d: dcmopen port %d softcarr %c\n", 31245750Smckusick brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0'); 31345750Smckusick #endif 31441480Smckusick (void) spltty(); 31544295Shibler while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 31641480Smckusick (tp->t_state & TS_CARR_ON) == 0) { 31741480Smckusick tp->t_state |= TS_WOPEN; 31844295Shibler if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 31944295Shibler ttopen, 0)) 32044295Shibler break; 32141480Smckusick } 32241480Smckusick (void) spl0(); 32345750Smckusick 32441480Smckusick #ifdef DEBUG 32541480Smckusick if (dcmdebug & DDB_OPENCLOSE) 32641480Smckusick printf("dcmopen: u %x st %x fl %x\n", 32741480Smckusick unit, tp->t_state, tp->t_flags); 32841480Smckusick #endif 32944295Shibler if (error == 0) 33044295Shibler error = (*linesw[tp->t_line].l_open)(dev, tp); 33144295Shibler return (error); 33241480Smckusick } 33341480Smckusick 33441480Smckusick /*ARGSUSED*/ 33541480Smckusick dcmclose(dev, flag) 33641480Smckusick dev_t dev; 33741480Smckusick { 33841480Smckusick register struct tty *tp; 33941480Smckusick int unit; 34041480Smckusick 34141480Smckusick unit = UNIT(dev); 34241480Smckusick tp = &dcm_tty[unit]; 34341480Smckusick (*linesw[tp->t_line].l_close)(tp); 344*49130Skarels #ifdef KGDB 345*49130Skarels if (dev != kgdb_dev) 346*49130Skarels #endif 347*49130Skarels (void) dcmmctl(dev, MO_OFF, DMSET); 348*49130Skarels if (tp->t_state & TS_HUPCLS) 349*49130Skarels (*linesw[tp->t_line].l_modem)(tp, 0); 35041480Smckusick #ifdef DEBUG 35141480Smckusick if (dcmdebug & DDB_OPENCLOSE) 35241480Smckusick printf("dcmclose: u %x st %x fl %x\n", 35341480Smckusick unit, tp->t_state, tp->t_flags); 35441480Smckusick #endif 35541480Smckusick ttyclose(tp); 35641480Smckusick return(0); 35741480Smckusick } 35841480Smckusick 35941480Smckusick dcmread(dev, uio, flag) 36041480Smckusick dev_t dev; 36141480Smckusick struct uio *uio; 36241480Smckusick { 36341480Smckusick register struct tty *tp; 36441480Smckusick 36541480Smckusick tp = &dcm_tty[UNIT(dev)]; 36641480Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 36741480Smckusick } 36841480Smckusick 36941480Smckusick dcmwrite(dev, uio, flag) 37041480Smckusick dev_t dev; 37141480Smckusick struct uio *uio; 37241480Smckusick { 37341480Smckusick int unit = UNIT(dev); 37441480Smckusick register struct tty *tp; 37541480Smckusick 37641480Smckusick tp = &dcm_tty[unit]; 37742354Smckusick /* 37842354Smckusick * XXX we disallow virtual consoles if the physical console is 37942354Smckusick * a serial port. This is in case there is a display attached that 38042354Smckusick * is not the console. In that situation we don't need/want the X 38142354Smckusick * server taking over the console. 38242354Smckusick */ 38342354Smckusick if (constty && unit == dcmconsole) 38442354Smckusick constty = NULL; 38541480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 38641480Smckusick } 38741480Smckusick 38841480Smckusick dcmintr(brd) 38941480Smckusick register int brd; 39041480Smckusick { 39142354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 39242354Smckusick register struct dcmischeme *dis; 39345750Smckusick register int unit = MKUNIT(brd, 0); 39445750Smckusick register int code, i; 39545750Smckusick int pcnd[4], mcode, mcnd[4]; 39641480Smckusick 39742354Smckusick /* 39842354Smckusick * Do all guarded register accesses right off to minimize 39942354Smckusick * block out of hardware. 40042354Smckusick */ 40141480Smckusick SEM_LOCK(dcm); 40241480Smckusick if ((dcm->dcm_ic & IC_IR) == 0) { 40341480Smckusick SEM_UNLOCK(dcm); 40441480Smckusick return(0); 40541480Smckusick } 40641480Smckusick for (i = 0; i < 4; i++) { 40741480Smckusick pcnd[i] = dcm->dcm_icrtab[i].dcm_data; 40841480Smckusick dcm->dcm_icrtab[i].dcm_data = 0; 40945750Smckusick mcnd[i] = dcm_modem[unit+i]->mdmin; 41041480Smckusick } 41141480Smckusick code = dcm->dcm_iir & IIR_MASK; 41242354Smckusick dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ 41345750Smckusick mcode = dcm->dcm_modemintr; 41445750Smckusick dcm->dcm_modemintr = 0; 41541480Smckusick SEM_UNLOCK(dcm); 41641480Smckusick 41741480Smckusick #ifdef DEBUG 41845750Smckusick if (dcmdebug & DDB_INTR) { 41945750Smckusick printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ", 42045750Smckusick brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); 42145750Smckusick printf("miir %x mc %x/%x/%x/%x\n", 42245750Smckusick mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); 42345750Smckusick } 42441480Smckusick #endif 42542354Smckusick if (code & IIR_TIMEO) 42642354Smckusick dcmrint(brd, dcm); 42741480Smckusick if (code & IIR_PORT0) 42845750Smckusick dcmpint(unit+0, pcnd[0], dcm); 42941480Smckusick if (code & IIR_PORT1) 43045750Smckusick dcmpint(unit+1, pcnd[1], dcm); 43141480Smckusick if (code & IIR_PORT2) 43245750Smckusick dcmpint(unit+2, pcnd[2], dcm); 43341480Smckusick if (code & IIR_PORT3) 43445750Smckusick dcmpint(unit+3, pcnd[3], dcm); 43545750Smckusick if (code & IIR_MODM) { 43645750Smckusick if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ 43745750Smckusick dcmmint(unit+0, mcnd[0], dcm); 43845750Smckusick if (mcode & 0x2) 43945750Smckusick dcmmint(unit+1, mcnd[1], dcm); 44045750Smckusick if (mcode & 0x4) 44145750Smckusick dcmmint(unit+2, mcnd[2], dcm); 44245750Smckusick if (mcode & 0x8) 44345750Smckusick dcmmint(unit+3, mcnd[3], dcm); 44445750Smckusick } 44541480Smckusick 44642354Smckusick dis = &dcmischeme[brd]; 44741480Smckusick /* 44842354Smckusick * Chalk up a receiver interrupt if the timer running or one of 44942354Smckusick * the ports reports a special character interrupt. 45041480Smckusick */ 45142354Smckusick if ((code & IIR_TIMEO) || 45242354Smckusick ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) 45342354Smckusick dis->dis_intr++; 45442354Smckusick /* 45542354Smckusick * See if it is time to check/change the interrupt rate. 45642354Smckusick */ 45742354Smckusick if (dcmistype < 0 && 45845750Smckusick (i = time.tv_sec - dis->dis_time) >= dcminterval) { 45941480Smckusick /* 46042354Smckusick * If currently per-character and averaged over 70 interrupts 46142354Smckusick * per-second (66 is threshold of 600 baud) in last interval, 46242354Smckusick * switch to timer mode. 46342354Smckusick * 46442354Smckusick * XXX decay counts ala load average to avoid spikes? 46541480Smckusick */ 46645750Smckusick if (dis->dis_perchar && dis->dis_intr > 70 * i) 46742354Smckusick dcmsetischeme(brd, DIS_TIMER); 46842354Smckusick /* 46942354Smckusick * If currently using timer and had more interrupts than 47042354Smckusick * received characters in the last interval, switch back 47142354Smckusick * to per-character. Note that after changing to per-char 47242354Smckusick * we must process any characters already in the queue 47342354Smckusick * since they may have arrived before the bitmap was setup. 47442354Smckusick * 47542354Smckusick * XXX decay counts? 47642354Smckusick */ 47742354Smckusick else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { 47842354Smckusick dcmsetischeme(brd, DIS_PERCHAR); 47941480Smckusick dcmrint(brd, dcm); 48041480Smckusick } 48142354Smckusick dis->dis_intr = dis->dis_char = 0; 48242354Smckusick dis->dis_time = time.tv_sec; 48342354Smckusick } 48441480Smckusick return(1); 48541480Smckusick } 48641480Smckusick 48741480Smckusick /* 48841480Smckusick * Port interrupt. Can be two things: 48941480Smckusick * First, it might be a special character (exception interrupt); 49041480Smckusick * Second, it may be a buffer empty (transmit interrupt); 49141480Smckusick */ 49241480Smckusick dcmpint(unit, code, dcm) 49341480Smckusick int unit, code; 49442354Smckusick struct dcmdevice *dcm; 49541480Smckusick { 49642354Smckusick struct tty *tp = &dcm_tty[unit]; 49741480Smckusick 49842354Smckusick if (code & IT_SPEC) 49942354Smckusick dcmreadbuf(unit, dcm, tp); 50041480Smckusick if (code & IT_TX) 50142354Smckusick dcmxint(unit, dcm, tp); 50241480Smckusick } 50341480Smckusick 50441480Smckusick dcmrint(brd, dcm) 50541480Smckusick int brd; 50641480Smckusick register struct dcmdevice *dcm; 50741480Smckusick { 50842354Smckusick register int i, unit; 50941480Smckusick register struct tty *tp; 51041480Smckusick 51141480Smckusick unit = MKUNIT(brd, 0); 51241480Smckusick tp = &dcm_tty[unit]; 51342354Smckusick for (i = 0; i < 4; i++, tp++, unit++) 51442354Smckusick dcmreadbuf(unit, dcm, tp); 51541480Smckusick } 51641480Smckusick 51742354Smckusick dcmreadbuf(unit, dcm, tp) 51841480Smckusick int unit; 51941480Smckusick register struct dcmdevice *dcm; 52041480Smckusick register struct tty *tp; 52141480Smckusick { 52242354Smckusick int port = PORT(unit); 52342354Smckusick register struct dcmpreg *pp = dcm_preg(dcm, port); 52442354Smckusick register struct dcmrfifo *fifo; 52541480Smckusick register int c, stat; 52641480Smckusick register unsigned head; 52742354Smckusick int nch = 0; 52842354Smckusick #ifdef IOSTATS 52942354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(unit)]; 53041480Smckusick 53142354Smckusick dsp->rints++; 53242354Smckusick #endif 53343407Shibler if ((tp->t_state & TS_ISOPEN) == 0) { 53442354Smckusick #ifdef KGDB 535*49130Skarels if ((makedev(dcmmajor, unit) == kgdb_dev) && 53642354Smckusick (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && 537*49130Skarels dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_END) { 53842354Smckusick pp->r_head = (head + 2) & RX_MASK; 539*49130Skarels kgdb_connect(0); /* trap into kgdb */ 54042354Smckusick return; 54142354Smckusick } 542*49130Skarels #endif /* KGDB */ 54342354Smckusick pp->r_head = pp->r_tail & RX_MASK; 54442354Smckusick return; 54542354Smckusick } 54641480Smckusick 54742354Smckusick head = pp->r_head & RX_MASK; 54842354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 54942354Smckusick /* 55042354Smckusick * XXX upper bound on how many chars we will take in one swallow? 55142354Smckusick */ 55242354Smckusick while (head != (pp->r_tail & RX_MASK)) { 55342354Smckusick /* 55442354Smckusick * Get character/status and update head pointer as fast 55542354Smckusick * as possible to make room for more characters. 55642354Smckusick */ 55742354Smckusick c = fifo->data_char; 55842354Smckusick stat = fifo->data_stat; 55941480Smckusick head = (head + 2) & RX_MASK; 56042354Smckusick pp->r_head = head; 56142354Smckusick fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; 56242354Smckusick nch++; 56341480Smckusick 56441480Smckusick #ifdef DEBUG 56541480Smckusick if (dcmdebug & DDB_INPUT) 56642354Smckusick printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n", 56742354Smckusick unit, c&0xFF, c, stat&0xFF, 56842354Smckusick tp->t_flags, head, pp->r_tail); 56941480Smckusick #endif 57042354Smckusick /* 57142354Smckusick * Check for and handle errors 57242354Smckusick */ 57342354Smckusick if (stat & RD_MASK) { 57441480Smckusick #ifdef DEBUG 57542354Smckusick if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) 57642354Smckusick printf("dcmreadbuf(%d): err: c%x('%c') s%x\n", 57742354Smckusick unit, stat, c&0xFF, c); 57841480Smckusick #endif 57941480Smckusick if (stat & (RD_BD | RD_FE)) 58041480Smckusick c |= TTY_FE; 58141480Smckusick else if (stat & RD_PE) 58241480Smckusick c |= TTY_PE; 58341480Smckusick else if (stat & RD_OVF) 58441480Smckusick log(LOG_WARNING, 58542354Smckusick "dcm%d: silo overflow\n", unit); 58641480Smckusick else if (stat & RD_OE) 58741480Smckusick log(LOG_WARNING, 58842354Smckusick "dcm%d: uart overflow\n", unit); 58941480Smckusick } 59041480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 59141480Smckusick } 59242354Smckusick dcmischeme[BOARD(unit)].dis_char += nch; 59342354Smckusick #ifdef IOSTATS 59442354Smckusick dsp->rchars += nch; 59542354Smckusick if (nch <= DCMRBSIZE) 59642354Smckusick dsp->rsilo[nch]++; 59741480Smckusick else 59842354Smckusick dsp->rsilo[DCMRBSIZE+1]++; 59941480Smckusick #endif 60041480Smckusick } 60141480Smckusick 60242354Smckusick dcmxint(unit, dcm, tp) 60341480Smckusick int unit; 60441480Smckusick struct dcmdevice *dcm; 60542354Smckusick register struct tty *tp; 60641480Smckusick { 60741480Smckusick tp->t_state &= ~TS_BUSY; 60841480Smckusick if (tp->t_state & TS_FLUSH) 60941480Smckusick tp->t_state &= ~TS_FLUSH; 610*49130Skarels (*linesw[tp->t_line].l_start)(tp); 61141480Smckusick } 61241480Smckusick 61341480Smckusick dcmmint(unit, mcnd, dcm) 61441480Smckusick register int unit; 61541480Smckusick register struct dcmdevice *dcm; 61641480Smckusick int mcnd; 61741480Smckusick { 61841480Smckusick register struct tty *tp; 61944317Shibler int delta; 62041480Smckusick 62141480Smckusick #ifdef DEBUG 62242354Smckusick if (dcmdebug & DDB_MODEM) 62345750Smckusick printf("dcmmint: port %d mcnd %x mcndlast %x\n", 62444317Shibler unit, mcnd, mcndlast[unit]); 62542354Smckusick #endif 62641480Smckusick tp = &dcm_tty[unit]; 62744317Shibler delta = mcnd ^ mcndlast[unit]; 62844317Shibler mcndlast[unit] = mcnd; 629*49130Skarels if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && 630*49130Skarels (tp->t_flags & CRTSCTS)) { 631*49130Skarels if (mcnd & MI_CTS) { 632*49130Skarels tp->t_state &= ~TS_TTSTOP; 633*49130Skarels ttstart(tp); 634*49130Skarels } else 635*49130Skarels tp->t_state |= TS_TTSTOP; /* inline dcmstop */ 636*49130Skarels } 63744317Shibler if ((delta & MI_CD) && 63844317Shibler (dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) { 63941480Smckusick if (mcnd & MI_CD) 64044317Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1); 64141480Smckusick else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 64245750Smckusick dcm_modem[unit]->mdmout &= ~(MO_DTR|MO_RTS); 64341480Smckusick SEM_LOCK(dcm); 64445750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 64541480Smckusick dcm->dcm_cr |= CR_MODM; 64641480Smckusick SEM_UNLOCK(dcm); 64742354Smckusick DELAY(10); /* time to change lines */ 64841480Smckusick } 64941480Smckusick } 65041480Smckusick } 65141480Smckusick 65241480Smckusick dcmioctl(dev, cmd, data, flag) 65341480Smckusick dev_t dev; 65441480Smckusick caddr_t data; 65541480Smckusick { 65641480Smckusick register struct tty *tp; 65741480Smckusick register int unit = UNIT(dev); 65841480Smckusick register struct dcmdevice *dcm; 65941480Smckusick register int port; 66042354Smckusick int error, s; 66141480Smckusick 66241480Smckusick #ifdef DEBUG 66341480Smckusick if (dcmdebug & DDB_IOCTL) 66441480Smckusick printf("dcmioctl: unit %d cmd %x data %x flag %x\n", 66541480Smckusick unit, cmd, *data, flag); 66641480Smckusick #endif 66741480Smckusick tp = &dcm_tty[unit]; 66841480Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 66941480Smckusick if (error >= 0) 67041480Smckusick return (error); 67141480Smckusick error = ttioctl(tp, cmd, data, flag); 67241480Smckusick if (error >= 0) 67341480Smckusick return (error); 67441480Smckusick 67541480Smckusick port = PORT(unit); 67641480Smckusick dcm = dcm_addr[BOARD(unit)]; 67741480Smckusick switch (cmd) { 67841480Smckusick case TIOCSBRK: 67942354Smckusick /* 68042354Smckusick * Wait for transmitter buffer to empty 68142354Smckusick */ 68242354Smckusick s = spltty(); 68342354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 68442354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed)); 68541480Smckusick SEM_LOCK(dcm); 68642354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 68742354Smckusick dcm->dcm_cr |= (1 << port); /* start break */ 68841480Smckusick SEM_UNLOCK(dcm); 68942354Smckusick splx(s); 69041480Smckusick break; 69141480Smckusick 69241480Smckusick case TIOCCBRK: 69341480Smckusick SEM_LOCK(dcm); 69442354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 69542354Smckusick dcm->dcm_cr |= (1 << port); /* end break */ 69641480Smckusick SEM_UNLOCK(dcm); 69741480Smckusick break; 69841480Smckusick 69941480Smckusick case TIOCSDTR: 70041480Smckusick (void) dcmmctl(dev, MO_ON, DMBIS); 70141480Smckusick break; 70241480Smckusick 70341480Smckusick case TIOCCDTR: 70441480Smckusick (void) dcmmctl(dev, MO_ON, DMBIC); 70541480Smckusick break; 70641480Smckusick 70741480Smckusick case TIOCMSET: 70841480Smckusick (void) dcmmctl(dev, *(int *)data, DMSET); 70941480Smckusick break; 71041480Smckusick 71141480Smckusick case TIOCMBIS: 71241480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIS); 71341480Smckusick break; 71441480Smckusick 71541480Smckusick case TIOCMBIC: 71641480Smckusick (void) dcmmctl(dev, *(int *)data, DMBIC); 71741480Smckusick break; 71841480Smckusick 71941480Smckusick case TIOCMGET: 72041480Smckusick *(int *)data = dcmmctl(dev, 0, DMGET); 72141480Smckusick break; 72241480Smckusick 72341480Smckusick default: 72441480Smckusick return (ENOTTY); 72541480Smckusick } 72641480Smckusick return (0); 72741480Smckusick } 72841480Smckusick 72941480Smckusick dcmparam(tp, t) 73041480Smckusick register struct tty *tp; 73141480Smckusick register struct termios *t; 73241480Smckusick { 73341480Smckusick register struct dcmdevice *dcm; 73442354Smckusick register int port, mode, cflag = t->c_cflag; 73541480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); 73642354Smckusick 73741480Smckusick /* check requested parameters */ 73841480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 73941480Smckusick return(EINVAL); 74041480Smckusick /* and copy to tty */ 74141480Smckusick tp->t_ispeed = t->c_ispeed; 74241480Smckusick tp->t_ospeed = t->c_ospeed; 74341480Smckusick tp->t_cflag = cflag; 74441480Smckusick if (ospeed == 0) { 74542354Smckusick (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET); 74642354Smckusick return(0); 74741480Smckusick } 74842354Smckusick 74942354Smckusick mode = 0; 75041480Smckusick switch (cflag&CSIZE) { 75141480Smckusick case CS5: 75241480Smckusick mode = LC_5BITS; break; 75341480Smckusick case CS6: 75441480Smckusick mode = LC_6BITS; break; 75541480Smckusick case CS7: 75641480Smckusick mode = LC_7BITS; break; 75741480Smckusick case CS8: 75841480Smckusick mode = LC_8BITS; break; 75941480Smckusick } 76041480Smckusick if (cflag&PARENB) { 76141480Smckusick if (cflag&PARODD) 76241480Smckusick mode |= LC_PODD; 76341480Smckusick else 76441480Smckusick mode |= LC_PEVEN; 76541480Smckusick } 76641480Smckusick if (cflag&CSTOPB) 76741480Smckusick mode |= LC_2STOP; 76841480Smckusick else 76941480Smckusick mode |= LC_1STOP; 77041480Smckusick #ifdef DEBUG 77141480Smckusick if (dcmdebug & DDB_PARAM) 77242354Smckusick printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n", 77342354Smckusick UNIT(tp->t_dev), cflag, mode, tp->t_ospeed, 77442354Smckusick DCM_USPERCH(tp->t_ospeed)); 77541480Smckusick #endif 77642354Smckusick 77742354Smckusick port = PORT(tp->t_dev); 77842354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)]; 77942354Smckusick /* 78042354Smckusick * Wait for transmitter buffer to empty. 78142354Smckusick */ 78241480Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 78342354Smckusick DELAY(DCM_USPERCH(tp->t_ospeed)); 78442354Smckusick /* 78542354Smckusick * Make changes known to hardware. 78642354Smckusick */ 78742354Smckusick dcm->dcm_data[port].dcm_baud = ospeed; 78841480Smckusick dcm->dcm_data[port].dcm_conf = mode; 78941480Smckusick SEM_LOCK(dcm); 79042354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 79142354Smckusick dcm->dcm_cr |= (1 << port); 79241480Smckusick SEM_UNLOCK(dcm); 79342354Smckusick /* 794*49130Skarels * Delay for config change to take place. Weighted by baud. 79542354Smckusick * XXX why do we do this? 79642354Smckusick */ 79742354Smckusick DELAY(16 * DCM_USPERCH(tp->t_ospeed)); 79842354Smckusick return(0); 79941480Smckusick } 80041480Smckusick 80141480Smckusick dcmstart(tp) 80241480Smckusick register struct tty *tp; 80341480Smckusick { 80441480Smckusick register struct dcmdevice *dcm; 80542354Smckusick register struct dcmpreg *pp; 80642354Smckusick register struct dcmtfifo *fifo; 80742354Smckusick register char *bp; 80842354Smckusick register unsigned tail, next; 80942354Smckusick register int port, nch; 81042354Smckusick unsigned head; 81142354Smckusick char buf[16]; 81242354Smckusick int s; 81342354Smckusick #ifdef IOSTATS 81442354Smckusick struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)]; 81542354Smckusick int tch = 0; 81642354Smckusick #endif 81742354Smckusick 81841480Smckusick s = spltty(); 81942354Smckusick #ifdef IOSTATS 82042354Smckusick dsp->xints++; 82142354Smckusick #endif 82241480Smckusick #ifdef DEBUG 82341480Smckusick if (dcmdebug & DDB_OUTPUT) 82442354Smckusick printf("dcmstart(%d): state %x flags %x outcc %d\n", 82542354Smckusick UNIT(tp->t_dev), tp->t_state, tp->t_flags, 82642354Smckusick tp->t_outq.c_cc); 82741480Smckusick #endif 82841480Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 82941480Smckusick goto out; 83041480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 83141480Smckusick if (tp->t_state&TS_ASLEEP) { 83241480Smckusick tp->t_state &= ~TS_ASLEEP; 83341480Smckusick wakeup((caddr_t)&tp->t_outq); 83441480Smckusick } 83541480Smckusick if (tp->t_wsel) { 83641480Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 83741480Smckusick tp->t_wsel = 0; 83841480Smckusick tp->t_state &= ~TS_WCOLL; 83941480Smckusick } 84041480Smckusick } 84142354Smckusick if (tp->t_outq.c_cc == 0) { 84242354Smckusick #ifdef IOSTATS 84342354Smckusick dsp->xempty++; 84442354Smckusick #endif 84542354Smckusick goto out; 84642354Smckusick } 84742354Smckusick 84842354Smckusick dcm = dcm_addr[BOARD(tp->t_dev)]; 84942354Smckusick port = PORT(tp->t_dev); 85042354Smckusick pp = dcm_preg(dcm, port); 85142354Smckusick tail = pp->t_tail & TX_MASK; 85242354Smckusick next = (tail + 1) & TX_MASK; 85342354Smckusick head = pp->t_head & TX_MASK; 85442354Smckusick if (head == next) 85542354Smckusick goto out; 85642354Smckusick fifo = &dcm->dcm_tfifos[3-port][tail]; 85742354Smckusick again: 85842354Smckusick nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK); 85942354Smckusick #ifdef IOSTATS 86042354Smckusick tch += nch; 86142354Smckusick #endif 86241480Smckusick #ifdef DEBUG 86342354Smckusick if (dcmdebug & DDB_OUTPUT) 86442354Smckusick printf("\thead %x tail %x nch %d\n", head, tail, nch); 86541480Smckusick #endif 86642354Smckusick /* 86742354Smckusick * Loop transmitting all the characters we can. 86842354Smckusick */ 86942354Smckusick for (bp = buf; --nch >= 0; bp++) { 87042354Smckusick fifo->data_char = *bp; 87142354Smckusick pp->t_tail = next; 87242354Smckusick /* 87342354Smckusick * If this is the first character, 87442354Smckusick * get the hardware moving right now. 87542354Smckusick */ 87642354Smckusick if (bp == buf) { 87742354Smckusick tp->t_state |= TS_BUSY; 87842354Smckusick SEM_LOCK(dcm); 87942354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 88042354Smckusick dcm->dcm_cr |= (1 << port); 88142354Smckusick SEM_UNLOCK(dcm); 88242354Smckusick } 88341480Smckusick tail = next; 88442354Smckusick fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; 88542354Smckusick next = (next + 1) & TX_MASK; 88641480Smckusick } 88742354Smckusick /* 88842354Smckusick * Head changed while we were loading the buffer, 88942354Smckusick * go back and load some more if we can. 89042354Smckusick */ 89142354Smckusick if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) { 89242354Smckusick #ifdef IOSTATS 89342354Smckusick dsp->xrestarts++; 89442354Smckusick #endif 89542354Smckusick head = pp->t_head & TX_MASK; 89642354Smckusick goto again; 89742354Smckusick } 898*49130Skarels 89942354Smckusick /* 90042354Smckusick * Kick it one last time in case it finished while we were 90144317Shibler * loading the last bunch. 90242354Smckusick */ 90342354Smckusick if (bp > &buf[1]) { 90441480Smckusick tp->t_state |= TS_BUSY; 90541480Smckusick SEM_LOCK(dcm); 90642354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 90742354Smckusick dcm->dcm_cr |= (1 << port); 90842354Smckusick SEM_UNLOCK(dcm); 90942354Smckusick } 91041480Smckusick #ifdef DEBUG 91141480Smckusick if (dcmdebug & DDB_INTR) 91243407Shibler printf("dcmstart(%d): head %x tail %x outqcc %d\n", 91343407Shibler UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc); 91441480Smckusick #endif 91541480Smckusick out: 91642354Smckusick #ifdef IOSTATS 91742354Smckusick dsp->xchars += tch; 91842354Smckusick if (tch <= DCMXBSIZE) 91942354Smckusick dsp->xsilo[tch]++; 92042354Smckusick else 92142354Smckusick dsp->xsilo[DCMXBSIZE+1]++; 92242354Smckusick #endif 92341480Smckusick splx(s); 92441480Smckusick } 92541480Smckusick 92641480Smckusick /* 92741480Smckusick * Stop output on a line. 92841480Smckusick */ 92941480Smckusick dcmstop(tp, flag) 93041480Smckusick register struct tty *tp; 93141480Smckusick { 93241480Smckusick int s; 93341480Smckusick 93441480Smckusick s = spltty(); 93541480Smckusick if (tp->t_state & TS_BUSY) { 93642354Smckusick /* XXX is there some way to safely stop transmission? */ 93744317Shibler if ((tp->t_state&TS_TTSTOP) == 0) 93841480Smckusick tp->t_state |= TS_FLUSH; 93941480Smckusick } 94041480Smckusick splx(s); 94141480Smckusick } 94241480Smckusick 94345750Smckusick /* 94445750Smckusick * Modem control 94545750Smckusick */ 94641480Smckusick dcmmctl(dev, bits, how) 94741480Smckusick dev_t dev; 94841480Smckusick int bits, how; 94941480Smckusick { 95041480Smckusick register struct dcmdevice *dcm; 95145750Smckusick int s, unit, hit = 0; 95241480Smckusick 95345750Smckusick unit = UNIT(dev); 95445750Smckusick #ifdef DEBUG 95545750Smckusick if (dcmdebug & DDB_MODEM) 95645750Smckusick printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", 95745750Smckusick BOARD(unit), unit, bits, how); 95845750Smckusick #endif 95941480Smckusick 96045750Smckusick dcm = dcm_addr[BOARD(unit)]; 96141480Smckusick s = spltty(); 96241480Smckusick switch (how) { 96341480Smckusick 96441480Smckusick case DMSET: 96545750Smckusick dcm_modem[unit]->mdmout = bits; 96641480Smckusick hit++; 96741480Smckusick break; 96841480Smckusick 96941480Smckusick case DMBIS: 97045750Smckusick dcm_modem[unit]->mdmout |= bits; 97141480Smckusick hit++; 97241480Smckusick break; 97341480Smckusick 97441480Smckusick case DMBIC: 97545750Smckusick dcm_modem[unit]->mdmout &= ~bits; 97641480Smckusick hit++; 97741480Smckusick break; 97841480Smckusick 97941480Smckusick case DMGET: 98045750Smckusick bits = dcm_modem[unit]->mdmin; 98141480Smckusick break; 98241480Smckusick } 98341480Smckusick if (hit) { 98441480Smckusick SEM_LOCK(dcm); 98545750Smckusick dcm->dcm_modemchng |= 1<<(unit & 3); 98641480Smckusick dcm->dcm_cr |= CR_MODM; 98741480Smckusick SEM_UNLOCK(dcm); 98842354Smckusick DELAY(10); /* delay until done */ 98941480Smckusick (void) splx(s); 99041480Smckusick } 99141480Smckusick return(bits); 99241480Smckusick } 99341480Smckusick 99442354Smckusick /* 99542354Smckusick * Set board to either interrupt per-character or at a fixed interval. 99642354Smckusick */ 99742354Smckusick dcmsetischeme(brd, flags) 99842354Smckusick int brd, flags; 99941480Smckusick { 100042354Smckusick register struct dcmdevice *dcm = dcm_addr[brd]; 100142354Smckusick register struct dcmischeme *dis = &dcmischeme[brd]; 100241480Smckusick register int i; 100342354Smckusick u_char mask; 100442354Smckusick int perchar = flags & DIS_PERCHAR; 100541480Smckusick 100641480Smckusick #ifdef DEBUG 100742354Smckusick if (dcmdebug & DDB_INTSCHM) 100842354Smckusick printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", 100942354Smckusick brd, perchar, dis->dis_perchar, 101042354Smckusick dis->dis_intr, dis->dis_char); 101142354Smckusick if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { 101242354Smckusick printf("dcmsetischeme(%d): redundent request %d\n", 101342354Smckusick brd, perchar); 101442354Smckusick return; 101542354Smckusick } 101642354Smckusick #endif 101742354Smckusick /* 101842354Smckusick * If perchar is non-zero, we enable interrupts on all characters 101942354Smckusick * otherwise we disable perchar interrupts and use periodic 102042354Smckusick * polling interrupts. 102142354Smckusick */ 102242354Smckusick dis->dis_perchar = perchar; 102342354Smckusick mask = perchar ? 0xf : 0x0; 102442354Smckusick for (i = 0; i < 256; i++) 102542354Smckusick dcm->dcm_bmap[i].data_data = mask; 102642354Smckusick /* 102742354Smckusick * Don't slow down tandem mode, interrupt on flow control 102842354Smckusick * chars for any port on the board. 102942354Smckusick */ 103042354Smckusick if (!perchar) { 103142354Smckusick register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)]; 103242354Smckusick int c; 103342354Smckusick 103442354Smckusick for (i = 0; i < 4; i++, tp++) { 103542354Smckusick if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) 103642354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 103742354Smckusick if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) 103842354Smckusick dcm->dcm_bmap[c].data_data |= (1 << i); 103941480Smckusick } 104041480Smckusick } 104142354Smckusick /* 104242354Smckusick * Board starts with timer disabled so if first call is to 104342354Smckusick * set perchar mode then we don't want to toggle the timer. 104442354Smckusick */ 104542354Smckusick if (flags == (DIS_RESET|DIS_PERCHAR)) 104641480Smckusick return; 104742354Smckusick /* 104842354Smckusick * Toggle card 16.7ms interrupts (we first make sure that card 104942354Smckusick * has cleared the bit so it will see the toggle). 105042354Smckusick */ 105142354Smckusick while (dcm->dcm_cr & CR_TIMER) 105242354Smckusick ; 105341480Smckusick SEM_LOCK(dcm); 105442354Smckusick dcm->dcm_cr |= CR_TIMER; 105541480Smckusick SEM_UNLOCK(dcm); 105641480Smckusick } 105741480Smckusick 105841480Smckusick /* 105941480Smckusick * Following are all routines needed for DCM to act as console 106041480Smckusick */ 106145788Sbostic #include "../hp300/cons.h" 106241480Smckusick 106342354Smckusick dcmcnprobe(cp) 106442354Smckusick struct consdev *cp; 106541480Smckusick { 106642354Smckusick register struct hp_hw *hw; 1067*49130Skarels int unit; 106841480Smckusick 1069*49130Skarels /* locate the major number */ 1070*49130Skarels for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) 1071*49130Skarels if (cdevsw[dcmmajor].d_open == dcmopen) 1072*49130Skarels break; 1073*49130Skarels 107442354Smckusick /* 107542354Smckusick * Implicitly assigns the lowest select code DCM card found to be 107642354Smckusick * logical unit 0 (actually CONUNIT). If your config file does 107742354Smckusick * anything different, you're screwed. 107842354Smckusick */ 107942354Smckusick for (hw = sc_table; hw->hw_type; hw++) 108042354Smckusick if (hw->hw_type == COMMDCM && !badaddr((short *)hw->hw_addr)) 108142354Smckusick break; 108242354Smckusick if (hw->hw_type != COMMDCM) { 108342354Smckusick cp->cn_pri = CN_DEAD; 108442354Smckusick return; 108542354Smckusick } 108642354Smckusick unit = CONUNIT; 108742354Smckusick dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_addr; 108841480Smckusick 108942354Smckusick /* initialize required fields */ 1090*49130Skarels cp->cn_dev = makedev(dcmmajor, unit); 109142354Smckusick cp->cn_tp = &dcm_tty[unit]; 109242354Smckusick switch (dcm_addr[BOARD(unit)]->dcm_rsid) { 109342354Smckusick case DCMID: 109442354Smckusick cp->cn_pri = CN_NORMAL; 109542354Smckusick break; 109642354Smckusick case DCMID|DCMCON: 109742354Smckusick cp->cn_pri = CN_REMOTE; 109842354Smckusick break; 109942354Smckusick default: 110042354Smckusick cp->cn_pri = CN_DEAD; 1101*49130Skarels return; 110242354Smckusick } 1103*49130Skarels /* 1104*49130Skarels * If dcmconsole is initialized, raise our priority. 1105*49130Skarels */ 1106*49130Skarels if (dcmconsole == UNIT(unit)) 1107*49130Skarels cp->cn_pri = CN_REMOTE; 1108*49130Skarels #ifdef KGDB 1109*49130Skarels if (major(kgdb_dev) == 2) /* XXX */ 1110*49130Skarels kgdb_dev = makedev(dcmmajor, minor(kgdb_dev)); 1111*49130Skarels #ifdef notdef 1112*49130Skarels /* 1113*49130Skarels * This doesn't currently work, at least not with ite consoles; 1114*49130Skarels * the console hasn't been initialized yet. 1115*49130Skarels */ 1116*49130Skarels if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { 1117*49130Skarels (void) dcminit(kgdb_dev, kgdb_rate); 1118*49130Skarels if (kgdb_debug_init) { 1119*49130Skarels /* 1120*49130Skarels * We assume that console is ready for us... 1121*49130Skarels * this assumes that a dca or ite console 1122*49130Skarels * has been selected already and will init 1123*49130Skarels * on the first putc. 1124*49130Skarels */ 1125*49130Skarels printf("dcm%d: ", UNIT(kgdb_dev)); 1126*49130Skarels kgdb_connect(1); 1127*49130Skarels } 1128*49130Skarels } 1129*49130Skarels #endif 1130*49130Skarels #endif 113142354Smckusick } 113242354Smckusick 113342354Smckusick dcmcninit(cp) 113442354Smckusick struct consdev *cp; 113542354Smckusick { 113642354Smckusick dcminit(cp->cn_dev, dcmdefaultrate); 1137*49130Skarels dcmconsinit = 1; 113842354Smckusick dcmconsole = UNIT(cp->cn_dev); 113942354Smckusick } 114042354Smckusick 114142354Smckusick dcminit(dev, rate) 114242354Smckusick dev_t dev; 114342354Smckusick int rate; 114442354Smckusick { 114542354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 114642354Smckusick int s, mode, port; 114742354Smckusick 114842354Smckusick port = PORT(dev); 114942354Smckusick mode = LC_8BITS | LC_1STOP; 115041480Smckusick s = splhigh(); 115142354Smckusick /* 115242354Smckusick * Wait for transmitter buffer to empty. 115342354Smckusick */ 115442354Smckusick while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 115542354Smckusick DELAY(DCM_USPERCH(rate)); 115642354Smckusick /* 115742354Smckusick * Make changes known to hardware. 115842354Smckusick */ 115942354Smckusick dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); 116042354Smckusick dcm->dcm_data[port].dcm_conf = mode; 116142354Smckusick SEM_LOCK(dcm); 116242354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 116342354Smckusick dcm->dcm_cr |= (1 << port); 116442354Smckusick SEM_UNLOCK(dcm); 116542354Smckusick /* 1166*49130Skarels * Delay for config change to take place. Weighted by baud. 116742354Smckusick * XXX why do we do this? 116842354Smckusick */ 116942354Smckusick DELAY(16 * DCM_USPERCH(rate)); 117041480Smckusick splx(s); 117141480Smckusick } 117241480Smckusick 117341480Smckusick dcmcngetc(dev) 117442354Smckusick dev_t dev; 117541480Smckusick { 117642354Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 117742354Smckusick register struct dcmrfifo *fifo; 117842354Smckusick register struct dcmpreg *pp; 117942354Smckusick register unsigned head; 118042354Smckusick int s, c, stat, port; 118142354Smckusick 118242354Smckusick port = PORT(dev); 118342354Smckusick pp = dcm_preg(dcm, port); 118442354Smckusick s = splhigh(); 118542354Smckusick head = pp->r_head & RX_MASK; 118642354Smckusick fifo = &dcm->dcm_rfifos[3-port][head>>1]; 118742354Smckusick while (head == (pp->r_tail & RX_MASK)) 118842354Smckusick ; 118942354Smckusick /* 119042354Smckusick * If board interrupts are enabled, just let our received char 119142354Smckusick * interrupt through in case some other port on the board was 119242354Smckusick * busy. Otherwise we must clear the interrupt. 119342354Smckusick */ 119442354Smckusick SEM_LOCK(dcm); 119542354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) 119642354Smckusick stat = dcm->dcm_iir; 119742354Smckusick SEM_UNLOCK(dcm); 119842354Smckusick c = fifo->data_char; 119942354Smckusick stat = fifo->data_stat; 120042354Smckusick pp->r_head = (head + 2) & RX_MASK; 120142354Smckusick splx(s); 120242354Smckusick return(c); 120341480Smckusick } 120441480Smckusick 120541480Smckusick /* 120641480Smckusick * Console kernel output character routine. 120741480Smckusick */ 120841480Smckusick dcmcnputc(dev, c) 120941480Smckusick dev_t dev; 121042354Smckusick int c; 121141480Smckusick { 121241480Smckusick register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 121342354Smckusick register struct dcmpreg *pp; 121442354Smckusick unsigned tail; 121542354Smckusick int s, port, stat; 121641480Smckusick 121742354Smckusick port = PORT(dev); 121842354Smckusick pp = dcm_preg(dcm, port); 121942354Smckusick s = splhigh(); 122042354Smckusick #ifdef KGDB 122142354Smckusick if (dev != kgdb_dev) 122242354Smckusick #endif 1223*49130Skarels if (dcmconsinit == 0) { 122442354Smckusick (void) dcminit(dev, dcmdefaultrate); 1225*49130Skarels dcmconsinit = 1; 122642354Smckusick } 122742354Smckusick tail = pp->t_tail & TX_MASK; 122842354Smckusick while (tail != (pp->t_head & TX_MASK)) 122942354Smckusick ; 123042354Smckusick dcm->dcm_tfifos[3-port][tail].data_char = c; 123142354Smckusick pp->t_tail = tail = (tail + 1) & TX_MASK; 123241480Smckusick SEM_LOCK(dcm); 123342354Smckusick dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 123442354Smckusick dcm->dcm_cr |= (1 << port); 123541480Smckusick SEM_UNLOCK(dcm); 123642354Smckusick while (tail != (pp->t_head & TX_MASK)) 123742354Smckusick ; 123842354Smckusick /* 123942354Smckusick * If board interrupts are enabled, just let our completion 124042354Smckusick * interrupt through in case some other port on the board 124142354Smckusick * was busy. Otherwise we must clear the interrupt. 124242354Smckusick */ 124342354Smckusick if ((dcm->dcm_ic & IC_IE) == 0) { 124442354Smckusick SEM_LOCK(dcm); 124542354Smckusick stat = dcm->dcm_iir; 124642354Smckusick SEM_UNLOCK(dcm); 124742354Smckusick } 124841480Smckusick splx(s); 124941480Smckusick } 125041480Smckusick #endif 1251