📄 com.c
字号:
/*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)com.c 8.1 (Berkeley) 6/11/93 */#include "com.h"#if NCOM > 0/* * COM driver, based on HP dca driver * uses National Semiconductor NS16450/NS16550AF UART */#include <sys/param.h>#include <sys/systm.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/uio.h>#include <sys/kernel.h>#include <sys/syslog.h>#include <i386/isa/isa_device.h>#include <i386/isa/comreg.h>#include <i386/isa/ic/ns16550.h>void comstart();int comprobe(), comattach(), comintr(), comparam();struct isa_driver comdriver = { comprobe, comattach, "com"};int comsoftCAR;int com_active;int com_hasfifo;int ncom = NCOM;#ifdef COMCONSOLEint comconsole = COMCONSOLE;#elseint comconsole = -1;#endifint comconsinit;int comdefaultrate = TTYDEF_SPEED;int commajor;short com_addr[NCOM];struct tty com_tty[NCOM];struct speedtab comspeedtab[] = { 0, 0, 50, COMBRD(50), 75, COMBRD(75), 110, COMBRD(110), 134, COMBRD(134), 150, COMBRD(150), 200, COMBRD(200), 300, COMBRD(300), 600, COMBRD(600), 1200, COMBRD(1200), 1800, COMBRD(1800), 2400, COMBRD(2400), 4800, COMBRD(4800), 9600, COMBRD(9600), 19200, COMBRD(19200), 38400, COMBRD(38400), 57600, COMBRD(57600), -1, -1};extern struct tty *constty;#ifdef KGDB#include <machine/remote-sl.h>extern int kgdb_dev;extern int kgdb_rate;extern int kgdb_debug_init;#endif#define UNIT(x) minor(x)comprobe(dev)struct isa_device *dev;{ /* force access to id reg */ outb(dev->id_iobase+com_cfcr, inb (dev->id_iobase+com_cfcr) & ~0x80); outb(dev->id_iobase+com_iir, 0); if ((inb(dev->id_iobase+com_iir) & 0x38) == 0) return(1); return(1);}intcomattach(isdp)struct isa_device *isdp;{ struct tty *tp; u_char unit; int port = isdp->id_iobase; unit = isdp->id_unit; if (unit == comconsole) DELAY(100000); com_addr[unit] = port; com_active |= 1 << unit; comsoftCAR |= 1 << unit; /* XXX */ /* look for a NS 16550AF UART with FIFOs */ outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); DELAY(100); if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) com_hasfifo |= 1 << unit; outb(port+com_ier, 0); outb(port+com_mcr, 0 | MCR_IENABLE);#ifdef KGDB if (kgdb_dev == makedev(commajor, unit)) { if (comconsole == unit) kgdb_dev = -1; /* can't debug over console port */ else { (void) cominit(unit, kgdb_rate); if (kgdb_debug_init) { /* * Print prefix of device name, * let kgdb_connect print the rest. */ printf("com%d: ", unit); kgdb_connect(1); } else printf("com%d: kgdb enabled\n", unit); } }#endif /* * Need to reset baud rate, etc. of next print so reset comconsinit. * Also make sure console is always "hardwired" */ if (unit == comconsole) { comconsinit = 0; comsoftCAR |= (1 << unit); } return (1);}/* ARGSUSED */#ifdef __STDC__comopen(dev_t dev, int flag, int mode, struct proc *p)#elsecomopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;#endif{ register struct tty *tp; register int unit; int error = 0; unit = UNIT(dev); if (unit >= NCOM || (com_active & (1 << unit)) == 0) return (ENXIO); tp = &com_tty[unit]; tp->t_oproc = comstart; tp->t_param = comparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp); if (tp->t_ispeed == 0) { tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = comdefaultrate; } comparam(tp, &tp->t_termios); ttsetwater(tp); } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) return (EBUSY); (void) spltty(); (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET); if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD)) tp->t_state |= TS_CARR_ON; while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && (tp->t_state & TS_CARR_ON) == 0) { tp->t_state |= TS_WOPEN; if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0)) break; } (void) spl0(); if (error == 0) error = (*linesw[tp->t_line].l_open)(dev, tp); return (error);} /*ARGSUSED*/comclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ register struct tty *tp; register com; register int unit; unit = UNIT(dev); com = com_addr[unit]; tp = &com_tty[unit]; (*linesw[tp->t_line].l_close)(tp, flag); outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);#ifdef KGDB /* do not disable interrupts if debugging */ if (kgdb_dev != makedev(commajor, unit))#endif outb(com+com_ier, 0); if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || (tp->t_state&TS_ISOPEN) == 0) (void) commctl(dev, 0, DMSET); ttyclose(tp); return(0);} comread(dev, uio, flag) dev_t dev; struct uio *uio;{ register struct tty *tp = &com_tty[UNIT(dev)]; return ((*linesw[tp->t_line].l_read)(tp, uio, flag));} comwrite(dev, uio, flag) dev_t dev; struct uio *uio;{ int unit = UNIT(dev); register struct tty *tp = &com_tty[unit]; /* * (XXX) We disallow virtual consoles if the physical console is * a serial port. This is in case there is a display attached that * is not the console. In that situation we don't need/want the X * server taking over the console. */ if (constty && unit == comconsole) constty = NULL; return ((*linesw[tp->t_line].l_write)(tp, uio, flag));} comintr(unit) register int unit;{ register com; register u_char code; register struct tty *tp; com = com_addr[unit]; while (1) { code = inb(com+com_iir); switch (code & IIR_IMASK) { case IIR_NOPEND: return (1); case IIR_RXTOUT: case IIR_RXRDY: tp = &com_tty[unit];/* * Process received bytes. Inline for speed... */#ifdef KGDB#define RCVBYTE() \ code = inb(com+com_data); \ if ((tp->t_state & TS_ISOPEN) == 0) { \ if (kgdb_dev == makedev(commajor, unit) && \ code == FRAME_END) \ kgdb_connect(0); /* trap into kgdb */ \ } else \ (*linesw[tp->t_line].l_rint)(code, tp)#else#define RCVBYTE() \ code = inb(com+com_data); \ if (tp->t_state & TS_ISOPEN) \ (*linesw[tp->t_line].l_rint)(code, tp)#endif RCVBYTE(); if (com_hasfifo & (1 << unit)) while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { if (code == LSR_RXRDY) { RCVBYTE(); } else comeint(unit, code, com); } break; case IIR_TXRDY: tp = &com_tty[unit]; tp->t_state &=~ (TS_BUSY|TS_FLUSH); if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else comstart(tp); break; case IIR_RLS: comeint(unit, inb(com+com_lsr), com); break; default: if (code & IIR_NOPEND) return (1); log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", unit, code); /* fall through */ case IIR_MLSC: commint(unit, com); break; } }}comeint(unit, stat, com) register int unit, stat; register com;{ register struct tty *tp; register int c; tp = &com_tty[unit];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -