⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i8250serial.c

📁 IXP425的BSP代码
💻 C
字号:
/* i8250Serial.c - I8250 tty driver *//* Copyright 1984-1996 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01p,18nov96,db	 put missing brackets in if-else statement(SPR #7411).01m,25jan95,vin	 removed magic numbers, replaced with macros.01n,15aug95,hdn  added support for i386ex, and cleanup.01m,14jun95,hdn  removed function declarations defined in sysLib.h.01l,06jun94,hdn  doc cleanup for 5.1.1 FCS.01k,22apr94,hdn  add a support for 38400.		 changed a description mentioned PC_KBD_TYPE.01j,30mar94,hdn  changed PC_CONSOLE tty number from 0,1 to 2,3.01i,17feb94,hdn  moved TY_CO_DEV structure from sysLib.c.01h,20oct93,vin  included support for keyboard and vga drivers01g,12oct93,hdn  added sysIntEnablePIC(), sysIntDisablePIC().01f,16jun93,hdn  renamed to i8250Serial.c.01e,21apr93,hdn  fixed a bug in tyCoInt.01d,09apr93,jdi  doc cleanup.01c,07apr93,hdn  renamed compaq to pc.01b,19oct92,hdn  supported nested interrupt.01a,15may92,hdn  written based on frc386 version.*//*DESCRIPTIONThis is the driver for the Intel 8250 UART Chip used on the PC 386.If the macro INCLUDE_PC_CONSOLE is defined then this driver alsoinitializes the keyboard and VGA console devices on the PC.If INCLUDE_PC_CONSOLE is defined then the keyboard and VGA consolesare created first. Depending on the definition of PC_KBD_TYPE in config.hthe corresponding keyboard driver is included.USER-CALLABLE ROUTINESMost of the routines in this driver are accessible only through the I/Osystem.  Two routines, however, must be called directly:  tyCoDrv() toinitialize the driver, and tyCoDevCreate() to create devices.Before the driver can be used, it must be initialized by calling tyCoDrv().This routine should be called exactly once, before any reads, writes, orcalls to tyCoDevCreate().  Normally, it is called from usrRoot() inusrConfig.c.Before a terminal can be used, it must be created, using tyCoDevCreate().Each port to be used should have exactly one device associated with itby calling this routine.IOCTL FUNCTIONSThis driver responds to all the same ioctl() codes as a normal tty driver;for more information, see the manual entry for tyLib.  As initialized, theavailable baud rates are 110, 300, 600, 1200, 2400, 4800, 9600, 19200, and38400.SEE ALSO: tyLib*/#include "vxWorks.h"#include "iv.h"#include "ioLib.h"#include "iosLib.h"#include "tyLib.h"#include "intLib.h"#include "errnoLib.h"#include "sysLib.h"#include "config.h"/* globals */TY_CO_DEV tyCoDv [N_UART_CHANNELS] =    {    {{{{NULL}}}, FALSE,     UART_LCR(COM1_BASE_ADR),     UART_LST(COM1_BASE_ADR),     UART_MDC(COM1_BASE_ADR),     UART_MSR(COM1_BASE_ADR),     UART_IER(COM1_BASE_ADR),     UART_IID(COM1_BASE_ADR),     UART_BRDL(COM1_BASE_ADR),     UART_BRDH(COM1_BASE_ADR),     UART_RDR(COM1_BASE_ADR)},    {{{{NULL}}}, FALSE,     UART_LCR(COM2_BASE_ADR),     UART_LST(COM2_BASE_ADR),     UART_MDC(COM2_BASE_ADR),     UART_MSR(COM2_BASE_ADR),     UART_IER(COM2_BASE_ADR),     UART_IID(COM2_BASE_ADR),     UART_BRDL(COM2_BASE_ADR),     UART_BRDH(COM2_BASE_ADR),     UART_RDR(COM2_BASE_ADR)},    };/* locals *//* baudTable is a table of the available baud rates, and the values to write * to the UART's baud rate divisor {high, low} register. the formula is * 1843200(source) / (16 * baudrate) */LOCAL BAUD baudTable [] =    {    {50, 2304}, {75, 1536}, {110, 1047}, {134, 857}, {150, 768},    {300, 384}, {600, 192}, {1200, 96}, {2000, 58}, {2400, 48},    {3600,32}, {4800, 24}, {7200,16}, {9600, 12}, {19200, 6}, {38400, 3}     };LOCAL int tyCoDrvNum;		/* driver number assigned to this driver *//* forward declarations */LOCAL void	tyCoStartup	(TY_CO_DEV *pTyCoDv);LOCAL int	tyCoOpen	(TY_CO_DEV *pTyCoDv, char *name, int mode);LOCAL STATUS	tyCoIoctl	(TY_CO_DEV *pTyCoDv, int request, int arg);LOCAL void	tyCoHrdInit	(void);#ifdef INCLUDE_PC_CONSOLE	/* if key board and VGA console needed */#include "serial/pcConsole.c"#include "serial/m6845Vga.c"#if (PC_KBD_TYPE == PC_PS2_101_KBD)	/* 101 KEY PS/2                 */#include "serial/i8042Kbd.c"#else#include "serial/i8048Kbd.c"		/* 83 KEY PC/PCXT/PORTABLE      */#endif /* (PC_KBD_TYPE == PC_XT_83_KBD) */#endif /* INCLUDE_PC_CONSOLE *//********************************************************************************* tyCoDrv - initialize the tty driver** This routine initializes the serial driver, sets up interrupt vectors,* and performs hardware initialization of the serial ports.** This routine should be called exactly once, before any reads, writes,* or calls to tyCoDevCreate().  Normally, it is called by usrRoot()* in usrConfig.c.** RETURNS: OK or ERROR if the driver cannot be installed.** SEE ALSO: tyCoDevCreate()*/STATUS tyCoDrv (void)    {    /* check if driver already installed */#ifdef INCLUDE_PC_CONSOLE    if (pcConDrv () == ERROR)       return (ERROR);#endif     if (tyCoDrvNum > 0)	return (OK);    tyCoHrdInit ();    tyCoDrvNum = iosDrvInstall (tyCoOpen, (FUNCPTR) NULL, tyCoOpen,				(FUNCPTR) NULL, tyRead, tyWrite, tyCoIoctl);    return (tyCoDrvNum == ERROR ? ERROR : OK);    }/********************************************************************************* tyCoDevCreate - create a device for an on-board serial port** This routine creates a device for a specified serial port.  Each port* to be used should have exactly one device associated with it by calling* this routine.** For instance, to create the device "/tyCo/0", with buffer sizes of 512* bytes, the proper call would be:* .CS*     tyCoDevCreate ("/tyCo/0", 0, 512, 512);* .CE** RETURNS: OK, or ERROR if the driver is not installed, the channel is* invalid, or the device already exists.** SEE ALSO: tyCoDrv()*/STATUS tyCoDevCreate    (    char *name,		/* name to use for this device */    FAST int channel,	/* physical channel for this device (0 only) */    int rdBufSize,	/* read buffer size, in bytes */    int wrtBufSize	/* write buffer size, in bytes */    )    {    TY_CO_DEV *pTyCoDv = &tyCoDv[channel];    if (channel >= N_UART_CHANNELS)	{#ifdef	INCLUDE_PC_CONSOLE        channel -= N_UART_CHANNELS;        if (channel < N_VIRTUAL_CONSOLES)	    return (pcConDevCreate (name, channel, rdBufSize, wrtBufSize));#endif	/* INCLUDE_PC_CONSOLE */	return (ERROR);	}    if (tyCoDrvNum <= 0)	{	errnoSet (S_ioLib_NO_DRIVER);	return (ERROR);	}    /* if this device already exists, don't create it */    if (pTyCoDv->created)	return (ERROR);    if (tyDevInit (&pTyCoDv->tyDev, rdBufSize, wrtBufSize, 	(FUNCPTR)tyCoStartup) != OK)	{	return (ERROR);	}#ifndef TY_CO_POLL    /* enable the receiver and receiver error */    sysOutByte (pTyCoDv->ier, 0x01);    if (channel == 0)	{	sysOutByte (UART_IER (COM1_BASE_ADR), I8250_IER_RDI_ENBL);	sysIntEnablePIC (COM1_INT_LVL);	}    else	{	sysOutByte (UART_IER (COM2_BASE_ADR), I8250_IER_RDI_ENBL);	sysIntEnablePIC (COM2_INT_LVL);	}#endif /* TY_CO_POLL XXX */    /* mark the device as created, and add the device to the I/O system */    pTyCoDv->created = TRUE;    return (iosDevAdd (&pTyCoDv->tyDev.devHdr, name, tyCoDrvNum));    }/********************************************************************************* tyCoHrdInit - initialize the UART*/LOCAL void tyCoHrdInit (void)    {    int oldLevel = intLock ();    TY_CO_DEV *pTyCoDv;    int ix;    for (ix = 0; ix < N_UART_CHANNELS; ix++)	{	pTyCoDv = &tyCoDv[ix];	/* initialization 9600 baud */	sysOutByte (pTyCoDv->ier,  0x00);	sysOutByte (pTyCoDv->mdc,  0x00);	sysInByte  (pTyCoDv->iid);	sysInByte  (pTyCoDv->lst);	sysInByte  (pTyCoDv->msr);	sysOutByte (pTyCoDv->lcr,  0x80);	sysOutByte (pTyCoDv->brdl, 0x0c);	sysOutByte (pTyCoDv->brdh, 0x00);	/* 8 data bits, 1 stop bit, no parity */	sysOutByte (pTyCoDv->lcr, 0x03);	/* enable the receiver and transmitter */	sysOutByte (pTyCoDv->mdc, 0x0b);	}    sysOutByte (UART_LCR (COM1_BASE_ADR),(I8250_LCR_WRD8 | I8250_LCR_DLAB));    sysOutByte (UART_BRDL (COM1_BASE_ADR), BAUD_9600_LSB);    sysOutByte (UART_BRDH (COM1_BASE_ADR), BAUD_9600_MSB);    sysOutByte (UART_LCR (COM1_BASE_ADR), (I8250_LCR_WRD8 | I8250_LCR_SB1));    sysOutByte (UART_MDC (COM1_BASE_ADR), (I8250_MCR_OUT2 | 					   I8250_MCR_RTS  | 					   I8250_MCR_DTR));    sysOutByte (UART_LCR (COM2_BASE_ADR), (I8250_LCR_WRD8 | I8250_LCR_DLAB));    sysOutByte (UART_BRDL (COM2_BASE_ADR), BAUD_9600_LSB);    sysOutByte (UART_BRDH (COM2_BASE_ADR), BAUD_9600_MSB);    sysOutByte (UART_LCR (COM2_BASE_ADR), (I8250_LCR_WRD8 | I8250_LCR_SB1));    sysOutByte (UART_MDC (COM2_BASE_ADR), (I8250_MCR_OUT2 |					   I8250_MCR_RTS  | 					   I8250_MCR_DTR));    /* all interrupts are masked out: the receiver interrupt will be enabled     * in the tyCoDevCreate      */    intUnlock (oldLevel);    } /********************************************************************************* tyCoOpen - open file to UART** ARGSUSED1*/LOCAL int tyCoOpen    (    TY_CO_DEV *pTyCoDv,    char *name,    int mode    )    {    return ((int) pTyCoDv);    }/********************************************************************************* tyCoIoctl - special device control** This routine handles FIOBAUDRATE requests and passes all others to tyIoctl.** RETURNS: OK or ERROR if invalid baud rate, or whatever tyIoctl returns.*/LOCAL STATUS tyCoIoctl    (    TY_CO_DEV *pTyCoDv,	/* device to control */    int request,	/* request code */    int arg		/* some argument */    )    {    int ix;    int status;    switch (request)	{	case FIOBAUDRATE:	    status = ERROR;	    for (ix = 0; ix < NELEMENTS (baudTable); ix++)		{		if (baudTable [ix].rate == arg)	/* lookup baud rate value */		    {    		    sysOutByte (pTyCoDv->lcr,I8250_LCR_DLAB | I8250_LCR_WRD8);    		    sysOutByte (pTyCoDv->lcr, 0x80);    		    sysOutByte (pTyCoDv->brdh, MSB (baudTable[ix].preset));    		    sysOutByte (pTyCoDv->brdl, LSB (baudTable[ix].preset));    		    sysOutByte (pTyCoDv->lcr, I8250_LCR_WRD8);		    status = OK;		    break;		    }		}	    break;	default:	    status = tyIoctl (&pTyCoDv->tyDev, request, arg);	    break;	}    return (status);    }/********************************************************************************* tyCoInt - handle a receiver/transmitter interrupt** This routine gets called to handle interrupts.* If there is another character to be transmitted, it sends it.  If* not, or if a device has never been created for this channel, just* disable the interrupt.*/void tyCoInt    (    TY_CO_DEV *pTyCoDv    )    {    char outChar;    char interruptID;    char lineStatus;    int ix = 0;    interruptID = sysInByte (pTyCoDv->iid);    do {	interruptID &= I8250_IIR_RLS;        if (interruptID == I8250_IIR_RLS)            lineStatus = sysInByte (pTyCoDv->lst);        else if (interruptID == I8250_IIR_RD)	    {            if (pTyCoDv->created)	        tyIRd (&pTyCoDv->tyDev, sysInByte (pTyCoDv->data));	    else	        sysInByte (pTyCoDv->data);	    }        else if (interruptID == I8250_IIR_THR)	    {            if ((pTyCoDv->created && tyITx (&pTyCoDv->tyDev, &outChar)) == OK)	        sysOutByte (pTyCoDv->data, outChar);            else	        sysOutByte (pTyCoDv->ier, I8250_IER_RDI_ENBL);	    }        interruptID = sysInByte (pTyCoDv->iid);	} while (((interruptID & I8250_IIR_PIMASK) == I8250_IIR_PI) && 		 (ix++ < 10));    }/********************************************************************************* tyCoStartup - transmitter startup routine** Call interrupt level character output routine.*/LOCAL void tyCoStartup    (    TY_CO_DEV *pTyCoDv		/* tty device to start up */    )    {    char 	outChar;    char 	lsrReg;    static int 	charCount = 0;    /* enable the transmitter and it should interrupt to write the next char */    if (tyITx (&pTyCoDv->tyDev, &outChar) == OK)	sysOutByte (pTyCoDv->data, outChar);	    sysOutByte (pTyCoDv->ier, (I8250_IER_THR_ENBL | I8250_IER_RDI_ENBL));    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -