ixp425Sio.c
资源名称:ixp425BSP.rar [点击查看]
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:20k
源码类别:
VxWorks
开发平台:
C/C++
- /* ixp425Sio.c - IXP425 UART tty driver */
- /* Copyright 2002 Wind River Systems, Inc. */
- #include "copyright_wrs.h"
- /*
- modification history
- --------------------
- 01b,06nov02,jb Fix compile warning
- 01a,05jun02,jb initial version...
- */
- /*
- DESCRIPTION
- This is the driver for the Intel IXP425 internal UART. This device comprises an
- asynchronous receiver/transmitter, a baud rate generator, and some modem control
- capability.
- An IXP425_SIO_CHAN structure is used to describe the serial channel. This data
- structure is defined in ixp425Sio.h.
- Only asynchronous serial operation is supported by this driver.
- The default serial settings are 8 data bits, 1 stop bit, no parity, 9600
- baud, and software flow control.
- USAGE
- The BSP's sysHwInit() routine typically calls sysSerialHwInit(),
- which creates the IXP425_SIO_CHAN structure and initializes all the values in the
- structure (except the SIO_DRV_FUNCS) before calling ixp425SioDevInit().
- The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(), which
- connects the chips interrupts via intConnect() (either the single
- interrupt 'ixp425SioInt' or the two interrupts 'ixp425SioIntWr', 'ixp425SioIntRd').
- This driver handles setting of hardware options such as parity(odd, even) and
- number of data bits(5, 6, 7, 8). Hardware flow control is provided with the
- handshakes RTS/CTS.
- INCLUDE FILES: ixp425Sio.h
- SEE ALSO:
- .I "ixp425 Data Sheet,"
- */
- /* includes */
- #include "vxWorks.h"
- #include "intLib.h"
- #include "errnoLib.h"
- #include "errno.h"
- #include "sioLib.h"
- #include "stdio.h"
- #include "ixp425Sio.h"
- #define IXP425_SIO_MIN_RATE 9600
- #define IXP425_SIO_MAX_RATE 921600
- #define IXP425_SIO_DEF_OPTS (CLOCAL | CREAD | CS8)
- #define REG(reg, pchan)
- (*(volatile UINT32 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))
- #define REGPTR(reg, pchan)
- ((volatile UINT32 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))
- /* for backward compatibility */
- #ifndef SIO_HUP
- #define SIO_OPEN 0x100A /* open channel, raise DTR, RTS */
- #define SIO_HUP 0x100B /* hang-up, lower DTR, RTS */
- #endif
- /* static forward declarations */
- LOCAL int ixp425SioCallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);
- LOCAL STATUS ixp425SioDummyCallback ();
- LOCAL void ixp425SioInitChannel (IXP425_SIO_CHAN *);
- LOCAL STATUS ixp425SioBaudSet (IXP425_SIO_CHAN *, UINT);
- LOCAL STATUS ixp425SioModeSet (IXP425_SIO_CHAN *, UINT);
- LOCAL STATUS ixp425SioIoctl (IXP425_SIO_CHAN *, int, int);
- LOCAL void ixp425SioTxStartup (IXP425_SIO_CHAN *);
- LOCAL int ixp425SioPollOutput (IXP425_SIO_CHAN *, char);
- LOCAL int ixp425SioPollInput (IXP425_SIO_CHAN *, char *);
- LOCAL STATUS ixp425SioOptsSet (IXP425_SIO_CHAN *, UINT);
- LOCAL void ixp425SioIntRd (IXP425_SIO_CHAN * pChan);
- /* driver functions */
- static SIO_DRV_FUNCS ixp425SioDrvFuncs =
- {
- (int (*)())ixp425SioIoctl,
- (int (*)())ixp425SioTxStartup,
- (int (*)())ixp425SioCallbackInstall,
- (int (*)())ixp425SioPollInput,
- (int (*)(SIO_CHAN *,char))ixp425SioPollOutput
- };
- /******************************************************************************
- *
- * ixp425SioDummyCallback - dummy callback routine.
- */
- LOCAL STATUS ixp425SioDummyCallback (void)
- {
- return (ERROR);
- }
- /******************************************************************************
- *
- * ixp425SioDevInit - initialise a UART channel
- *
- * This routine initialises some SIO_CHAN function pointers and then resets
- * the chip in a quiescent state. Before this routine is called, the BSP
- * must already have initialised all the device addresses, etc. in the
- * IXP425_SIO_CHAN structure.
- *
- * RETURNS: N/A
- */
- void ixp425SioDevInit
- (
- IXP425_SIO_CHAN * pChan /* pointer to channel */
- )
- {
- int oldlevel = intLock ();
- /* Initialise the driver function pointers in the SIO_CHAN's */
- pChan->pDrvFuncs = &ixp425SioDrvFuncs;
- #ifdef IXP425_SIO_DEBUG
- /* Initialise counter statistics */
- pChan->rxCount = 0;
- pChan->txCount = 0;
- pChan->overrunErr = 0;
- pChan->parityErr = 0;
- pChan->framingErr = 0;
- pChan->breakErr = 0;
- #endif
- /* Set the non BSP-specific constants */
- pChan->getTxChar = ixp425SioDummyCallback;
- pChan->putRcvChar = ixp425SioDummyCallback;
- pChan->options = IXP425_SIO_DEF_OPTS;
- pChan->mcr = MCR_OUT2;
- /*
- * Mode 0 is undefined. However the VxWorks ttyDrv will issue
- * an ioctl for mode set to change to interrupt mode when it
- * needs to use the UART.
- */
- pChan->channelMode = 0;
- /* Enable the device */
- pChan->ier = IER_UUE;
- /* Set hardware opts and baud rate */
- ixp425SioInitChannel (pChan);
- intUnlock (oldlevel);
- }
- /*******************************************************************************
- *
- * ixp425SioInitChannel - initialise UART
- *
- * Initialise 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 ixp425SioInitChannel
- (
- IXP425_SIO_CHAN * pChan /* pointer to channel */
- )
- {
- /* set the requested baud rate */
- ixp425SioBaudSet(pChan, pChan->baudRate);
- /* set the options */
- ixp425SioOptsSet(pChan, pChan->options);
- }
- /*******************************************************************************
- *
- * ixp425SioOptsSet - set the serial options
- *
- * Set the channel operating mode to that specified. The following sioLib options
- * are supported: CLOCAL, CREAD, CSIZE, PARENB, and PARODD.
- * The HUPCL option is not supported for now.
- *
- * 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 ixp425SioOptsSet
- (
- IXP425_SIO_CHAN * pChan, /* pointer to channel */
- UINT options /* new hardware options */
- )
- {
- FAST int oldlevel; /* current interrupt level mask */
- pChan->lcr = 0;
- pChan->mcr &= (~MCR_RTS); /* clear RTS bit */
- 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;
- case CS8:
- default:
- pChan->lcr = CHAR_LEN_8; break;
- }
- if (options & STOPB)
- pChan->lcr |= LCR_STB_2;
- else
- pChan->lcr |= LCR_STB_1;
- 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 |= LCR_PDIS; break;
- }
- REG(IER, pChan) = IER_UUE; /* disable interrupts, enable UART */
- if (!(options & CLOCAL)) /* use hardware flow control (RTS/CTS) */
- {
- pChan->mcr |= MCR_RTS;
- pChan->ier &= (~IER_TIE);
- pChan->ier |= IER_MIE; /* enable modem status interrupt */
- }
- else
- pChan->ier &= (~IER_MIE); /* software flow ctrl */
- oldlevel = intLock();
- REG(LCR, pChan) = (unsigned int) pChan->lcr;
- REG(MCR, pChan) = (unsigned int) pChan->mcr;
- /* Enable FIFOs and set trigger level */
- REG(FCR, pChan) = (unsigned int) (FCR_RESETRF | FCR_RESETTF | FCR_TRFIFOE);
- REG(FCR, pChan) |= (unsigned int) (FCR_ITL_32);
- if (options & CREAD)
- pChan->ier |= (IER_RAVIE | IER_RTOIE);
- if (pChan->channelMode == SIO_MODE_INT)
- {
- pChan->ier |= IER_RLSE;
- REG(IER, pChan) = (unsigned int) pChan->ier;
- }
- intUnlock (oldlevel);
- pChan->options = options;
- return OK;
- }
- /******************************************************************************
- *
- * ixp425SioBaudSet - 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 ixp425SioBaudSet
- (
- IXP425_SIO_CHAN * pChan, /* pointer to channel */
- UINT baud /* requested baud rate */
- )
- {
- FAST int oldlevel;
- /* disable interrupts during chip access */
- oldlevel = intLock ();
- /* Enable access to the divisor latches by setting DLAB in LCR. */
- REG(LCR, pChan) = (unsigned int) (LCR_DLAB | pChan->lcr);
- /* Set divisor latches. */
- REG(DLL, pChan) = (unsigned int) (pChan->xtal/(16 * baud));
- REG(DLM, pChan) = (unsigned int) ((pChan->xtal/(16 * baud)) >> 8);
- /* Restore line control register */
- REG(LCR, pChan) = (unsigned int) pChan->lcr;
- pChan->baudRate = baud;
- intUnlock (oldlevel);
- return (OK);
- }
- /*******************************************************************************
- *
- * ixp425SioModeSet - 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 channel's receiver
- * interrupt. The transmitter interrupt is enabled in TxStartup(). 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 ixp425SioModeSet
- (
- IXP425_SIO_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)
- {
- if (pChan->options & CLOCAL)
- {
- pChan->ier |= (IER_RAVIE | IER_RTOIE | IER_RLSE);
- REG(IER, pChan) = (unsigned int) pChan->ier;
- }
- else
- {
- mask = REG(MSR, pChan) & MSR_CTS;
- /* if the CTS is asserted enable Tx interrupt */
- if (mask & MSR_CTS)
- pChan->ier |= IER_TIE;
- else
- pChan->ier &= (~IER_TIE); /* disable Tx interrupt */
- REG(IER, pChan) = (unsigned int) pChan->ier;
- }
- }
- else /* Polled mode */
- {
- REG(IER, pChan) = (unsigned int) IER_UUE;
- }
- pChan->channelMode = newMode;
- intUnlock (oldlevel);
- return (OK);
- }
- /*******************************************************************************
- *
- * ixp425SioIoctl - special device control
- *
- * Includes commands to get/set baud rate, mode(INT,POLL), hardware options(
- * parity, number of data bits), and modem control(RTS/CTS).
- *
- * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
- * request.
- */
- LOCAL STATUS ixp425SioIoctl
- (
- IXP425_SIO_CHAN * pChan, /* pointer to channel */
- int request, /* request code */
- int arg /* some argument */
- )
- {
- FAST STATUS status;
- status = OK;
- switch (request)
- {
- case SIO_BAUD_SET:
- if (arg < IXP425_SIO_MIN_RATE || arg > IXP425_SIO_MAX_RATE)
- status = EIO; /* baud rate out of range */
- else
- status = ixp425SioBaudSet (pChan, arg);
- break;
- case SIO_BAUD_GET:
- *(int *)arg = pChan->baudRate;
- break;
- case SIO_MODE_SET:
- status = (ixp425SioModeSet (pChan, arg) == OK) ? OK : EIO;
- break;
- case SIO_MODE_GET:
- *(int *)arg = pChan->channelMode;
- break;
- case SIO_AVAIL_MODES_GET:
- *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
- break;
- case SIO_HW_OPTS_SET:
- status = (ixp425SioOptsSet (pChan, arg) == OK) ? OK : EIO;
- break;
- case SIO_HW_OPTS_GET:
- *(int *)arg = pChan->options;
- break;
- case SIO_HUP:
- /* Does nothing for now */
- break;
- case SIO_OPEN:
- /* Does nothing for now */
- break;
- default:
- status = ENOSYS;
- }
- return (status);
- }
- /*******************************************************************************
- *
- * ixp425SioIntWr - handle a transmitter interrupt
- *
- * This routine handles write interrupts from the UART. It reads a character
- * and puts it in the transmit holding register of the device for transfer.
- * If there are no more characters to transmit, transmission is disabled by
- * clearing the transmit interrupt enable bit in the IER(int enable register).
- * Any pending recieve data is also serviced.
- *
- * RETURNS: N/A
- *
- */
- void ixp425SioIntWr
- (
- IXP425_SIO_CHAN * pChan /* pointer to channel */
- )
- {
- char outChar;
- unsigned int charCnt = 0;
- while( (charCnt < IXP425_SIO_MAX_CNT) )
- {
- if((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
- {
- /*
- * At the time of this writing the TDRQ bit of the LSR is not working so we
- * can't check for character overuns. We get around this by making sure we only ever
- * write less then the size of the FIFO per ISR as represented by IXP425_SIO_MAX_CNT.
- */
- REG(THR, pChan) = (unsigned int)outChar;
- #ifdef IXP425_SIO_DEBUG
- pChan->txCount++;
- #endif
- charCnt++;
- }
- else
- {
- break;
- }
- }
- if (charCnt == 0)
- pChan->ier &= (~IER_TIE); /* disable Tx Int */
- /* Service any pending receive characters */
- ixp425SioIntRd(pChan);
- }
- /*******************************************************************************
- *
- * ixp425SioIntRd - handle a receiver interrupt
- *
- * This routine handles read interrupts from the UART.
- *
- * RETURNS: N/A
- *
- */
- void ixp425SioIntRd
- (
- IXP425_SIO_CHAN * pChan /* pointer to channel */
- )
- {
- char inchar;
- volatile char lsr;
- unsigned int charCnt = IXP425_SIO_MAX_CNT;
- lsr = REG(LSR, pChan);
- while( (lsr & LSR_DR) && (charCnt != 0) )
- {
- inchar = REG(RBR, pChan);
- (*pChan->putRcvChar)(pChan->putRcvArg, inchar);
- #ifdef IXP425_SIO_DEBUG
- pChan->rxCount++;
- #endif
- --charCnt;
- lsr = REG(LSR, pChan);
- }
- }
- #ifdef IXP425_SIO_DEBUG
- /*******************************************************************************
- *
- * ixp425SioIntErr - handle an error interrupt
- *
- * This routine handles error interrupts from the UART.
- *
- * RETURNS: N/A
- *
- */
- void ixp425SioIntErr
- (
- IXP425_SIO_CHAN * pChan, /* pointer to channel */
- char intErr
- )
- {
- if(intErr & LSR_OE)
- pChan->overrunErr++;
- if(intErr & LSR_PE)
- pChan->parityErr++;
- if(intErr & LSR_FE)
- pChan->framingErr++;
- if(intErr & LSR_BI)
- pChan->breakErr++;
- }
- #endif
- /*******************************************************************************
- *
- * ixp425SioInt - interrupt level processing
- *
- * This function handles four sources of interrupts from the UART. They are
- * prioritized in the following order by the Interrupt Identification Register
- * 'Receiver Line Status', 'Received Data Ready', 'Transmit Holding Register Empty'
- * and 'Modem Status'.
- *
- * When a modem status interrupt occurs, the transmit interrupt is enabled if
- * the CTS signal is TRUE.
- *
- * RETURNS: N/A
- */
- void ixp425SioInt
- (
- IXP425_SIO_CHAN * pChan /* pointer to channel */
- )
- {
- FAST volatile char intStatus;
- /* read the Interrrupt Identification Register */
- intStatus = (char)((REG(IIR, pChan)) & 0x0f);
- REG(IER,pChan) = 0; /* disable interrupts */
- switch (intStatus)
- {
- case IIR_RLS: /* overrun,parity error and break interrupt */
- intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */
- #ifdef IXP425_SIO_DEBUG
- ixp425SioIntErr (pChan, intStatus);
- #endif
- break;
- case IIR_RDA: /* received data available */
- case IIR_TIMEOUT:
- ixp425SioIntRd (pChan);
- break;
- case IIR_THRE: /* transmitter holding register empty */
- ixp425SioIntWr (pChan);
- break;
- case IIR_MSTAT: /* modem status register */
- {
- char msr;
- msr = REG(MSR, pChan);
- /* if CTS is asserted by modem, enable tx interrupt */
- if ((msr & MSR_CTS) && (msr & MSR_DCTS))
- pChan->ier |= IER_TIE;
- else
- pChan->ier &= (~IER_TIE);
- }
- break;
- default:
- break;
- }
- REG(IER, pChan) = (unsigned int) pChan->ier; /* re-enable interrupts */
- }
- /*******************************************************************************
- *
- * ixp425SioTxStartup - transmitter startup routine
- *
- * Call interrupt level character output routine and enable interrupt if it is
- * in interrupt mode with no hardware flow control.
- * If the option for hardware flow control is enabled and CTS is set TRUE,
- * then the Tx interrupt is enabled.
- *
- * RETURNS: N/A
- */
- LOCAL void ixp425SioTxStartup
- (
- IXP425_SIO_CHAN * pChan /* pointer to channel */
- )
- {
- char mask;
- if (pChan->channelMode == SIO_MODE_INT)
- {
- if (pChan->options & CLOCAL) /* Software flow control */
- {
- pChan->ier |= IER_TIE;
- REG(IER, pChan) = (unsigned int) pChan->ier;
- }
- else
- {
- mask = REG(MSR, pChan) & MSR_CTS;
- if (mask & MSR_CTS)
- pChan->ier |= IER_TIE;
- else
- pChan->ier &= (~IER_TIE);
- REG(IER, pChan) = (unsigned int) pChan->ier;
- }
- }
- }
- /******************************************************************************
- *
- * ixp425SioPollOutput - output a character in polled mode. Used by the
- * Windriver debug agent.
- *
- * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
- * if the output buffer if full.
- */
- LOCAL int ixp425SioPollOutput
- (
- IXP425_SIO_CHAN * pChan, /* pointer to channel */
- char outChar /* char to send */
- )
- {
- char pollStatus = REG(LSR, pChan);
- char msr = REG(MSR, pChan);
- if (!(pollStatus & LSR_TDRQ))
- return (EAGAIN);
- if (!(pChan->options & CLOCAL)) /* hardare flow control */
- {
- if (msr & MSR_CTS)
- {
- REG(THR, pChan) = outChar;
- #ifdef IXP425_SIO_DEBUG
- pChan->txCount++;
- #endif
- }
- else
- return (EAGAIN);
- }
- else
- {
- REG(THR, pChan) = outChar; /* transmit character */
- #ifdef IXP425_SIO_DEBUG
- pChan->txCount++;
- #endif
- }
- return (OK);
- }
- /******************************************************************************
- *
- * ixp425SioPollInput - poll the device for input. Used by the Windriver
- * debug agent.
- *
- * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
- * if the input buffer if empty.
- */
- LOCAL int ixp425SioPollInput
- (
- IXP425_SIO_CHAN * pChan, /* pointer to channel */
- char * pChar /* pointer to char */
- )
- {
- char pollStatus = REG(LSR, pChan);
- if (!(pollStatus & LSR_DR))
- return (EAGAIN);
- *pChar = REG(RBR, pChan);
- #ifdef IXP425_SIO_DEBUG
- pChan->rxCount++;
- #endif
- return (OK);
- }
- /******************************************************************************
- *
- * ixp425SioCallbackInstall - install ISR callbacks to get/put chars.
- *
- * This routine installs the callback functions for the driver
- *
- * RETURNS: OK on success or ENOSYS on unsupported callback type.
- */
- LOCAL int ixp425SioCallbackInstall
- (
- SIO_CHAN * pSioChan, /* pointer to device to control */
- int callbackType, /* callback type(tx or receive) */
- STATUS (*callback)(), /* pointer to callback function */
- void * callbackArg /* callback function argument */
- )
- {
- IXP425_SIO_CHAN * pChan = (IXP425_SIO_CHAN *)pSioChan;
- switch (callbackType)
- {
- case SIO_CALLBACK_GET_TX_CHAR:
- pChan->getTxChar = callback;
- pChan->getTxArg = callbackArg;
- return (OK);
- case SIO_CALLBACK_PUT_RCV_CHAR:
- pChan->putRcvChar = callback;
- pChan->putRcvArg = callbackArg;
- return (OK);
- default:
- return (ENOSYS);
- }
- }
- /******************************************************************************
- *
- * ixp425SioStatsShow - display UART error statistics.
- *
- * PRE: This routine requires that printf() is available.
- *
- * RETURNS: N/A
- */
- void ixp425SioStatsShow
- (
- IXP425_SIO_CHAN * pChan
- )
- {
- printf("nIXP425 UART Statistics:");
- #ifdef IXP425_SIO_DEBUG
- printf("nrxCount:t%u", pChan->rxCount);
- printf("ntxCount:t%u", pChan->txCount);
- printf("noverrun Errors:t%u", pChan->overrunErr);
- printf("nparity Errors:t%u", pChan->parityErr);
- printf("nframing Errors:t%u", pChan->framingErr);
- printf("nbreak Errors:t%un", pChan->breakErr);
- #else
- printf("nUART statistics not availablen");
- #endif /* IXP425_SIO_DEBUG */
- }