cy.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,542 行 · 第 1/5 页
C
2,542 行
/*- * cyclades cyclom-y serial driver * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993 * * Copyright (c) 1993 Andrew Herbert. * 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. The name Andrew Herbert may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ``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 I 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. * * $\Id: cy.c,v 1.7.4.3 1996/01/29 04:44:13 bde Exp $ */#include "cy.h"#if NCY > 0/* * TODO: * Check that cy16's work. * Implement BREAK. * Fix overflows when closing line. * Atomic COR change. * Don't report individual ports in devconf; busy flag for board should be * union of the current individual busy flags. * Consoles. *//* * Temporary compile-time configuration options. */#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2) /* Number of chars in the receiver FIFO before an * an interrupt is generated. Should depend on * line speed. Needs to be about 6 on a 486DX33 * for 4 active ports at 115200 bps. Why doesn't * 10 work? */#define PollMode /* Use polling-based irq service routine, not the * hardware svcack lines. Must be defined for * Cyclom-16Y boards. Less efficient for Cyclom-8Ys, * and stops 4 * 115200 bps from working. */#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly * the output CR/LF processing, plus we can avoid a * few checks usually done in ttyinput(). * * XXX not fully implemented, and not particularly * worthwhile. */#undef CyDebug /* Include debugging code (not very expensive). *//* These will go away. */#undef SOFT_CTS_OFLOW#define SOFT_HOTCHAR#include <sys/param.h>#include <sys/systm.h>#include <sys/reboot.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/conf.h>#include <sys/dkstat.h>#include <sys/file.h>#include <sys/uio.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/syslog.h>#include <sys/devconf.h>#include <sys/interrupt.h>#include <machine/clock.h>#include <i386/isa/icu.h> /* XXX just to get at `imen' */#include <i386/isa/isa.h>#include <i386/isa/isa_device.h>#include <i386/isa/cyreg.h>#include <i386/isa/ic/cd1400.h>/* * Dictionary so that I can name everything *sio* or *com* to compare with * sio.c. There is also lots of ugly formatting and unnecessary ifdefs to * simplify the comparision. These will go away. */#define LSR_BI CD1400_RDSR_BREAK#define LSR_FE CD1400_RDSR_FE#define LSR_OE CD1400_RDSR_OE#define LSR_PE CD1400_RDSR_PE#define MCR_DTR CD1400_MSVR2_DTR#define MCR_RTS CD1400_MSVR1_RTS#define MSR_CTS CD1400_MSVR2_CTS#define MSR_DCD CD1400_MSVR2_CD#define MSR_DSR CD1400_MSVR2_DSR#define MSR_RI CD1400_MSVR2_RI#define NSIO (NCY * CY_MAX_PORTS)#define comconsole cyconsole#define comdefaultrate cydefaultrate#define com_events cy_events#define comhardclose cyhardclose#define commajor cymajor#define commctl cymctl#define comparam cyparam#define comspeed cyspeed#define comstart cystart#define comwakeup cywakeup#define kdc_sio kdc_cy#define nsio_tty ncy_tty#define p_com_addr p_cy_addr#define sioattach cyattach#define sioclose cyclose#define siodevtotty cydevtotty#define siodriver cydriver#define siodtrwakeup cydtrwakeup#define sioioctl cyioctl#define siointr cyintr#define siointr1 cyintr1#define siointrts cyintrts#define sioopen cyopen#define siopoll cypoll#define sioprobe cyprobe#define sioread cyread#define sioregisterdev cyregisterdev#define siosettimeout cysettimeout#define siostop cystop#define siowrite cywrite#define sio_timeout cy_timeout#define sio_timeouts_until_log cy_timeouts_until_log#define sio_tty cy_tty#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */#define CD1400_xIVR_CHAN_SHIFT 3#define CD1400_xIVR_CHAN 0x0F /* XXX reduce to pack Cyclom-8Ys */#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)#define RS_IBUFSIZE 256#define CALLOUT_MASK 0x80#define CONTROL_MASK 0x60#define CONTROL_INIT_STATE 0x20#define CONTROL_LOCK_STATE 0x40#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)/* * Input buffer watermarks. * The external device is asked to stop sending when the buffer exactly reaches * high water, or when the high level requests it. * The high level is notified immediately (rather than at a later clock tick) * when this watermark is reached. * The buffer size is chosen so the watermark should almost never be reached. * The low watermark is invisibly 0 since the buffer is always emptied all at * once. */#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)/* * com state bits. * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher * than the other bits so that they can be tested as a group without masking * off the low bits. * * The following com and tty flags correspond closely: * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and * siostop()) * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart()) * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) * TS_FLUSH is not used. * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). */#define CS_BUSY 0x80 /* output in progress */#define CS_TTGO 0x40 /* output not stopped by XOFF */#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */#define CS_CHECKMSR 1 /* check of MSR scheduled */#define CS_CTS_OFLOW 2 /* use CTS output flow control */#define CS_DTR_OFF 0x10 /* DTR held off */#define CS_ODONE 4 /* output completed */#define CS_RTS_IFLOW 8 /* use RTS input flow control */static char const * const error_desc[] = {#define CE_OVERRUN 0 "silo overflow",#define CE_INTERRUPT_BUF_OVERFLOW 1 "interrupt-level buffer overflow",#define CE_TTY_BUF_OVERFLOW 2 "tty-level buffer overflow",};#define CE_NTYPES 3#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])/* types. XXX - should be elsewhere */typedef u_char bool_t; /* boolean */typedef u_char volatile *cy_addr;/* queue of linear buffers */struct lbq { u_char *l_head; /* next char to process */ u_char *l_tail; /* one past the last char to process */ struct lbq *l_next; /* next in queue */ bool_t l_queued; /* nonzero if queued */};/* com device structure */struct com_s { u_char state; /* miscellaneous flag bits */ bool_t active_out; /* nonzero if the callout device is open */#if 0 u_char cfcr_image; /* copy of value written to CFCR */ u_char ftl; /* current rx fifo trigger level */ u_char ftl_init; /* ftl_max for next open() */ u_char ftl_max; /* maximum ftl for curent open() */ bool_t hasfifo; /* nonzero for 16550 UARTs */ bool_t loses_outints; /* nonzero if device loses output interrupts */#endif u_char mcr_image; /* copy of value written to MCR */#if 0#ifdef COM_MULTIPORT bool_t multiport; /* is this unit part of a multiport device? */#endif /* COM_MULTIPORT */ bool_t no_irq; /* nonzero if irq is not attached */ bool_t poll; /* nonzero if polling is required */ bool_t poll_output; /* nonzero if polling for output is required */#endif int unit; /* unit number */ int dtr_wait; /* time to hold DTR down on close (* 1/hz) */#if 0 u_int tx_fifo_size;#endif u_int wopeners; /* # processes waiting for DCD in open() */ /* * The high level of the driver never reads status registers directly * because there would be too many side effects to handle conveniently. * Instead, it reads copies of the registers stored here by the * interrupt handler. */ u_char last_modem_status; /* last MSR read by intr handler */ u_char prev_modem_status; /* last MSR handled by high level */ u_char hotchar; /* ldisc-specific char to be handled ASAP */ u_char *ibuf; /* start of input buffer */ u_char *ibufend; /* end of input buffer */ u_char *ihighwater; /* threshold in input buffer */ u_char *iptr; /* next free spot in input buffer */ struct lbq obufq; /* head of queue of output buffers */ struct lbq obufs[2]; /* output buffers */ cy_addr cy_iobase; /* base address of this port's cyclom */ cy_addr iobase; /* base address of this port's cd1400 */ struct tty *tp; /* cross reference */ /* Initial state. */ struct termios it_in; /* should be in struct tty */ struct termios it_out; /* Lock state. */ struct termios lt_in; /* should be in struct tty */ struct termios lt_out; bool_t do_timestamp; struct timeval timestamp; u_long bytes_in; /* statistics */ u_long bytes_out; u_int delta_error_counts[CE_NTYPES]; u_long error_counts[CE_NTYPES]; u_int recv_exception; /* exception chars received */ u_int mdm; /* modem signal changes */#ifdef CyDebug u_int start_count; /* no. of calls to comstart() */ u_int start_real; /* no. of calls that did something */#endif u_char channel_control;/* CD1400 CCR control command shadow */ u_char cor[3]; /* CD1400 COR1-3 shadows */ u_char intr_enable; /* CD1400 SRER shadow */ /* * Ping-pong input buffers. The extra factor of 2 in the sizes is * to allow for an error byte for each input byte. */#define CE_INPUT_OFFSET RS_IBUFSIZE u_char ibuf1[2 * RS_IBUFSIZE]; u_char ibuf2[2 * RS_IBUFSIZE]; /* * Data area for output buffers. Someday we should build the output * buffer queue without copying data. */ u_char obuf1[256]; u_char obuf2[256]; struct kern_devconf kdc;};/* * XXX public functions in drivers should be declared in headers produced * by `config', not here. *//* Interrupt handling entry points. */void siointr __P((int unit));void siointrts __P((int unit));void siopoll __P((void));/* Device switch entry points. */int sioopen __P((dev_t dev, int oflags, int devtype, struct proc *p));int sioclose __P((dev_t dev, int fflag, int devtype, struct proc *p));int sioread __P((dev_t dev, struct uio *uio, int ioflag));int siowrite __P((dev_t dev, struct uio *uio, int ioflag));int sioioctl __P((dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p));void siostop __P((struct tty *tp, int rw));#define sioreset noresetstruct tty *siodevtotty __P((dev_t dev));#define siommap nommap#define siostrategy nostrategystatic int sioattach __P((struct isa_device *dev));static void cd1400_channel_cmd __P((cy_addr iobase, int cmd));static timeout_t siodtrwakeup;static void comhardclose __P((struct com_s *com));static void siointr1 __P((struct com_s *com));static int commctl __P((struct com_s *com, int bits, int how));static int comparam __P((struct tty *tp, struct termios *t));static int sioprobe __P((struct isa_device *dev));static void sioregisterdev __P((struct isa_device *id));static void siosettimeout __P((void));static int comspeed __P((speed_t speed, int *prescaler_io));static void comstart __P((struct tty *tp));static timeout_t comwakeup;static void disc_optim __P((struct tty *tp, struct termios *t, struct com_s *com));#ifdef CyDebugvoid cystatus __P((int unit));#endif/* table and macro for fast conversion from a unit number to its com struct */static struct com_s *p_com_addr[NSIO];#define com_addr(unit) (p_com_addr[unit])static struct timeval intr_timestamp;struct isa_driver siodriver = { sioprobe, sioattach, "cy"};#ifdef COMCONSOLE#undef COMCONSOLE#define COMCONSOLE 1#else#define COMCONSOLE 0#endif#ifndef CONUNIT#define CONUNIT (0)#endifstatic int comconsole = CONUNIT;static speed_t comdefaultrate = TTYDEF_SPEED;static u_int com_events; /* input chars + weighted output completions */static int commajor;static int sio_timeout;static int sio_timeouts_until_log;#if 0 /* XXX */static struct tty *sio_tty[NSIO];#elsestatic struct tty sio_tty[NSIO];static int nsio_tty = NSIO;#endif#ifdef KGDB#include <machine/remote-sl.h>extern int kgdb_dev;extern int kgdb_rate;extern int kgdb_debug_init;#endif#ifdef CyDebugstatic u_int cd_inbs;static u_int cy_inbs;static u_int cd_outbs;static u_int cy_outbs;static u_int cy_svrr_probes;static u_int cy_timeouts;#endifstatic int cy_nr_cd1400s[NCY];#undef RxFifoThresholdstatic int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);static struct kern_devconf kdc_sio[NCY] = { { 0, 0, 0, /* filled in by dev_attach */ "cyc", 0, { MDDT_ISA, 0, "tty" }, isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, &kdc_isa0, /* parent */ 0, /* parentdata */ DC_UNCONFIGURED, /* state */ "Cyclades multiport board", DC_CLS_MISC /* just an ordinary device */} };static voidsioregisterdev(id) struct isa_device *id;{ int unit; unit = id->id_unit; if (unit != 0) kdc_sio[unit] = kdc_sio[0]; kdc_sio[unit].kdc_unit = unit; kdc_sio[unit].kdc_isa = id; dev_attach(&kdc_sio[unit]);}static intsioprobe(dev) struct isa_device *dev;{ int cyu; u_char firmware_version; cy_addr iobase; int unit; iobase = (cy_addr)dev->id_maddr; unit = dev->id_unit; if ((u_int)unit >= NCY) return (0); cy_nr_cd1400s[unit] = 0; sioregisterdev(dev); /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ cy_inb(iobase, CY16_RESET); /* XXX? */ DELAY(500); /* wait for the board to get its act together */ /* this is needed to get the board out of reset */ cy_outb(iobase, CY_CLEAR_INTR, 0); DELAY(500); for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu, iobase += CY_CD1400_MEMSIZE) { int i; /* wait for chip to become ready for new command */ for (i = 0; i < 10; i++) { DELAY(50); if (!cd_inb(iobase, CD1400_CCR)) break; } /* clear the GFRCR register */ cd_outb(iobase, CD1400_GFRCR, 0); /* issue a reset command */ cd_outb(iobase, CD1400_CCR, CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET); /* wait for the CD1400 to initialize itself */ for (i = 0; i < 200; i++) { DELAY(50); /* retrieve firmware version */ firmware_version = cd_inb(iobase, CD1400_GFRCR); if ((firmware_version & 0xf0) == 0x40) break; } /* * Anything in the 0x40-0x4F range is fine. * If one CD1400 is bad then we don't support higher * numbered good ones on this board. */ if ((firmware_version & 0xf0) != 0x40) break; ++cy_nr_cd1400s[unit]; } return (cy_nr_cd1400s[unit] == 0 ? 0 : -1);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?