cy.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,536 行 · 第 1/5 页
C
2,536 行
/*- * 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.83 1999/01/08 19:17:46 bde Exp $ */#include "opt_compat.h"#include "opt_devfs.h"#include "cy.h"/* * TODO: * Atomic COR change. * 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/tty.h>#include <sys/proc.h>#include <sys/conf.h>#include <sys/dkstat.h>#include <sys/fcntl.h>#include <sys/interrupt.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/syslog.h>#ifdef DEVFS#include <sys/devfsext.h>#endif#include <machine/clock.h>#include <machine/ipl.h>#ifndef SMP#include <machine/lock.h>#endif#include <i386/isa/isa_device.h>#include <i386/isa/cyreg.h>#include <i386/isa/ic/cd1400.h>#ifdef SMP#define disable_intr() COM_DISABLE_INTR()#define enable_intr() COM_ENABLE_INTR()#endif /* SMP *//* * 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 commctl cymctl#define comparam cyparam#define comspeed cyspeed#define comstart cystart#define comwakeup cywakeup#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 siointr cyintr#define siointr1 cyintr1#define sioioctl cyioctl#define sioopen cyopen#define siopoll cypoll#define sioprobe cyprobe#define sioread cyread#define siosettimeout cysettimeout#define siostop cystop#define siowrite cywrite#define sio_registered cy_registered#define sio_timeout cy_timeout#define sio_timeout_handle cy_timeout_handle#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 0x1F/* * ETC states. com->etc may also contain a hardware ETC command value, * meaning that execution of that command is pending. */#define ETC_NONE 0 /* we depend on bzero() setting this */#define ETC_BREAK_STARTING 1#define ETC_BREAK_STARTED 2#define ETC_BREAK_ENDING 3#define ETC_BREAK_ENDED 4#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */#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) >> 16) * CY_MAX_PORTS \ | (((mynor) & 0xff) & ~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 */#define CSE_ODONE 1 /* output transmitted */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 */#endif u_char etc; /* pending Embedded Transmit Command */ u_char extra_state; /* more flag bits, separate for order trick */#if 0 u_char fifo_image; /* copy of value written to FIFO */#endif u_char gfrcr_image; /* copy of value read from GFRCR */#if 0 bool_t hasfifo; /* nonzero for 16550 UARTs */ bool_t loses_outints; /* nonzero if device loses output interrupts */#endif u_char mcr_dtr; /* MCR bit that is wired to DTR */ u_char mcr_image; /* copy of value written to MCR */ u_char mcr_rts; /* MCR bit that is wired to RTS */#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 */ int cy_align; /* index for register alignment */ cy_addr cy_iobase; /* base address of this port's cyclom */ cy_addr iobase; /* base address of this port's cd1400 */ int mcr_rts_reg; /* cd1400 reg number of reg holding mcr_rts */ 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; bool_t do_dcd_timestamp; struct timeval timestamp; struct timeval dcd_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 car; /* CD1400 CAR shadow (if first unit in cd) */ 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];#ifdef DEVFS void *devfs_token_ttyd; void *devfs_token_ttyl; void *devfs_token_ttyi; void *devfs_token_cuaa; void *devfs_token_cual; void *devfs_token_cuai;#endif};/* PCI driver entry point. */int cyattach_common __P((cy_addr cy_iobase, int cy_align));ointhand2_t siointr;static int cy_units __P((cy_addr cy_iobase, int cy_align));static int sioattach __P((struct isa_device *dev));static void cd1400_channel_cmd __P((struct com_s *com, int cmd));static void cd1400_channel_cmd_wait __P((struct com_s *com));static void cd_etc __P((struct com_s *com, int etc));static int cd_getreg __P((struct com_s *com, int reg));static void cd_setreg __P((struct com_s *com, int reg, int val));static timeout_t siodtrwakeup;static void comhardclose __P((struct com_s *com));#if 0static void siointr1 __P((struct com_s *com));#endifstatic int commctl __P((struct com_s *com, int bits, int how));static int comparam __P((struct tty *tp, struct termios *t));static swihand_t siopoll;static int sioprobe __P((struct isa_device *dev));static void siosettimeout __P((void));static int comspeed __P((speed_t speed, u_long cy_clock, 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));#endifstatic char driver_name[] = "cy";/* 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])struct isa_driver siodriver = { sioprobe, sioattach, driver_name};static d_open_t sioopen;static d_close_t sioclose;static d_read_t sioread;static d_write_t siowrite;static d_ioctl_t sioioctl;static d_stop_t siostop;static d_devtotty_t siodevtotty;#define CDEV_MAJOR 48static struct cdevsw sio_cdevsw = { sioopen, sioclose, sioread, siowrite, sioioctl, siostop, noreset, siodevtotty, ttpoll, nommap, NULL, driver_name, NULL, -1, nodump, nopsize, D_TTY,};static int comconsole = -1;static speed_t comdefaultrate = TTYDEF_SPEED;static u_int com_events; /* input chars + weighted output completions */static bool_t sio_registered;static int sio_timeout;static int sio_timeouts_until_log;static struct callout_handle sio_timeout_handle = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);#if 0 /* XXX */static struct tty *sio_tty[NSIO];#elsestatic struct tty sio_tty[NSIO];#endifstatic const int nsio_tty = NSIO;#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_chip_offset[] = { 0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00,};static int cy_nr_cd1400s[NCY];static int cy_total_devices;#undef RxFifoThresholdstatic int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);static intsioprobe(dev) struct isa_device *dev;{ cy_addr iobase; iobase = (cy_addr)dev->id_maddr; /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ cy_inb(iobase, CY16_RESET, 0); /* 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, 0); DELAY(500); return (cy_units(iobase, 0) == 0 ? 0 : -1);}static intcy_units(cy_iobase, cy_align) cy_addr cy_iobase; int cy_align;{ int cyu; u_char firmware_version; int i; cy_addr iobase; for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) { iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align); /* wait for chip to become ready for new command */ for (i = 0; i < 10; i++) { DELAY(50); if (!cd_inb(iobase, CD1400_CCR, cy_align)) break; } /* clear the GFRCR register */ cd_outb(iobase, CD1400_GFRCR, cy_align, 0); /* issue a reset command */ cd_outb(iobase, CD1400_CCR, cy_align, 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, cy_align); 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; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?