📄 mdc.c
字号:
#ifndef lintstatic char *sccsid = "@(#)mdc.c 4.3 (ULTRIX) 9/10/90";#endif lint/************************************************************************ * * * Copyright (c) 1990 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************ * * mdc.c * * Mipsmate DC7085 SLU console driver -the real thing!!!!! * * Modification history * * * August 22, 1990 Paul Grist * Changed initilazation of console baud rate to use "baud0", it * was left "baud1" from some early prom debug, hence was broke. * * July 14, 1990 Kuo-Hsiung Hsieh * Asserted Speed Select (SS) modem control signal in open routine. * Deasserted SS when process exits. As requested by PTT test. * * July 5, 1990 Kuo-Hsiung Hsieh * Fixed data corrupted problem due to setting break condition * on a transmission line. On DC type of chip, a specific delay * period has to be imposed on the transmission line if the next * thing to transmit is a break condition. Data could be corrupted * even though TRDY bit may say it is ready to send the next * character. * * June 4, 1990 Kuo-Hsiung Hsieh * Fixed duplicated assertion of break. It is caused by reading * the transmit data register which is the modem status register. * * May 10, 1990 Kuo-Hsiung Hsieh * Fixed linenum typo which caused system hung and added modem stuff. * * March 23, 1990 Tim Burke * * Created file. Contents based on dc7085.c file. Due to time constraints * a separate copy of this driver is being developed instead of modifying * the original source to accomodate all three device types. The main * changes from the dc7085 sources is to remove all references to graphic * capabilities. This driver can accomodate up to 3 DC7085 chips while * the original driver could only have 1 such chip. * * Extensive cleanups of the original dc7085.c driver were also done. * These cleanups include using #define constants, overhaul of the buad * rate representation scheme. Use consistent variable terminology, * specifically unit means dc number, linenum is the particular line of * a dc and minor_num is the device minor number. */#include "../machine/pte.h"#include "../h/param.h"#include "../h/systm.h"#include "../h/ioctl.h"#include "../h/tty.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/proc.h"#include "../h/map.h"#include "../h/buf.h"#include "../h/vm.h"#include "../h/conf.h"#include "../h/file.h"#include "../h/uio.h"#include "../h/kernel.h"#include "../h/devio.h"#include "../../machine/common/cpuconf.h"#include "../h/exec.h"#include "../h/kmalloc.h"#include "../h/sys_tpath.h"#include "../io/uba/ubavar.h" /* auto-config headers */#include "../machine/cpu.h"#include "../machine/mips/mdcreg.h"/* * Declare the data structures used to represent the terminal attributes. */struct tty mdc_tty[NDC * NDCLINE]; /* Allocate 1 tty structure per line*/u_char mdcmodem[NDC]; /* keeps track of modem state */u_short mdcscan_previous[NDC]; /* Used to detect modem transitions */int mdcmodem_active; /* Determines scan rate */int console_baud; /* Specifies console baud rate */int mdcdefaultCAR[NDC]; /* Default status of modem/nomodem */int mdcsoftCAR[NDC]; /* Present status of modem/nomodem */int mdc_cnt; /* The number of configured lines */u_char mdc_brk[NDC];extern int nMDC; /* Configuration - # of DC chips */struct timeval mdctimestamp[NDC]; /* Timer for modem control */int mdc_attach_called = 0; /* Attach routine has been called */int mdcprobe(), mdcattach(), mdcrint(), mdc_unit_init();int mdc_dsr_check(), mdc_tty_drop(), mdc_cd_drop(); int mdcputc(), mdcgetc();void mdcsetbreak();u_short mdcstd[] = { 0 };struct uba_device *mdcinfo[1];/* * Unibus device driver definition. These routines are used at boot time by * the configuration program. */struct uba_driver mdcdriver = { mdcprobe, /* probe routine */ 0, /* slave routine */ mdcattach, /* attach routine */ 0, /* ud_dgo routine */ mdcstd, /* device csr address */ "mdc", /* device name */ mdcinfo /* backpointers to ubdinit structs */ /* I guess the rest are just 0's */ /* name of a controller */ /* backpointers to ubminit structs */ /* want exclusive use of bdp's */ };int mdcstart(), mdcxint(), mdcbaudrate();int ttrstrt();#define MODEM_LINE 2 /* Modem control only on line 2 */#define NOMODEM_UNIT 2 /* DC #2 does not have full modem */#define LINEMASK 0x03 /* line unit mask, each DC has 4 lines*/#define LINEBITS 2 /* The linemask occupies 2 bits *//* * Baud Rate Support * * When the baud rate on the right is specified, the line parameter register * is setup with the appropriate bits as specified in the left column. */#define BAUD_UNSUPPORTED 0 /* Device does not provide this baud rate */#define BAUD_SUPPORTED 1 /* Device does provide this baud rate *//* * If the BAUD38 bit of the System Control and Status Register is set the * chip can do 38400 baud in which case EXTB would be supported. This bit * applies to all 4 lines such that it is not possible to simultaneously do * 19200 and 38400. To keep things simple, only provide support for 19.2. * The third column is the minimum delay value for setting a break * condition. If we set a break condition without delaying this minimum * interval, we might corrupt character which is still in the shift * register. The delay values are calculated based on the equation: * 12 (bits/char) * 256 (hz) / baudrate + 2 (safety factor). */struct baud_support mdc_speeds[] = { {0, BAUD_UNSUPPORTED, 0}, /* B0 */ {DC_B50, BAUD_SUPPORTED, 78}, /* B50 */ {DC_B75, BAUD_SUPPORTED, 42}, /* B75 */ {DC_B110, BAUD_SUPPORTED, 30}, /* B110 */ {DC_B134_5, BAUD_SUPPORTED, 25}, /* B134 */ {DC_B150, BAUD_SUPPORTED, 22}, /* B150 */ {0, BAUD_UNSUPPORTED, 0}, /* B200 */ {DC_B300, BAUD_SUPPORTED, 12}, /* B300 */ {DC_B600, BAUD_SUPPORTED, 7}, /* B600 */ {DC_B1200, BAUD_SUPPORTED, 5}, /* B1200 */ {DC_B1800, BAUD_SUPPORTED, 4}, /* B1800 */ {DC_B2400, BAUD_SUPPORTED, 3}, /* B2400 */ {DC_B4800, BAUD_SUPPORTED, 2}, /* B4800 */ {DC_B9600, BAUD_SUPPORTED, 2}, /* B9600 */ {DC_B19200, BAUD_SUPPORTED, 2}, /* EXTA */ {0, BAUD_UNSUPPORTED, 0}, /* EXTB */ };extern int pmcons_init();extern int prom_getenv();extern int cpu;#ifdef DEBUGint mdcdebug = 0;/* * Print out the modem leads for this DC unit. */#define PRINT_SIGNALS(dcaddr) { cprintf("Modem signals: "); \ if (dcaddr->dcmsr & DC_DSR) cprintf(" DSR "); \ if (dcaddr->dcmsr & DC_CTS) cprintf(" CTS "); \ if (dcaddr->dcmsr & DC_CD) cprintf(" CD "); \ cprintf("\n"); } #endif DEBUG/* * Probe to see if the device is alive. Since this is a bounded configuration * there must be a DC chip present for the console. The intialization is done * through dc_cons_init out of startup(). */mdcprobe(reg)int reg;{ return(1);}/* * Initialize the device and setup initial values of relevant variables. */mdcattach(){ register int unit; extern mdcscan(); /* * If the option card is in place this routine may end up being called * more than once. Use mdc_attach_called to insure that the body of this * routine is only executed once. */ if (mdc_attach_called == 0) { mdc_attach_called = 1; /* * Setup per-DC registers and software status. */ mdc_cnt = 0; if (nMDC <= 0) { panic("mdcattach: no units configured.\n"); } if (nMDC > MAX_NDC) { nMDC = MAX_NDC; cprintf("Too many DC chips configured: nMDC = %d\n",nMDC); } for (unit = 0; unit < nMDC; unit++) { mdc_brk[unit] = 0; mdc_unit_init(unit); mdc_cnt += NDCLINE; } /* * Initialize the scanner process. Since the chip does not * interrupt on modem transitions it is necessary to have a scanner * thread that occasionally checks the modem leads and looks for * changes. Start up this to examine the modem leads once per second. */ mdcmodem_active = 0; timeout(mdcscan, (caddr_t)0, hz); }}/* * Initalizes the DC registers and associated software attributes. * Called on a per unit basis from attach(). */mdc_unit_init(unit) register int unit;{ register volatile struct mdz_reg *dcaddr;# ifdef DEBUG if (mdcdebug) cprintf("mdc_unit_init: unit = %d.\n",unit);# endif DEBUG if (unit > MAX_NDC) { /* paranoia */ return; } dcaddr = mdz_regs[unit]; /* * Note that the dcsoftCAR and dcdefaultCAR do not look at the flags * field of the config file. This may need to be fixed up. */ mdcsoftCAR[unit] = 0xf; /* Set lines to direct connect */ mdcdefaultCAR[unit] = 0xf; /* Default lines to direct connect */ mdcscan_previous[unit] = 0; /* Initial modem status */ /* * DC0 and DC1 allow modem control on line 2. Initialize these leads * to clear the modem control signals. */ if (unit != NOMODEM_UNIT) { dcaddr->dctcr &= ~(DC_RDTR | DC_RRTS | DC_RSS); }}/* * Called early from startup. The purpose of this routine is to setup the * console line to enable output so the startup messages can be displayed. */mdc_cons_init(){ register int linenum = CONSOLE_LINE; register volatile struct mdz_reg *dcaddr = mdz_regs[CONSOLE_UNIT]; register int prom_baud; /* * The console will default to 9600 baud. This can be changed via * the baud environment variable. Read in the console baud rate * for later use. This presently only supports a selected number of * baud rates. */ prom_baud = atoi(prom_getenv("baud0")); switch (prom_baud) { case 75: console_baud = B75; break; case 110: console_baud = B110; break; case 150: console_baud = B150; break; case 300: console_baud = B300; break; case 600: console_baud = B600; break; case 1200: console_baud = B1200; break; case 2400: console_baud = B2400; break; case 4800: console_baud = B4800; break; case 9600: console_baud = B9600; break; default: console_baud = B9600; } dcaddr->dclpr = linenum | mdc_speeds[console_baud].baud_param | BITS8 | DC_RE;}/* * Open line and set default parameters. If this is a modem line wait for * the appropriate leads to be asserted. */mdcopen(dev, flag) dev_t dev;{ register volatile struct mdz_reg *dcaddr; register struct tty *tp; register int unit; register int linenum; register int minor_num; int inuse; /*hold state of inuse bit while blocked waiting for carr*/ minor_num = minor(dev); unit = minor_num >> LINEBITS; dcaddr = mdz_regs[unit]; linenum = minor_num & LINEMASK; if (minor_num >= mdc_cnt) { return (ENXIO); } tp = &mdc_tty[minor_num]; if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { return (EBUSY); } while (tp->t_state&TS_CLOSING) { /* let DTR stay down for awhile */ sleep((caddr_t)&tp->t_rawq, TTIPRI); } tp->t_addr = (caddr_t)tp; tp->t_oproc = mdcstart; tp->t_baudrate = mdcbaudrate; tty_def_open(tp, dev, flag, (mdcsoftCAR[unit]&(1<<(linenum)))); /* * If the line is not presently open setup the default terminal * attributes. */ if ((tp->t_state & TS_ISOPEN) == 0) { /* * Prevent spurious startups by making the 500ms timer * initially high. */ /* Tim - Should this only be set if opening modem line? */ mdcmodem[unit] = MODEM_DSR_START; /* * Specify console terminal attributes. Do not allow modem control * on the console. Setup <NL> to <CR> <LF> mapping. */ if ((unit == CONSOLE_UNIT) && (linenum == CONSOLE_LINE)) { tp->t_cflag |= CLOCAL; tp->t_flags = ANYP|ECHO|CRMOD; tp->t_iflag |= ICRNL; tp->t_oflag |= ONLCR; } } mdcparam(minor_num); /* enables interrupts */ (void) spltty(); /* * No modem control provided for lines with softCAR set. * Modem control provided only for line 2. */# ifdef DEBUG if (mdcdebug) cprintf("mdcopen: unit = %d, linenum = %d\n",unit, linenum);# endif DEBUG /* * Modem control is only provided on line 2 of DC0 and DC1. All other * lines are restricted to be direct connect. For this reason set * CLOCAL as a sanity check. */ if ((unit == NOMODEM_UNIT) || (linenum != MODEM_LINE)) { tp->t_cflag |= CLOCAL; } if (tp->t_cflag & CLOCAL) { /* * This is a local connection - ignore carrier * receive enable interrupts enabled above via dcparam() */ tp->t_state |= TS_CARR_ON; /* dcscan sets */ if (linenum == MODEM_LINE) { dcaddr->dctcr |= (DC_RDTR | DC_RRTS | DC_RSS); } /* * Set state bit to tell tty.c not to assign this line as the * controlling terminal for the process which opens this line. */ if ((flag & O_NOCTTY) && (u.u_procp->p_progenv == A_POSIX)) tp->t_state |= TS_ONOCTTY; (void) spl0(); return ((*linesw[tp->t_line].l_open)(dev, tp)); } /* * this is a modem line */ /* receive enable interrupts enabled above via dcparam() */ if (linenum == MODEM_LINE) { dcaddr->dctcr |= (DC_RDTR | DC_RRTS | DC_RSS); } /* * After DSR first comes up we must wait for the other signals * before commencing transmission. */#ifdef DEBUG if (mdcdebug) { cprintf("open flag : %x\n", flag); if (flag & (O_NDELAY|O_NONBLOCK)) cprintf("flag & (O_NDELAY|O_NONBLOCK)\n"); }#endif DEBUG if ((flag & (O_NDELAY|O_NONBLOCK)) == 0) { /* * Delay before examining other signals if DSR is being followed * otherwise proceed directly to dc_dsr_check to look for * carrier detect and clear to send. */#ifdef DEBUG if (mdcdebug) { cprintf("mdcopen: "); PRINT_SIGNALS(dcaddr); }#endif DEBUG if (dcaddr->dcmsr & DC_DSR) { mdcmodem[unit] |= (MODEM_DSR_START|MODEM_DSR); tp->t_dev = dev; /* need it for timeouts */ /* * Give CD and CTS 30 sec. to * come up. Start transmission * immediately, no longer need * 500ms delay. */ timeout(mdc_dsr_check, tp, hz*30); mdc_dsr_check(tp); } }# ifdef DEBUG if (mdcdebug) cprintf("mdcopen: linenum=%d, state=0x%x, tp=0x%x\n", linenum, tp->t_state, tp);# endif DEBUG if (flag & (O_NDELAY|O_NONBLOCK)) tp->t_state |= TS_ONDELAY; else while ((tp->t_state & TS_CARR_ON) == 0) { tp->t_state |= TS_WOPEN; inuse = tp->t_state&TS_INUSE;#ifdef DEBUG if (mdcdebug) { cprintf("mdc_open: going to sleep\n"); }#endif DEBUG sleep((caddr_t)&tp->t_rawq, TTIPRI); /* * See if we were awoken by a false call to the modem * line by a non-modem. */ if (mdcmodem[unit]&MODEM_BADCALL){ (void) spl0(); return(EWOULDBLOCK); } /* if we opened "block if in use" and * the terminal was not inuse at that time * but is became "in use" while we were * waiting for carrier then return */ if ((flag & O_BLKINUSE) && (inuse==0) && (tp->t_state&TS_INUSE)) { (void) spl0(); return(EALREADY); } } /* * Set state bit to tell tty.c not to assign this line as the * controlling terminal for the process which opens this line. */ if ((flag & O_NOCTTY) && (u.u_procp->p_progenv == A_POSIX)) tp->t_state |= TS_ONOCTTY; (void) spl0();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -