📄 com.c
字号:
/* $OpenBSD: com.c,v 1.50 1999/08/08 16:28:17 niklas Exp $ *//* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ *//*- * Copyright (c) 1993, 1994, 1995, 1996 * Charles M. Hannum. All rights reserved. * Copyright (c) 1991 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 7.5 (Berkeley) 5/16/91 *//* * 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 <sys/types.h>#include <sys/device.h>/*#include <sys/vnode.h>*/#include <machine/bus.h>#include <machine/intr.h>#include <dev/ic/comreg.h>#include <dev/ic/comvar.h>#include <dev/ic/ns16550reg.h>#define com_lcr com_cfcr#ifndef NULL#define NULL 0#endif/* XXX: These belong elsewhere */cdev_decl(com);bdev_decl(com);static u_char tiocm_xxx2mcr __P((int));/* * XXX the following two cfattach structs should be different, and possibly * XXX elsewhere. */int comprobe __P((struct device *, void *, void *));void comattach __P((struct device *, struct device *, void *));void compwroff __P((struct com_softc *));void com_raisedtr __P((void *));#if NCOM_ISAstruct cfattach com_isa_ca = { sizeof(struct com_softc), comprobe, comattach};#endif#if NCOM_ISAPNPstruct cfattach com_isapnp_ca = { sizeof(struct com_softc), comprobe, comattach};#endifstruct cfdriver com_cd = { NULL, "com", DV_TTY};#ifndef CONSPEED#define CONSPEED B9600#endif#ifdef COMCONSOLEint comdefaultrate = CONSPEED; /* XXX why set default? */#elseint comdefaultrate = TTYDEF_SPEED;#endifint comconsaddr;int comconsinit;int comconsattached;bus_space_tag_t comconsiot;bus_space_handle_t comconsioh;tcflag_t comconscflag = TTYDEF_CFLAG;int commajor;int comsopen = 0;int comevents = 0;#ifdef KGDB#include <machine/remote-sl.h>extern int kgdb_dev;extern int kgdb_rate;extern int kgdb_debug_init;#endif#define DEVUNIT(x) (minor(x) & 0x7f)#define DEVCUA(x) (minor(x) & 0x80)/* Macros to clear/set/test flags. */#define SET(t, f) (t) |= (f)#define CLR(t, f) (t) &= ~(f)#define ISSET(t, f) ((t) & (f))/* Macros for determining bus type. */#if NCOM_ISA#define IS_ISA(parent) \ (strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") == 0)#else#define IS_ISA(parent) 0#endif#if NCOM_ISAPNP#define IS_ISAPNP(parent) \ (strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isapnp") == 0)#else#define IS_ISAPNP(parent) 0#endifintcomspeed(speed) long speed;{#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ int x, err; if (speed == 0) return 0; if (speed < 0) return -1; x = divrnd((COM_FREQ / 16), speed); if (x <= 0) return -1; err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000; if (err < 0) err = -err; if (err > COM_TOLERANCE) return -1; return x;#undef divrnd(n, q)}intcomprobe1(iot, ioh) bus_space_tag_t iot; bus_space_handle_t ioh;{ int i, k; /* force access to id reg */ bus_space_write_1(iot, ioh, com_lcr, 0); bus_space_write_1(iot, ioh, com_iir, 0); for (i = 0; i < 32; i++) { k = bus_space_read_1(iot, ioh, com_iir); if (k & 0x38) { bus_space_read_1(iot, ioh, com_data); /* cleanup */ } else break; } if (i >= 32) return 0; return 1;}intcomprobe(parent, match, aux) struct device *parent; void *match, *aux;{ bus_space_tag_t iot; bus_space_handle_t ioh; int iobase, needioh; int rv = 1; /* * XXX should be broken out into functions for isa probe and * XXX for commulti probe, with a helper function that contains * XXX most of the interesting stuff. */#if NCOM_ISA || NCOM_ISAPNP if (IS_ISA(parent) || IS_ISAPNP(parent)) { struct isa_attach_args *ia = aux; iot = ia->ia_iot; iobase = ia->ia_iobase; if (IS_ISAPNP(parent)) { ioh = ia->ia_ioh; needioh = 0; } else needioh = 1; } else#endif return(0); /* This cannot happen */ /* if it's in use as console, it's there. */ if (iobase == comconsaddr && !comconsattached) goto out; if (needioh && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { rv = 0; goto out; } rv = comprobe1(iot, ioh); if (needioh) bus_space_unmap(iot, ioh, COM_NPORTS);out:#if NCOM_ISA if (rv && IS_ISA(parent)) { struct isa_attach_args *ia = aux; ia->ia_iosize = COM_NPORTS; ia->ia_msize = 0; }#endif return (rv);}voidcomattach(parent, self, aux) struct device *parent, *self; void *aux;{ struct com_softc *sc = (void *)self; int iobase, irq; bus_space_tag_t iot; bus_space_handle_t ioh; u_int8_t lcr; /* * XXX should be broken out into functions for isa attach and * XXX for commulti attach, with a helper function that contains * XXX most of the interesting stuff. */ sc->sc_hwflags = 0; sc->sc_swflags = 0;#if NCOM_ISA || NCOM_ISAPNP if (IS_ISA(parent) || IS_ISAPNP(parent)) { struct isa_attach_args *ia = aux; /* * We're living on an isa. */ iobase = ia->ia_iobase; iot = ia->ia_iot; if (IS_ISAPNP(parent)) { /* No console support! */ ioh = ia->ia_ioh; } else { if (iobase != comconsaddr) { if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) panic("comattach: io mapping failed"); } else ioh = comconsioh; } irq = ia->ia_irq; } else#endif panic("comattach: impossible"); sc->sc_iot = iot; sc->sc_ioh = ioh; sc->sc_iobase = iobase; if (iobase == comconsaddr) { comconsattached = 1; /* * Need to reset baud rate, etc. of next print so reset * comconsinit. Also make sure console is always "hardwired". */ delay(1000); /* wait for output to finish */ comconsinit = 0; SET(sc->sc_hwflags, COM_HW_CONSOLE); SET(sc->sc_swflags, COM_SW_SOFTCAR); } /* * Probe for all known forms of UART. */ lcr = bus_space_read_1(iot, ioh, com_lcr); bus_space_write_1(iot, ioh, com_lcr, 0xbf); bus_space_write_1(iot, ioh, com_efr, 0); bus_space_write_1(iot, ioh, com_lcr, 0); bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE); delay(100); switch(bus_space_read_1(iot, ioh, com_iir) >> 6) { case 0: sc->sc_uarttype = COM_UART_16450; break; case 2: sc->sc_uarttype = COM_UART_16550; break; case 3: sc->sc_uarttype = COM_UART_16550A; break; default: sc->sc_uarttype = COM_UART_UNKNOWN; break; } if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */ bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); if (bus_space_read_1(iot, ioh, com_efr) == 0) { sc->sc_uarttype = COM_UART_ST16650; } else { bus_space_write_1(iot, ioh, com_lcr, 0xbf); if (bus_space_read_1(iot, ioh, com_efr) == 0) sc->sc_uarttype = COM_UART_ST16650V2; } } bus_space_write_1(iot, ioh, com_lcr, lcr); if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */ u_int8_t scr0, scr1, scr2; scr0 = bus_space_read_1(iot, ioh, com_scratch); bus_space_write_1(iot, ioh, com_scratch, 0xa5); scr1 = bus_space_read_1(iot, ioh, com_scratch); bus_space_write_1(iot, ioh, com_scratch, 0x5a); scr2 = bus_space_read_1(iot, ioh, com_scratch); bus_space_write_1(iot, ioh, com_scratch, scr0); if ((scr1 != 0xa5) || (scr2 != 0x5a)) sc->sc_uarttype = COM_UART_8250; } /* * Print UART type and initialize ourself. */ sc->sc_fifolen = 1; /* default */ switch (sc->sc_uarttype) { case COM_UART_UNKNOWN: printf(": unknown uart\n"); break; case COM_UART_8250: printf(": ns8250, no fifo\n"); break; case COM_UART_16450: printf(": ns16450, no fifo\n"); break; case COM_UART_16550: printf(": ns16550, no working fifo\n"); break; case COM_UART_16550A: printf(": ns16550a, 16 byte fifo\n"); SET(sc->sc_hwflags, COM_HW_FIFO); sc->sc_fifolen = 16; break; case COM_UART_ST16650: printf(": st16650, no working fifo\n"); break; case COM_UART_ST16650V2: printf(": st16650, 32 byte fifo\n"); SET(sc->sc_hwflags, COM_HW_FIFO); sc->sc_fifolen = 32; break; case COM_UART_TI16750: printf(": ti16750, 64 byte fifo\n"); SET(sc->sc_hwflags, COM_HW_FIFO); sc->sc_fifolen = 64; break; default: panic("comattach: bad fifo type"); } /* clear and disable fifo */ bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST); (void)bus_space_read_1(iot, ioh, com_data); bus_space_write_1(iot, ioh, com_fifo, 0); /* disable interrupts */ bus_space_write_1(iot, ioh, com_ier, 0); bus_space_write_1(iot, ioh, com_mcr, 0); /* XXX maybe move up some? */ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) printf("%s: console\n", sc->sc_dev.dv_xname); /* * If there are no enable/disable functions, assume the device * is always enabled. */ if (!sc->enable) sc->enabled = 1;}intcom_detach(self, flags) struct device *self; int flags;{ struct com_softc *sc = (struct com_softc *)self; int maj, mn; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == comopen) break; /* Nuke the vnodes for any open instances. */ mn = self->dv_unit; vdevgone(maj, mn, mn, VCHR); /* XXX a symbolic constant for the cua bit would be nicer. */ mn |= 0x80; vdevgone(maj, mn, mn, VCHR); /* Detach and free the tty. */ if (sc->sc_tty) { tty_detach(sc->sc_tty); ttyfree(sc->sc_tty); } untimeout(compoll, NULL); untimeout(com_raisedtr, sc); untimeout(comdiag, sc); return (0);}intcom_activate(self, act) struct device *self; enum devact act;{ struct com_softc *sc = (struct com_softc *)self; int s, rv = 0; s = spltty(); switch (act) { case DVACT_ACTIVATE: rv = EOPNOTSUPP; break; case DVACT_DEACTIVATE: if (sc->sc_hwflags & COM_HW_CONSOLE) { rv = EBUSY; break; } if (sc->disable != NULL && sc->enabled != 0) { (*sc->disable)(sc); sc->enabled = 0; } break; } splx(s); return (rv);}intcomopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ int unit = DEVUNIT(dev); struct com_softc *sc; bus_space_tag_t iot; bus_space_handle_t ioh; struct tty *tp; int s; int error = 0; if (unit >= com_cd.cd_ndevs) return ENXIO; sc = com_cd.cd_devs[unit]; if (!sc) return ENXIO; s = spltty(); if (!sc->sc_tty) { tp = sc->sc_tty = ttymalloc(); tty_attach(tp); } else tp = sc->sc_tty; splx(s); tp->t_oproc = comstart;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -