会员
周边
众包
新闻
博问
闪存
赞助商
所有博客
当前博客
我的博客
我的园子
账号设置
简洁模式
...
退出登录
注册
登录
张鹏的博客
嵌入式系统
at91 uart driver for vxworks
/* at91UART.c - AT91RM9200 serial driver */
/* Copyright 2003-2004 Coordinate Co., Ltd. */
/* Copyright 1984-2002 Wind River Systems, Inc. */
/*
modification history
--------------------
01a,28jul04,cor created from original at91Sio.c.
*/
/*
.SH TODO
- Replace the documentation for this template driver with documentation
for the driver being written.
- Begin with an overview of the complete device. Indicate if the new driver
only implements a sub-section of the whole device or not.
- Describe all of the operating modes of the device, and indicate which
ones this driver implements.
- Document the device initialization steps to be used in the BSP to create
and initialize the device. Document all the macros that
can be used to customize the driver to a particular hardware environment.
- Document anything that will help the user to understand how this device
works and interacts with this driver.
.SH TEMPLATE OVERVIEW
This is a template serial driver. It can be used as a starting point
when writing new drivers for VxWorks version 5.4 or later.
These drivers support new functionality not found in the older style
serial drivers. First, they provide an interface for setting hardware
options; e.g., the number of stop bits, data bits, parity, etc.
Second, they provide an interface for polled communication which
can be used to provided external mode debugging (i.e., ROM monitor
style debugging) over a serial line. Currently only asynchronous mode
drivers are supported.
Throughout this file the word "template" is used in place of a real
device name, which by convention uses the first letter of the
manufacturers name followed by the part number. For example, the
Zilog 8530 serial device would have a data structure called a
Z8530_CHAN, rather than TEMPLATE_CHAN.
.SH CALLBACKS
Servicing a "transmitter ready" interrupt involves making a callback to a
higher level library in order to get a character to transmit.
By default, this driver installs dummy callback routines which do
nothing. A higher layer library that wants to use this driver (e.g., ttyDrv)
will install its own callback routines using the SIO_INSTALL_CALLBACK
ioctl command. (See below).
The prototype for the transmit data callback SIO_CALLBACK_GET_TX_CHAR is:
.CS
int sioTxCharGet
(
void * arg, /@ callback argument @/
char * pChar /@ ptr to data location @/
)
.CE
This callback routine should fetch the next character to send and store it
in the location pointed to by pChar. It returns OK to indicate that a
character is ready and should be sent. It returns ERROR to indicate that
no character was available and the transmitter can be placed in an idle state.
Likewise, a receiver interrupt handler makes a callback to pass the
character to the higher layer library. It will be called by the driver
for each character received. This routine should capture the data and pass
it along to other layers and eventually to the user.
The prototype for the receive data callback SIO_CALLBACK_PUT_RCV_CHAR is:
.CS
void sioRxCharPut
(
void * arg, /@ callback argument @/
char data /@ data byte @/
)
.CE
A new error handling callback has been added SIO_CALLBACK_ERROR. This driver
should use this callback to inform the higher layer about error conditions.
The prototype for this callback is:
.CS
void sioErrorRtn
(
void * arg, /@ callback argument @/
int code, /@ error code @/
void * pData, /@ opt dev specific data @/
int dataSize /@ opt size of data in bytes @/
)
.CE
The available error codes for this callback are:
.CS
SIO_ERROR_FRAMING /@ (1) Framing error @/
SIO_ERROR_PARITY /@ (2) Parity error @/
SIO_ERROR_OFLOW /@ (3) data overflow @/
SIO_ERROR_UFLOW /@ (4) data underflow @/
SIO_ERROR_CONNECT /@ (5) connection made @/
SIO_ERROR_DISCONNECT /@ (6) connection lost @/
SIO_ERROR_NO_CLK /@ (7) clock lost @/
SIO_ERROR_UNKNWN /@ (8) other errors @/
.CE
For engineering purposes, the driver may return device specific data in
the form of a data buffer. The argument pData is the location of the buffer
and dataSize is its size, in bytes. The data is not guaranteed to be static
so it should be copied to a static buffer for safekeeping.
.SH MODES
Ideally the driver should support both polled and interrupt modes, and be
capable of switching modes dynamically. However this is not required.
VxWorks will be able to support a tty device on this driver even if
the driver only supports interrupt mode.
Polled mode is provided solely for WDB system mode usage. Users can use
the polled mode interface directly, but there is no clear reason for doing so.
Normal access to SIO devices through ttyDrv only uses interrupt mode.
For dynamically switchable drivers, be aware that the driver may be
asked to switch modes in the middle of its input ISR. A driver's input ISR
will look something like this:
inChar = *pDev->dr; /@ read a char from data register @/
*pDev->cr = GOT_IT; /@ acknowledge the interrupt @/
pDev->putRcvChar (...); /@ give the character to the higher layer @/
If this channel is used as a communication path to an external mode
debug agent, and if the character received is a special "end of packet"
character, then the agent's callback will lock interrupts, switch
the device to polled mode, and use the device in polled mode for awhile.
Later on the agent will unlock interrupts, switch the device back to
interrupt mode, and return to the ISR.
In particular, the callback can cause two mode switches, first to polled mode
and then back to interrupt mode, before it returns.
This may require careful ordering of the callback within the interrupt
handler. For example, you may need to acknowledge the interrupt before
invoking the callback.
.SH USAGE
The driver is typically called only by the BSP. The directly callable
routines in this module are templateSioCreate(), templateSioDestroy().
.SH BSP
By convention all the BSP-specific serial initialization is performed in
a file called sysSerial.c, which is #include'ed by sysLib.c.
This driver can be customized by redefining the macros SYS_SIO_READ8 and
SYS_SIO_WRITE8. These two macros are used for all accesses to the
actual chip. If not defined, the source code will assume a simple memory
mapped device using byte read/write access to all registers.
The macros SYS_SIO_INT_CONNECT, SYS_SIO_INT_DISCONNECT, SYS_SIO_INT_ENABLE,
and SYS_SIO_PROBE can be redefined by the BSP to perform basic low level
routines with the same calling sequence as intConnect(), intConnect(),
intEnable(), and vxMemProbe().
.SH TESTING
The interrupt driven interface can be tested in the usual way; VxWorks
prints to the serial console when it comes up, so seeing the usual VxWorks
output on power-up shows that the driver is basically working.
The VxWorks portkit test can be used to perform a more strenuous test.
The polled interface should be easy enough to verify - you should be able
to call the channels SIO_MODE_SET ioctl to put it in polled mode. Note
that the usual print tools won't work with a serial channel in polled mode.
Some agent has to perform a polling loop to handle input/output on a
character by character basis. It is not automatic. The WDB agent
performs its own polling loop when it switches the WDB serial line into
polled mode.
The dynamic mode switching can be verified using the tornado tools.
Reconfigure the agent to use the WDB_COMM_UDLP_SLIP communication path (see
the Configuration section in the VxWorks run-time Guide for details).
Start VxWorks, and connect the tgtsvr to the agent using the wdbserial
backend (see the Tornado Users Guide for details).
Start the wtxtcl shell as follows:
% wtxtcl
From the tcl prompt, attach to the target server:
wtxtcl.ex> wtxToolAttach <tgtsvr name>
Tell the agent to switch to external mode, and verify the reply is OK (0).
wtxtcl.ex>wtxAgentModeSet 2
0
Ask the agent to suspend the system (the request will reach the agent in
interrupt mode, but the reply will be sent in polled mode):
wtxtcl.ex>wtxContextSuspend 0 0
0
At this point the target will be suspended. The console should apprear
frozen (if the board has a console device), and you will not be able to
"ping" the target's network interface.
Resume the target:
wtxtcl.ex>wtxContextResume 0 0
0
The target should now be running again, so you should be able to type into
the console (if the board has a console device) and ping the targets network
interface from the host.
.SH INCLUDE FILES:
at91Sio.h sioLib.h
*/
#include "vxWorks.h"
#include "intLib.h"
#include "errnoLib.h"
#include "iosLib.h" /* For S_iosLib_DEVICE_NOT_FOUND */
#include "cacheLib.h"
#include "stdlib.h" /* malloc/free */
#include "stdio.h" /* for printf */
#include "vxLib.h" /* for vxMemProbe */
#include "at91.h"
#include "at91rm9200.h"
#include "at91If.h"
#include "at91Sio.h"
#include "arch\arm\ivarm.h"
#define DEFAULT_BAUD 9600
/* channel control register (write) definitions */
#if 0
/* TODO - These are just made up bit defines for a mythical device! */
#define TEMPLATE_RESET_CHIP 0x07 /* reset all */
#define TEMPLATE_RESET_TX 0x01 /* reset the transmitter */
#define TEMPLATE_RESET_ERR 0x02 /* reset error condition */
#define TEMPLATE_RESET_INT 0x04 /* acknoledge the interrupt */
#define TEMPLATE_INT_ENABLE 0x08 /* enable interrupts */
#define TEMPLATE_TX_ENABLE 0x10 /* enable interrupts */
#define TEMPLATE_RX_ENABLE 0x20 /* enable interrupts */
/* channel status register (read) definitions */
#define TEMPLATE_CR_OKAY 0x00 /* no error conditions */
#define TEMPLATE_CR_TX_READY 0x01 /* txmitter ready for another char */
#define TEMPLATE_CR_TX_ERROR 0x04 /* txmitter int enable */
#define TEMPLATE_CR_RX_AVAIL 0x10 /* character has arrived */
#define TEMPLATE_CR_RX_ERROR 0x40 /* receiver error */
/* channel modem status register definitions */
#define TEMPLATE_MSR_RTS 0x1 /* RTS signal asserted */
#define TEMPLATE_MSR_DTR 0x2 /* DTR signal asserted */
#define TEMPLATE_MSR_DSR 0x4 /* DSR signal asserted */
#define TEMPLATE_MSR_CTS 0x8 /* CTS signal asserted */
#define TEMPLATE_MSR_CD 0x10 /* CD signal asserted */
/* input and output signals */
#define TEMPLATE_ISIG_MASK (SIO_MODEM_CTS|SIO_MODEM_DSR|SIO_MODEM_CD)
#define TEMPLATE_OSIG_MASK (SIO_MODEM_RTS|SIO_MODEM_DTR)
/* channel modem control register definitions */
#define TEMPLATE_MC_RTS 0x1 /* enable RTS */
#define TEMPLATE_MC_DTR 0x2 /* enable DTR */
#endif
#define AT91_BAUD_MIN 110
#define AT91_BAUD_MAX 921600
/* Hardware abstraction macros */
#if 0
/* Macros from BSP */
#define SYS_SIO_READ8(addr, pData) \
(*pData = *(UINT8 *)(addr))
#define SYS_SIO_WRITE8(addr, data) \
(*(UINT8 *)addr = data)
#define SYS_SIO_INT_CONNECT(vec, rtn, arg) \
intConnect ((VOIDFUNCPTR *)vec, (VOIDFUNCPTR)rtn, (
int)arg)
#define SYS_SIO_INT_DISCONNECT(vec, rtn, arg) \
intConnect ((VOIDFUNCPTR *)vec, NULL, 0)
#define SYS_SIO_INT_ENABLE(level) \
intEnable (level)
#define SYS_SIO_PROBE(addr, mode, size, pData) \
vxMemProbe (addr, mode, size, pData)
/* #define CACHE_PIPE_FLUSH() */
/* Local driver abstractions, following bus/adaptor model */
#define TEMPLATE_SIO_READ8(pChan, reg, result) \
SYS_SIO_READ8(((pChan->ioBase) + reg),result)
#define TEMPLATE_SIO_WRITE8(pChan, reg, data) \
SYS_SIO_WRITE8(((pChan->ioBase) + reg),data)
#define TEMPLATE_SIO_INT_CONNECT(pChan, vec, rtn, arg) \
do { \
SYS_SIO_INT_CONNECT((pChan->vecBase) + vec, rtn, arg); \
SYS_SIO_INT_ENABLE(pChan->intLevel); \
}
while (0)
#define TEMPLATE_INT_DISCONNECT(pChan, vec, rtn, arg) \
SYS_SIO_INT_DISCONNECT(((pChan)->vecBase + vec), rtn, arg)
/* Do NOT disable interrupt level for disconnect */
#define TEMPLATE_PROBE(pChan, offset, dir, size, ptr) \
SYS_SIO_PROBE((
char *)((pChan)->ioBase + offset), dir, size, ptr)
#define TEMPLATE_PIPE_FLUSH(pChan) \
CACHE_PIPE_FLUSH()
#endif
/* forward static declarations */
LOCAL
int at91TxStartup (SIO_CHAN * pSioChan);
LOCAL
int at91CallbackInstall (SIO_CHAN *pSioChan,
int callbackType,
STATUS (*callback)(
void *,...),
void *callbackArg);
LOCAL
int at91PollOutput (SIO_CHAN *pSioChan,
char outChar);
LOCAL
int at91PollInput (SIO_CHAN *pSioChan,
char *thisChar);
LOCAL
int at91Ioctl (SIO_CHAN *pSioChan,
int request,
void *arg);
LOCAL STATUS at91DummyTxCallback (
void *,
char *);
LOCAL
void at91DummyRxCallback (
void *,
char);
LOCAL
void at91DummyErrCallback (
void *,
int,
void *,
int);
LOCAL
void at91UARTIntRx (AT91_UART_CHAN * pChan);
LOCAL
void at91UARTIntTx (AT91_UART_CHAN * pChan);
LOCAL STATUS at91Probe (AT91_UART_CHAN * pChan);
/*
LOCAL STATUS at91Verify (AT91_UART_CHAN *pChan);
LOCAL int at91MstatGet (AT91_UART_CHAN *pChan);
LOCAL int at91MstatSetClr (AT91_UART_CHAN *pChan, UINT bits, BOOL setFlag);
*/
/* local variables */
LOCAL SIO_DRV_FUNCS at91UARTDrvFuncs =
{
at91Ioctl,
at91TxStartup,
at91CallbackInstall,
at91PollInput,
at91PollOutput
};
/******************************************************************************
*
* at91UARTDevInit - initialise an AT91_SIO channel
*
* This routine initialises some SIO_CHAN function pointers and then resets
* the chip to a quiescent state. Before this routine is called, the BSP
* must already have initialised all the device addresses, etc. in the
* AT91_UART_CHAN structure.
*
* RETURNS: N/A
*/
void at91UARTDevInit
(
AT91_UART_CHAN * pChan
/* ptr to AT91_UART_CHAN describing this channel */
)
{
AT91PS_USART pUsart;
/* point to UART register index by ioBase of pChan */
AT91PS_PIO pPIOA, pPIOB;
/* point to PIO Controller A, B */
AT91_UART_PARAS *pParas;
int oldIntLvl;
if (pChan != NULL)
{
pChan->sio.pDrvFuncs = &at91UARTDrvFuncs;
/* install dummy driver callbacks */
pChan->getTxChar = at91DummyTxCallback;
pChan->putRcvChar = at91DummyRxCallback;
pChan->errorRtn = at91DummyErrCallback;
pChan->intConnect = FALSE;
/* int's not connected yet */
/* setting polled mode is one way to make the device quiet */
pChan->mode = SIO_MODE_POLL;
/* setting mode to poll mode */
if (at91Probe (pChan) == OK)
{
oldIntLvl = intLock();
pParas = pChan->pUart;
pChan->ioBase = pParas->ioBase;
/* set parameter of pParas to pChan for easy usage */
pUsart = (AT91PS_USART)(pParas->ioBase);
pPIOA = (AT91PS_PIO)(AT91RM9200_PIOA_BASE_ADDR);
pPIOB = (AT91PS_PIO)(AT91RM9200_PIOB_BASE_ADDR);
*(
volatile unsigned
int *)AT91RM9200_PMC_PCER = 1 << pParas->uartId;
/* enable clock */
pPIOA->PIO_ASR = pParas->PIOA_ASR;
pPIOA->PIO_BSR = pParas->PIOA_BSR;
pPIOA->PIO_PDR = pParas->PIOA_ASR | pParas->PIOA_BSR;
pPIOB->PIO_ASR = pParas->PIOA_ASR;
pPIOB->PIO_BSR = pParas->PIOA_BSR;
pPIOB->PIO_PDR = pParas->PIOB_ASR | pParas->PIOB_BSR;
pUsart->US_IDR = -1;
/* disable all USART interrupts */
/* reset & disble transmit and receive */
pUsart->US_CR = AT91RM9200_US_CR_RSTRX | AT91RM9200_US_CR_RSTTX | \
AT91RM9200_US_CR_RXDIS | AT91RM9200_US_CR_TXDIS;
pUsart->US_BRGR = AT91_MASTER_CLOCK / (pParas->baudRate) / 16;
/* 115200 baud with 18.432 Mhz Crystal */
pUsart->US_RTOR = AT91_USART_RX_TIMEOUT;
/* Receiver Time-out Register */
pUsart->US_TTGR = 0;
/* Transmitter timeguart is disabled */
pUsart->US_FIDI = 0;
/* in ISO7816 mode, BRG generates no signal */
/* Disable PDC Channels for DBGU and Initial the State of it */
pUsart->US_PTCR = AT91RM9200_PDC_PTCR_TXTDIS | AT91RM9200_PDC_PTCR_RXTDIS;
pUsart->US_TNPR = 0;
pUsart->US_TNCR = 0;
/* clear out next transmit counts */
pUsart->US_RNPR = 0;
pUsart->US_RNCR = 0;
/* clear out next receive counts */
pUsart->US_TPR = 0;
pUsart->US_TCR = 0;
/* clear out transmit counts */
pUsart->US_RPR = 0;
pUsart->US_RCR = 0;
/* clear out receive counts */
pUsart->US_MR = pParas->uartOption;
/* default mode */
intUnlock(oldIntLvl);
pChan->mode = SIO_MODE_INT;
/* Enable transmit and received of UART Device */
pUsart->US_CR = AT91RM9200_US_CR_RXEN | AT91RM9200_US_CR_TXEN;
}
else
{
/* Whoops, device is not there! */
free ((
char *)pChan);
errnoSet (S_iosLib_DEVICE_NOT_FOUND);
return;
}
}
return;
}
/*******************************************************************************
*
* at91UARTInt - handle an AT91RM9200 UART interrupt
*
* This routine is called to handle AT91RM9200 UART interrupts.
*/
void at91UARTInt
(
AT91_UART_CHAN *pChan
)
{
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
UINT32 status;
int errorCode = SIO_ERROR_NONE;
status = pUsart->US_CSR;
if (status)
{
/* we can make below process several times when TXRDY or RXRDY is there */
if (status & (AT91RM9200_US_SR_RXRDY))
at91UARTIntRx (pChan);
/* Check for error conditions */
if (status & (AT91RM9200_US_SR_PARE | AT91RM9200_US_SR_FRAME | AT91RM9200_US_SR_OVRE))
{
/*
* Determine precise error condition and perform
* recovery actions.
*/
pUsart->US_CR = AT91RM9200_US_CR_RSTSTA;
/*
* If needed, you should acknowledge or reset the interrupt source
* as soon as possible, usually before passing any error conditions
* upstream.
*/
if (status & (AT91RM9200_US_SR_PARE))
{
errorCode = SIO_ERROR_PARITY;
}
else
if (status & (AT91RM9200_US_SR_FRAME))
{
errorCode = SIO_ERROR_FRAMING;
}
if (errorCode != SIO_ERROR_NONE)
(*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0);
if (status & (AT91RM9200_US_SR_OVRE))
{
errorCode = SIO_ERROR_OFLOW;
(*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0);
}
}
if (status & (AT91RM9200_US_SR_TXRDY))
at91UARTIntTx (pChan);
}
}
/******************************************************************************
*
* at91UARTIntRx - handle a channel's receive-character interrupt
*
* RETURNS: N/A
*/
LOCAL
void at91UARTIntRx
(
AT91_UART_CHAN * pChan
/* channel generating the interrupt */
)
{
char inChar;
/* receive data */
UINT32 rxStatus = 0;
/* receive status */
/*
STATUS status = OK;
int errorCode = SIO_ERROR_NONE;
*/
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
/*
*
* Get status and data from the device. Determine if valid data is ready
* or not.
*
* For PCI devices, do an immediate return if device is not asserting
* an interrupt.
*/
rxStatus = pUsart->US_CSR;
while (rxStatus & AT91RM9200_US_SR_RXRDY)
{
inChar = pUsart->US_RHR;
/* RXRDY bit in US_CSR will be clear when RHR is read */
/* send data character upstream */
(*pChan->putRcvChar) (pChan->putRcvArg, inChar);
if (pChan->mode != SIO_MODE_INT)
break;
rxStatus = pUsart->US_CSR;
}
#if 0 /* will be processed in at91UARTIntErr */
if (status == ERROR)
{
/* send error notification upstream */
(*pChan->errorRtn) (pChan->errorArg, SIO_ERROR_UNKNWN, NULL, 0);
}
#endif
#if 0 /* Keyboard emulation code */
/*
* TODO - For a keyboard type device we would map the raw scan code
* to ASCII, or other mapping. Do that here.
*/
if (pChan->scanMode == SIO_KYBD_MODE_ASCII)
inChar = templateAsciiTbl[(UINT8)inChar];
#endif
}
/******************************************************************************
*
* at91UARTIntTx - handle a channels transmitter-ready interrupt
*
* RETURNS: N/A
*/
LOCAL
void at91UARTIntTx
(
AT91_UART_CHAN *pChan
/* channel generating the interrupt */
)
{
char outChar;
UINT32 txStatus;
/* status of transmit */
/* BOOL txReady = TRUE; */
int errorCode = SIO_ERROR_NONE;
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);;
/* point to UART register index by ioBase of pChan */
/*
* Check the Tx status
*
* For PCI devices, do an immediate return if device is not asserting
* an interrupt.
*/
#if 0
/* Check for error conditions */
if (crData & TEMPLATE_CR_TX_ERROR)
{
/*
* TODO - Typically you should determine the precise error condition
* and perform all recovery operations here.
*/
TEMPLATE_SIO_WRITE8 (pChan, TEMPLATE_CSR_ID, TEMPLATE_RESET_TX);
errorCode = SIO_ERROR_UNKNWN;
txReady = TRUE;
/* set to false if xmitter is not ready now */
}
#endif
/*
* If transmitter is okay and ready to send, lets see if there is a
* data character ready to be sent.
*
* If there's a character to transmit then write it out, else reset (idle)
* the transmitter. For chips with output FIFO's it is more efficient
* to fill the entire FIFO here.
*/
txStatus = pUsart->US_CSR;
if (txStatus & AT91RM9200_US_SR_TXRDY)
{
if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
{
/* Output data to device. */
pUsart->US_THR = outChar;
/* need to insert a wait time for transmit finished ? */
txStatus = pUsart->US_CSR;
/*
* If a device error occurs at this point, then
* isolate the precise error type and try to recover.
*/
}
else
{
/*
* There is no more data to send.
*
* Put XMTR in an idle state. Higher layer
* will call TxStartup entry to resume xmit operations.
*/
pUsart->US_IDR = AT91RM9200_US_INT_TXRDY;
/*
pUsart->US_CR = AT91RM9200_US_CR_TXDIS | AT91RM9200_US_CR_RSTTX; */
/* disable transmit */
/* break; */
}
}
/*
* If needed, you should acknowledge or reset the interrupt source
* as soon as possible, usually before passing any error conditions
* upstream.
*/
/* US_TXRDY will be cleared when char is sent */
/* Pass any errorCodes upstream. */
if (errorCode != SIO_ERROR_NONE)
{
(*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0);
}
}
#if 0
/******************************************************************************
*
* at91UARTIntErr - handle a channels error interrupt
*
* RETURNS: N/A
*/
LOCAL
void at91UARTIntErr
(
AT91_UART_CHAN * pChan
/* channel generating the interrupt */
)
{
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);;
/* point to UART register index by ioBase of pChan */
UINT32 errStatus;
errStatus = pUsart->US_CSR;
/*
* Determine the precise error condition and perform recovery
* operations.
*
* For PCI devices, do an immediate return if device is not asserting
* an interrupt.
*/
if (errStatus & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE)
{
}
}
#endif
/******************************************************************************
*
* templateTxStartup - start the interrupt transmitter
*
* This routine exits to inform the device to start transmitting data again.
* The actual data will be obtained by calling the TxCharGet callback routine.
*
* This routine is usually just the same as the tx interrupt routine. This
* routine runs at task level context and does not have to be interrupt safe.
*
* RETURNS: OK on success, ENOSYS if the device is polled-only, or
* EIO on hardware error.
*/
LOCAL
int at91TxStartup
(
SIO_CHAN * pSioChan
/* channel to start */
)
{
AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
/* char outChar; */
/* This routine should only be called while in interrupt mode */
/* NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
*/
/* pChan->mode = SIO_MODE_POLL; */
if (pChan->mode == SIO_MODE_INT)
{
#if 0
if (pChan->options & CLOCAL)
{
/* No modem control - start immediately */
}
else
{
/*
* Modem controls are active.
*
* If CTS is high, we can start immediately so just enable
* the TX interrupt.
*
* If CTS is low, then we cannot send now. The driver
* should be set up to generate a TX interrupt when the CTS
* line returns to the active state.
*/
}
/*
* Enable the correct interrupts. A TX interrupt should either
* occur immediately, or later when CTS becomes active. That will start
* the flow of data.
*
* There are two usual methods here. The first is to just enable
* TX interrupts, which should cause an immediate TX interrupt, which
* will begin fetching and sending characters.
*
* The second method is to call the getTxChara callback here, put
* the data to the transmitter directly, and then to enable TX
* interrupts to fetch and send additional characters.
*/
#endif
#if 0
if ((pUsart->US_CSR & AT91C_US_TXRDY) && \
((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR))
{
/* Output data to device. */
pUsart->US_THR = outChar;
/*
* If a device error occurs at this point, then
* isolate the precise error type and try to recover.
*/
}
#endif
/* intEnable(pChan->intLevel); */
/* pUsart->US_CR = AT91C_US_TXEN; */
pUsart->US_IER = AT91RM9200_US_INT_TXRDY;
/* we need set it again here ? */
return OK;
}
else
/*
while ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
{
while (EAGAIN == at91PollOutput ((SIO_CHAN *)pChan, outChar));
}
*/
return ENOSYS;
/* Not valid for polled mode operation */
return (OK);
}
/******************************************************************************
*
* at91CallbackInstall - install ISR callbacks to get/put chars
*
* This driver allows interrupt callbacks for transmitting characters
* and receiving characters. In general, drivers may support other
* types of callbacks too.
*
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.
*/
LOCAL
int at91CallbackInstall
(
SIO_CHAN * pSioChan,
/* channel */
int callbackType,
/* type of callback */
STATUS (*callback)(
void *,...),
/* callback */
void * callbackArg
/* parameter to callback */
)
{
AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;
switch (callbackType)
{
case SIO_CALLBACK_GET_TX_CHAR:
pChan->getTxChar = (STATUS (*)(
void *,
char *))callback;
pChan->getTxArg = callbackArg;
return (OK);
case SIO_CALLBACK_PUT_RCV_CHAR:
pChan->putRcvChar = (
void (*)(
void *,
char))callback;
pChan->putRcvArg = callbackArg;
return (OK);
case SIO_CALLBACK_ERROR:
pChan->errorRtn = (
void (*)(
void *,
int,
void *,
int))callback;
pChan->errorArg = callbackArg;
return (OK);
default:
return (ENOSYS);
}
}
/*******************************************************************************
*
* templatePollOutput - output a character in polled mode
*
* Polled mode operation takes place without any kernel or other OS
* services available. Use extreme care to insure that this code does not
* call any kernel services. Polled mode is only for WDB system mode use.
* Kernel services, semaphores, tasks, etc, are not available during WDB
* system mode.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the output buffer if full. ENOSYS if the device is
* interrupt-only.
*/
LOCAL
int at91PollOutput
(
SIO_CHAN * pSioChan,
char outChar
)
{
AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
UINT32 status;
/* is the transmitter ready to accept a character? */
/* Read TX device status */
status = pUsart->US_CSR;
/* determine if transmitter is ready */
if (0x00 == (status & (AT91RM9200_US_SR_TXRDY)))
/* device is busy, try again later */
return (EAGAIN);
/* transmit the character */
pUsart->US_THR = (AT91_REG)outChar;
return (OK);
}
/******************************************************************************
*
* at91PollInput - poll the device for input
*
* Polled mode operation takes place without any kernel or other OS
* services available. Use extreme care to insure that this code does not
* call any kernel services. Polled mode is only for WDB system mode use.
* Kernel services, semaphores, tasks, etc, are not available during WDB
* system mode.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the input buffer if empty, ENOSYS if the device is
* interrupt-only.
*/
LOCAL
int at91PollInput
(
SIO_CHAN * pSioChan,
char * thisChar
)
{
AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
UINT32 status;
/* Read RX device status */
status = pUsart->US_CSR;
/* Check if receive data is available */
if (0x00 == (status & (AT91RM9200_US_SR_RXRDY)))
{
return EAGAIN;
/* no input available at this time */
}
/* Check for receive error conditions */
if (0x00 != (status & (AT91RM9200_US_SR_PARE | AT91RM9200_US_SR_FRAME | AT91RM9200_US_SR_OVRE)))
{
/* Decode and handle the specific error condition */
pUsart->US_CR = AT91RM9200_US_CR_RSTSTA;
/* reset receive of USART to clear error */
/* Do NOT call the error callback routine, just return EIO */
return EIO;
}
/* read character, store it, and return OK */
*thisChar = (
char)(pUsart->US_RHR);
return (OK);
}
/******************************************************************************
*
* at91ModeSet - toggle between interrupt and polled mode
*
* RETURNS: OK on success, EIO on unsupported mode.
*/
LOCAL
int at91ModeSet
(
AT91_UART_CHAN * pChan,
/* channel */
uint_t newMode
/* new mode */
)
{
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
AT91_UART_PARAS *pParas = (AT91_UART_PARAS *)(pChan->pUart);
int oldIntLvl;
if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
return (EIO);
oldIntLvl = intLock();
/*
* use this function will made all the action done in
* at91IosDevInit be cancelled, so we can't do it now
pUsart->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX;
*/
if (pChan->mode == SIO_MODE_INT)
{
/* switch device to interrupt mode */
if (pChan->intConnect == FALSE)
{
/* interconnect ISR to intvector */;
intConnect (INUM_TO_IVEC(pParas->vector), at91UARTInt, (
int)pChan);
pChan->intConnect = TRUE;
}
/* enable interrupt of device */
pUsart->US_IER = AT91RM9200_US_INT_RXRDY | AT91RM9200_US_INT_PARE |AT91RM9200_US_INT_FRAME | AT91RM9200_US_INT_OVRE;
pUsart->US_IDR = AT91RM9200_US_INT_TXRDY;
/* we only enable receive and error interrupt
pUsart->US_IER = AT91RM9200_US_INT_RXRDY | AT91RM9200_US_INT_RXRDY |AT91RM9200_US_INT_PARE | AT91RM9200_US_INT_FRAME |AT91RM9200_US_INT_OVRE;
*/
intEnable (pParas->intLevel);
}
else
{
/* switch device to polled mode */
/* disable interrupt of device */
pUsart->US_IDR = -1;
/* disable all interrupt */
intDisable (pParas->intLevel);
}
/* activate the new mode */
pChan->mode = newMode;
intUnlock(oldIntLvl);
return (OK);
}
#if 0
/*******************************************************************************
*
* templateHup - hang up the modem control lines
*
* Resets the RTS and DTR signals.
*
* RETURNS: OK always.
*/
LOCAL STATUS at91Hup
(
AT91_UART_CHAN * pChan
/* pointer to channel */
)
{
/*
* TODO - Use global intLock if lockout time will be very short. If not,
* use a device specific lockout that will not damage overall system
* latency.
*/
at91MstatSetClr (pChan,(SIO_MODEM_RTS|SIO_MODEM_DTR), FALSE);
return (OK);
}
/*******************************************************************************
*
* at91Open - Set the modem control lines
*
* Set the modem control lines(RTS, DTR) TRUE if not already set.
*
* RETURNS: OK
*/
LOCAL STATUS at91Open
(
AT91_UART_CHAN * pChan
/* pointer to channel */
)
{
/*
* TODO - Use global intLock if lockout time will be very short. If not,
* use a device specific lockout that will not damage overall system
* latency.
*/
at91MstatSetClr (pChan, (SIO_MODEM_RTS|SIO_MODEM_DTR), TRUE);
return (OK);
}
#endif
/******************************************************************************
*
* at91OptSet - set hardware options
*
* This routine sets up the hardware according to the specified option
* argument. If the hardware cannot support a particular option value, then
* it should ignore that portion of the request.
*
* RETURNS: OK upon success, or EIO for invalid arguments.
*/
LOCAL
int at91OptSet
(
AT91_UART_CHAN * pChan,
/* channel */
uint_t newOpts
/* new options */
)
{
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
AT91_UART_PARAS *pParas = (AT91_UART_PARAS *)(pChan->pUart);
int uartHwOptions = pParas->uartOption;
/*
BOOL hdweFlowCtrl=TRUE;
BOOL rcvrEnable = TRUE;
*/
int oldIntLvl;
if (pChan == NULL || newOpts & 0xffffff00)
return EIO;
/* do nothing if options already set */
if (pParas->uartOption== newOpts)
return OK;
/* ignore requests for unsupported options */
/* decode individual request elements */
uartHwOptions &= ~(AT91RM9200_US_MR_CHRL);
switch (newOpts & CSIZE)
{
case CS5:
uartHwOptions |= AT91RM9200_US_MR_CHRL_5_BITS;
break;
case CS6:
uartHwOptions |= AT91RM9200_US_MR_CHRL_6_BITS;
break;
case CS7:
uartHwOptions |= AT91RM9200_US_MR_CHRL_7_BITS;
break;
default:
case CS8:
uartHwOptions |= AT91RM9200_US_MR_CHRL_8_BITS;
break;
}
uartHwOptions &= ~(AT91RM9200_US_MR_NBSTOP);
if (newOpts & STOPB)
/* 2 bits stop bit */
uartHwOptions |= AT91RM9200_US_MR_NBSTOP_2_BIT;
else
/* 1 bit stop bit */
uartHwOptions |= AT91RM9200_US_MR_NBSTOP_1_BIT;
uartHwOptions &= ~(AT91RM9200_US_MR_PAR);
switch (newOpts & (PARENB|PARODD))
{
case PARENB|PARODD:
/* enable odd parity */
uartHwOptions |= AT91RM9200_US_MR_PAR_ODD;
break;
case PARENB:
/* enable even parity */
uartHwOptions |= AT91RM9200_US_MR_PAR_EVEN;
break;
case PARODD:
/* invalid mode, not normally used. */
uartHwOptions |= AT91RM9200_US_MR_PAR_MULTI_DROP;
break;
default:
case 0:
/* no parity */;
uartHwOptions |= AT91RM9200_US_MR_PAR_NONE;
break;
}
if (newOpts & CLOCAL)
{
/* clocal disables hardware flow control */
uartHwOptions &= ~(AT91RM9200_US_MR_USMODE);
uartHwOptions |= AT91RM9200_US_MR_USMODE_NORMAL;
}
else
{
/* enable hardware flow control */
uartHwOptions &= ~(AT91RM9200_US_MR_USMODE);
uartHwOptions |= AT91RM9200_US_MR_USMODE_HWHSH;
uartHwOptions |= AT91RM9200_US_MR_USMODE_MODEM;
}
if ((newOpts & CREAD) == 0)
pUsart->US_CR = AT91RM9200_US_CR_RXDIS;
else
pUsart->US_CR = AT91RM9200_US_CR_RXEN;
oldIntLvl = intLock ();
/*
* Reset the device according to uartHwOptions
*/
pUsart->US_MR = uartHwOptions;
intUnlock (oldIntLvl);
/*
* Be sure that pChan->options reflects the actual
* hardware settings. If 5 data bits were requested, but unsupported,
* then be sure pChan->options reflects the actual number of data bits
* currently selected.
*/
/*
* we store register setting in pParas->uartOption
* and software setting in pChan->options
*/
pParas->uartOption = uartHwOptions;
pChan->options = newOpts;
return (OK);
}
/*******************************************************************************
*
* at91Ioctl - special device control
*
* This routine handles the IOCTL messages from the user. It supports commands
* to get/set baud rate, mode(INT,POLL), hardware options(parity, number of
* data bits) and modem control(RTS/CTS and DTR/DSR handshakes).
* The ioctl commands SIO_HUP and SIO_OPEN are used to implement the HUPCL(hang
* up on last close) function.
*
* As on a UNIX system, requesting a baud rate of zero is translated into
* a hangup request. The DTR and RTS lines are dropped. This should cause
* a connected modem to drop the connection. The SIO_HUP command will only
* hangup if the HUPCL option is active. The SIO_OPEN function will raise
* DTR and RTS lines whenever it is called. Use the BAUD_RATE=0 function
* to hangup when HUPCL is not active.
*
* The CLOCAL option will disable hardware flow control. When selected,
* hardware flow control is not used. When not selected hardware flow control
* is based on the RTS/CTS signals. CTS is the clear to send input
* from the other end. It must be true for this end to begin sending new
* characters. In most drivers, the RTS signal will be assumed to be connected
* to the opposite end's CTS signal and can be used to control output from
* the other end. Raising RTS asserts CTS at the other end and the other end
* can send data. Lowering RTS de-asserts CTS and the other end will stop
* sending data. (This is non-EIA defined use of RTS).
*
* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
* request.
*/
LOCAL
int at91Ioctl
(
SIO_CHAN * pSioChan,
/* device to control */
int request,
/* request code */
void * someArg
/* some argument */
)
{
AT91_UART_CHAN *pChan = (AT91_UART_CHAN *) pSioChan;
AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);
/* point to UART register index by ioBase of pChan */
AT91_UART_PARAS *pParas = (AT91_UART_PARAS *)(pChan->pUart);
int oldLevel;
/* current interrupt level mask */
int baudConstant;
int arg = (
int)someArg;
/* TEMPLATE_PIPE_FLUSH(pChan); */
switch (request)
{
case SIO_BAUD_SET:
/*
* like unix, a baud request for 0 is really a request to hangup.
*/
if (arg == 0)
return (EIO);
/* return (at91Hup (pChan)); */
/*
* Set the baud rate. Return EIO for an invalid baud rate, or
* OK on success.
*/
if (arg < AT91_BAUD_MIN || arg > AT91_BAUD_MAX)
{
return (EIO);
}
/* Calculate the baud rate constant for the new baud rate */
baudConstant = AT91_MASTER_CLOCK / arg / 16;
/* disable interrupts during chip access */
oldLevel = intLock ();
pUsart->US_BRGR = baudConstant;
intUnlock (oldLevel);
pParas->baudRate = arg;
return (OK);
case SIO_BAUD_GET:
*(
int *)someArg = pParas->baudRate;
return (OK);
case SIO_MODE_SET:
/*
* Set the mode (e.g., to interrupt or polled). Return OK
* or EIO for an unknown or unsupported mode.
*/
return (at91ModeSet (pChan, arg));
case SIO_MODE_GET:
/* Get the current mode and return OK. */
*(
int *)someArg = pChan->mode;
return (OK);
case SIO_AVAIL_MODES_GET:
/* TODO - set the available modes and return OK. */
*(
int *)someArg = SIO_MODE_INT | SIO_MODE_POLL;
return (OK);
case SIO_HW_OPTS_SET:
/*
* Optional command to set the hardware options (as defined
* in sioLib.h).
* Return OK, or ENOSYS if this command is not implemented.
* Note: several hardware options are specified at once.
* This routine should set as many as it can and then return
* OK. The SIO_HW_OPTS_GET is used to find out which options
* were actually set.
*/
return (at91OptSet (pChan, arg));
case SIO_HW_OPTS_GET:
/*
* Optional command to get the hardware options (as defined
* in sioLib.h). Return OK or ENOSYS if this command is not
* implemented. Note: if this command is unimplemented, it
* will be assumed that the driver options are CREAD | CS8
* (e.g., eight data bits, one stop bit, no parity, ints enabled).
*/
*(
int *)someArg = pChan->options;
return (OK);
#if 0
case SIO_HUP:
/* check if hupcl option is enabled */
if (pChan->options & HUPCL)
return (at91Hup (pChan));
return (OK);
case SIO_OPEN:
return (at91Open (pChan));
/* always open */
#endif
#if 0 /* TODO - optional modem control line support */
/*
* These new ioctl commands are for monitoring and setting the
* state of the modem control lines under user control. The
* return values from these calls inform the user about which
* control lines are inputs and which are outputs. Basically
* this lets the user know if the device is wired for DTE or
* DCE configuration. It also informs the user if any signals
* are missing altogether.
*/
case SIO_MSTAT_GET:
return templateMstatGet(pChan);
case SIO_MCTRL_BITS_SET:
return templateMstatSetClr (pChan, arg, TRUE);
case SIO_MCTRL_BITS_CLR:
return templateMstatSetClr (pChan, arg, FALSE);
/*
* The ISIG and OSIG masks tell the user which signals are actually
* outputs and which aren't. In our case here, we assume the device
* is DTE mapped with DTR and RTS as outputs. DSR and CTS as inputs.
* This template driver doesn't support RI.
*/
case SIO_MCTRL_OSIG_MASK:
*(
int *)someArg = TEMPLATE_OSIG_MASK;
break;
case SIO_MCTRL_ISIG_MASK:
*(
int *)someArg = TEMPLATE_ISIG_MASK;
break;
#endif /* optional Modem control line support */
#if 0 /* TODO - optional keyboard scan code support */
/*
* The following new ioctl commands are meant only for keyboard
* input devices to use. These allow the user to specify and
* examine the type of keyboard character mapping to use. The
* possible types are NONE (raw scan codes), ASCII (default ascii
* mappings, and UNICODE for standard 16 bit unicode mappings.
*
* Our template driver supports only raw and ascii modes.
*/
case SIO_KYBD_MODE_SET:
switch (arg)
{
case SIO_KYBD_MODE_RAW:
case SIO_KYBD_MODE_ASCII:
break;
case SIO_KYBD_MODE_UNICODE:
return ENOSYS;
/* template doesn't support unicode */
}
pChan->scanMode = arg;
return OK;
case SIO_KYBD_MODE_GET:
*(
int *)someArg = pChan->scanMode;
return OK;
#endif /* optional keyboard scan code support */
default:
return ENOSYS;
}
return OK;
}
/*******************************************************************************
*
* dummyTxCallback - dummy Tx callback routine
*
* RETURNS: ERROR.
*/
LOCAL STATUS at91DummyTxCallback
(
void * callbackArg,
/* argument registered with callback */
char * pChara
/* ptr to data location */
)
{
static
BOOL doit = TRUE;
/*
* TODO - Until an upstream module connects to this device, there
* is no data available to send. We should only be concerned
* if this callback is being called repeatedly and often. That
* could indicate an interrupt servicing problem of some kind.
*/
if (doit)
{
printf (
"Dummy txCallback: 0x%x 0x%x\n",
(
int)callbackArg, (
int)pChara);
doit = FALSE;
}
return (ERROR);
}
/*******************************************************************************
*
* dummyRxCallback - dummy Rx callback routine
*
* RETURNS: N/A.
* ARGSUSED
*/
LOCAL
void at91DummyRxCallback
(
void * callbackArg,
/* argument registered with callback */
char data
/* receive data */
)
{
static
BOOL doit = TRUE;
/*
* TODO - Device is transferring data, but there is no
* upstream module connected to receive it. Lets log
* a message about incoming data being lost. Buts lets
* do this only once we don't want a 'flood' of logged
* messages.
*/
if (doit)
{
printf (
"Dummy rxCallback: 0x%x 0x%x\n",
(
int)callbackArg, (
int)data);
doit = FALSE;
}
return;
}
/*******************************************************************************
*
* dummyErrCallback - dummy Error callback routine
*
* There should be an sioLib module to provide dummyCallbacks for all SIO
* drivers to use.
*
* RETURNS: N/A.
* ARGSUSED
*/
LOCAL
void at91DummyErrCallback
(
void * callbackArg,
/* argument registered with callback */
int errorCode,
/* error code */
void * pData,
/* ptr to device specific data */
int size
/* size of device specific data */
)
{
static
BOOL doit = TRUE;
/* TODO - We could log the reported error (once). */
if (doit)
{
printf (
"Dummy errorCallback: 0x%x 0x%x 0x%x %d\n",
(
int)callbackArg, errorCode, (
int)pData, size);
doit = FALSE;
}
return;
}
/*******************************************************************************
*
* at91Probe - probe for device
*
* Try to determine if device is present. Do not reconfigure device if it
* is there. This should be a passive probe that does not interfere with
* the device.
*
* RETURNS:
* Returns OK if device adaptor is there, ERROR if not there.
*/
LOCAL STATUS at91Probe
(
AT91_UART_CHAN * pChan
/* channel to probe */
)
{
/*
* the UART and DBGU is internal controller of AT91RM9200 CPU,
* so we needn't to probe it
*/
return OK;
}
#if 0
/*******************************************************************************
*
* at91Verify - verify at91_uart chan structure
*
* Given a pointer to what should be a AT91_UART_CHAN, verify that it really
* is a AT91_UART_CHAN structure.
*
* This routine should not be called at every level with every routine. It is
* primarily provided for use with the xxxDestroy routine. Performance will be
* a problem if every pointer is checked for validity with every use.
*
* RETURNS:
* Returns OK if pointer is valid, ERROR if not.
*/
LOCAL STATUS at91Verify
(
AT91_UART_CHAN * pChan
/* pointer to be verified */
)
{
/*
* Examine the structure. Look for magic cookies or flag bits.
* Anything that would confirm this pointer as being a valid
* AT91_UART_CHAN pointer.
*/
if (pChan == NULL)
return ERROR;
return OK;
}
#endif
#if 0 /* Optional modem control line support */
/*******************************************************************************
*
* at91MstatGet - read device modem control line status
*
* Read the device modem control lines and map them to the standard
* modem signal bits.
*
* RETURNS:
* Returns the modem control line status bits.
*/
LOCAL
int at91MstatGet
(
AT91_UART_CHAN *pChan
)
{
AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;
UINT32 status;
int result = 0;
AT91PS_USART pUsart;
/* point to UART register index by ioBase of pChan */
pUsart = (AT91PS_USART)(pChan->ioBase);
/* Read RX device status */
status = pUsart->US_CSR;
/* Now map device status bits, to standard status bits */
if (rawStatus & TEMPLATE_MSR_CD)
result |= SIO_MODEM_CD;
if (rawStatus & TEMPLATE_MSR_DTR)
result |= SIO_MODEM_DTR;
if (rawStatus & TEMPLATE_MSR_DSR)
result |= SIO_MODEM_DSR;
if (rawStatus & TEMPLATE_MSR_RTS)
result |= SIO_MODEM_RTS;
if (rawStatus & TEMPLATE_MSR_CTS)
result |= SIO_MODEM_CTS;
return result;
}
/*******************************************************************************
*
* templateMstatSetClear - set/clear modem control lines
*
* This routine allows the user to set or clear individual modem control
* lines. Of course, only the output lines can actually be changed.
*
* RETURNS:
* OK, or EIO upon detecting a hardware fault.
*/
LOCAL
int templateMstatSetClr
(
TEMPLATE_CHAN *pChan,
UINT bits,
/* bits to change */
BOOL setFlag
/* TRUE = set, FALSE = clear */
)
{
UINT8 rawStatus;
UINT8 rawMask = 0;
/* Read current modem status */
TEMPLATE_SIO_READ8 (pChan, TEMPLATE_MSR_ID, &rawStatus);
/* ignore input only bits */
bits &= TEMPLATE_OSIG_MASK;
/* Now map standard bits to device specific bits */
if (bits & SIO_MODEM_DTR)
rawMask |= TEMPLATE_MSR_DTR;
if (bits & SIO_MODEM_RTS)
rawMask |= TEMPLATE_MSR_RTS;
/* Update device with new output signals */
if (setFlag)
rawStatus |= rawMask;
/* set new bits */
else
rawStatus &= ~rawMask;
/* clear bits */
TEMPLATE_SIO_WRITE8 (pChan, TEMPLATE_MSR_ID, rawStatus);
return OK;
}
#endif /* optional modem control line support */
posted on
2015-09-17 10:26
嵌入式操作系统
阅读(
657
) 评论(
0
)
编辑
收藏
举报
刷新页面
返回顶部
导航
博客园
首页
新随笔
联系
订阅
管理
公告