📄 ns16550sio.c
字号:
/* ns16550Sio.c - NS 16550 UART tty driver *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01m,24apr02,pmr SPR 75161: returning int from ns16550TxStartup() as required.01l,03apr02,jnz fixed bug at ns16550SioDrvFuncs declraation.01k,31oct01,mdg Corrected transmit interrtupt race condition found on on MIPS Malta board with RM5261 processor. (SPR# 71830)01j,14mar01,rcs corrected baud rate divisor calculation formula. (SPR# 63899)01i,17sep97,dat fixed merge problems that caused baud rate setting to fail.01h,06mar97,dat SPR 7899, max baud rate set to 115200.01g,08may97,db added hardware options and modem control(SPRs #7570, #7082).01f,18dec95,myz added case IIR_TIMEOUT in ns16550Int routine.01e,28nov95,myz fixed bugs to work at 19200 baud or above with heavy traffic.01d,09nov95,jdi doc: style cleanup.01c,02nov95,myz undo 01b fix01b,02nov95,p_m added test for 960CA and 960JX around access to lcr field in order to compile on all architectures.01a,24oct95,myz written from ns16550Serial.c.*//*DESCRIPTIONThis is the driver for the NS16552 DUART. This device includes two universalasynchronous receiver/transmitters, a baud rate generator, and a complete modem control capability. A NS16550_CHAN structure is used to describe the serial channel. This data structure is defined in ns16550Sio.h.Only asynchronous serial operation is supported by this driver.The default serial settings are 8 data bits, 1 stop bit, no parity, 9600baud, and software flow control. USAGEThe BSP's sysHwInit() routine typically calls sysSerialHwInit(),which creates the NS16550_CHAN structure and initializes all the values in the structure (except the SIO_DRV_FUNCS) before calling ns16550DevInit().The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(), whichconnects the chips interrupts via intConnect() (either the singleinterrupt `ns16550Int' or the three interrupts `ns16550IntWr', `ns16550IntRd',and `ns16550IntEx').This driver handles setting of hardware options such as parity(odd, even) andnumber of data bits(5, 6, 7, 8). Hardware flow control is provided with thehandshakes RTS/CTS. The function HUPCL(hang up on last close) is available.When hardware flow control is enabled, the signals RTS and DTR are set TRUE and remain set until a HUPCL is performed. INCLUDE FILES: drv/sio/ns16552Sio.h*//* includes */#include "vxWorks.h"#include "intLib.h"#include "errnoLib.h"#include "errno.h"#include "sioLib.h"#include "drv/sio/ns16552Sio.h"/* local defines */#ifndef SIO_HUP# define SIO_OPEN 0x100A# define SIO_HUP 0x100B#endif/* min/max baud rate */ #define NS16550_MIN_RATE 50#define NS16550_MAX_RATE 115200#define REG(reg, pchan) \ (*(volatile UINT8 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))#define REGPTR(reg, pchan) \ ((volatile UINT8 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))/* static forward declarations */LOCAL int ns16550CallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);LOCAL STATUS ns16550DummyCallback ();LOCAL void ns16550InitChannel (NS16550_CHAN *);LOCAL STATUS ns16550BaudSet (NS16550_CHAN *, UINT);LOCAL STATUS ns16550ModeSet (NS16550_CHAN *, UINT);LOCAL STATUS ns16550Ioctl (NS16550_CHAN *, int, int);LOCAL int ns16550TxStartup (NS16550_CHAN *);LOCAL int ns16550PollOutput (NS16550_CHAN *, char);LOCAL int ns16550PollInput (NS16550_CHAN *, char *);LOCAL STATUS ns16550OptsSet (NS16550_CHAN *, UINT);LOCAL STATUS ns16550Open (NS16550_CHAN * pChan );LOCAL STATUS ns16550Hup (NS16550_CHAN * pChan );/* driver functions */static SIO_DRV_FUNCS ns16550SioDrvFuncs = { (int (*)())ns16550Ioctl, (int (*)())ns16550TxStartup, (int (*)())ns16550CallbackInstall, (int (*)())ns16550PollInput, (int (*)(SIO_CHAN *,char))ns16550PollOutput };/******************************************************************************** ns16550DummyCallback - dummy callback routine.*/LOCAL STATUS ns16550DummyCallback (void) { return (ERROR); }/******************************************************************************** ns16550DevInit - intialize an NS16550 channel** This routine initializes some SIO_CHAN function pointers and then resets* the chip in a quiescent state. Before this routine is called, the BSP* must already have initialized all the device addresses, etc. in the* NS16550_CHAN structure.** RETURNS: N/A*/void ns16550DevInit ( NS16550_CHAN * pChan /* pointer to channel */ ) { int oldlevel = intLock (); /* initialize the driver function pointers in the SIO_CHAN's */ pChan->pDrvFuncs = &ns16550SioDrvFuncs; /* set the non BSP-specific constants */ pChan->getTxChar = ns16550DummyCallback; pChan->putRcvChar = ns16550DummyCallback; pChan->channelMode = 0; /* undefined */ pChan->options = (CLOCAL | CREAD | CS8); /* pChan->mcr = REG(MCR, pChan); pChan->lcr = REG(LCR, pChan); pChan->ier = REG(IER, pChan); */ pChan->mcr |= MCR_OUT2; /* reset the chip */ ns16550InitChannel (pChan); intUnlock (oldlevel); }/********************************************************************************* ns16550InitChannel - initialize UART** Initialize the number of data bits, parity and set the selected* baud rate.* Set the modem control signals if the option is selected.** RETURNS: N/A*/LOCAL void ns16550InitChannel ( NS16550_CHAN * pChan /* pointer to channel */ ) { /*clear UART register */ REG(MCR, pChan) =0;/*Auto-RTS and auto-CTS are disabled*/ REG(LCR, pChan) =0;/*5-bit character*/ REG(FCR, pChan) =0;/*FIFOs are disabled.*/ REG(IER, pChan) =0;/*Receiver data available (trigger threshold reached) interrupt disabled.*/ /* set the requested baud rate */ ns16550BaudSet(pChan, pChan->baudRate); /* set the options */ ns16550OptsSet(pChan, pChan->options); }/********************************************************************************* ns16550OptsSet - set the serial options** Set the channel operating mode to that specified. All sioLib options* are supported: CLOCAL, HUPCL, CREAD, CSIZE, PARENB, and PARODD.* When the HUPCL option is enabled, a connection is closed on the last* close() call and opened on each open() call.** Note, this routine disables the transmitter. The calling routine* may have to re-enable it.** RETURNS:* Returns OK to indicate success, otherwise ERROR is returned*/LOCAL STATUS ns16550OptsSet ( NS16550_CHAN * pChan, /* pointer to channel */ UINT options /* new hardware options */ ) { FAST int oldlevel; /* current interrupt level mask */ pChan->lcr = 0; pChan->mcr |= ((MCR_RTS | MCR_DTR)); /* clear RTS and DTR bits */ if (pChan == NULL || options & 0xffffff00) return ERROR; switch (options & CSIZE) { case CS5: pChan->lcr |= CHAR_LEN_5; break; case CS6: pChan->lcr |= CHAR_LEN_6; break; case CS7: pChan->lcr |= CHAR_LEN_7; break; default: case CS8: pChan->lcr |= CHAR_LEN_8; break; } if (options & STOPB) pChan->lcr |= LCR_STB; else pChan->lcr |= ONE_STOP; switch (options & (PARENB | PARODD)) { case PARENB|PARODD: pChan->lcr |= LCR_PEN; break; case PARENB: pChan->lcr |= (LCR_PEN | LCR_EPS); break; default: case 0: pChan->lcr |= PARITY_NONE; break; } /* REG(IER, pChan) = 0; */ if (!(options & CLOCAL)) { /* !clocal enables hardware flow control(DTR/DSR) */ pChan->mcr |= (MCR_DTR | MCR_RTS); pChan->ier &= (~TxFIFO_BIT); pChan->ier |= IER_EMSI; /* enable modem status interrupt */ } else pChan->ier &= ~IER_EMSI; /* disable modem status interrupt */ oldlevel = intLock (); REG(LCR, pChan) = pChan->lcr; REG(MCR, pChan) = pChan->mcr; /* now reset the channel mode registers *//* REG(FCR, pChan) = (RxCLEAR | TxCLEAR | FIFO_ENABLE); */ if (options & CREAD) pChan->ier |= RxFIFO_BIT; pChan->ier |= 0x40; if (pChan->channelMode == SIO_MODE_INT) { REG(IER, pChan) = pChan->ier; } REG(FCR,pChan) = FIFO_ENABLE; REG(FCR,pChan) = RxCLEAR | TxCLEAR | FIFO_ENABLE; intUnlock (oldlevel); pChan->options = options; return OK; }/********************************************************************************* ns16550Hup - hang up the modem control lines ** Resets the RTS and DTR signals and clears both the receiver and* transmitter sections.** RETURNS: OK*/LOCAL STATUS ns16550Hup ( NS16550_CHAN * pChan /* pointer to channel */ ) { FAST int oldlevel; /* current interrupt level mask */ oldlevel = intLock (); pChan->mcr &= (~(MCR_RTS | MCR_DTR)); REG(MCR, pChan) = pChan->mcr; REG(FCR, pChan) = (RxCLEAR | TxCLEAR); intUnlock (oldlevel); return (OK); } /********************************************************************************* ns16550Open - Set the modem control lines ** Set the modem control lines(RTS, DTR) TRUE if not already set. * It also clears the receiver, transmitter and enables the fifo. ** RETURNS: OK*/LOCAL STATUS ns16550Open ( NS16550_CHAN * pChan /* pointer to channel */ ) { FAST int oldlevel; /* current interrupt level mask */ char mask; mask = REG(MCR, pChan) & (MCR_RTS | MCR_DTR); if (mask != (MCR_RTS | MCR_DTR)) { /* RTS and DTR not set yet */ oldlevel = intLock (); /* set RTS and DTR TRUE */ pChan->mcr |= (MCR_DTR | MCR_RTS); REG(MCR, pChan) = pChan->mcr; /* clear Tx and receive and enable FIFO */ REG(FCR, pChan) = (RxCLEAR | TxCLEAR | FIFO_ENABLE); intUnlock (oldlevel); } return (OK); }/******************************************************************************** ns16550BaudSet - change baud rate for channel** This routine sets the baud rate for the UART. The interrupts are disabled* during chip access.** RETURNS: OK*/LOCAL STATUS ns16550BaudSet ( NS16550_CHAN * pChan, /* pointer to channel */ UINT baud /* requested baud rate */ ) { int oldlevel; int divisor = ((pChan->xtal + (8 * baud)) / (16 * baud)); /* int divisor =8;*/ /* disable interrupts during chip access */ oldlevel = intLock (); /* Enable access to the divisor latches by setting DLAB in LCR. */ /* REG(LCR, pChan) = LCR_DLAB | pChan->lcr;*/ REG(LCR, pChan) |= LCR_DLAB; /* Set divisor latches. */ REG(DLL,pChan) = (divisor&0xff); REG(DLM,pChan) = (divisor >> 8); /* Restore line control register *//* REG(LCR, pChan) = pChan->lcr;*/ REG(LCR, pChan) &= (~LCR_DLAB); pChan->baudRate = baud; /* intUnlock (oldlevel);*/ return (OK); }/********************************************************************************* ns16550ModeSet - change channel mode setting** This driver supports both polled and interrupt modes and is capable of* switching between modes dynamically. ** If interrupt mode is desired this routine enables the channels receiver and * transmitter interrupts. If the modem control option is TRUE, the Tx interrupt* is disabled if the CTS signal is FALSE. It is enabled otherwise. ** If polled mode is desired the device interrupts are disabled. ** RETURNS:* Returns a status of OK if the mode was set else ERROR.*/LOCAL STATUS ns16550ModeSet ( NS16550_CHAN * pChan, /* pointer to channel */ UINT newMode /* mode requested */ ) { FAST int oldlevel; /* current interrupt level mask */ char mask; if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT)) return (ERROR); oldlevel = intLock (); if (newMode == SIO_MODE_INT) { /* Enable appropriate interrupts */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -