📄 uartmd.c
字号:
packet->status = IOM_COMPLETED;
return (IOM_COMPLETED);
}
/*
* ======== submitFlush ========
* The local routine to handle an IOM_FLUSH command.
*/
static Int submitFlush(UartChanHandle chan, IOM_Packet *packet)
{
Uns imask;
Int status;
/*
* Abort the current read operation.
* Wait for all output operations to complete in order.
*/
/*
* Abort the current read operations
*/
if (chan->mode == IOM_INPUT) {
/* abort and flush are equivalent for input channels */
return (submitAbort(chan, packet));
}
else {
imask = HWI_disable();
/*
* If output is in process, add 'flush' packet to pendList.
* txIsr will handle flush packet when all output is complete.
*/
if (chan->dataPacket) {
packet->status = IOM_PENDING;
QUE_enqueue(&chan->pendList, packet);
status = IOM_PENDING;
}
else {
status = IOM_COMPLETED;
}
HWI_restore(imask);
}
return (status);
}
/*
* ======== submitRead ========
* The local routine to handle application reads.
*/
static Int submitRead(UartChanHandle chan, IOM_Packet *packet)
{
CIRC_Handle circ = &chan->circ;
UARTHW_Handle hUart = chan->port->hUart;
Uns imask;
/*
* Disable interrupts since several of these variables are
* shared with the ISR.
*/
imask = HWI_disable();
/*
* If chan->dataPacket is non-NULL, then there is already a packet
* in process. Simply enqueue the new packet and return IOM_PENDING.
*/
if (chan->dataPacket) {
QUE_enqueue(&chan->pendList, packet);
HWI_restore(imask);
return (IOM_PENDING);
}
/*
* Update local bufptr and bufcnt variables from new packet. We
* don't set 'chan->dataPacket' until we are sure that no other
* characters exist in the circular buffer. The ISR will then
* put characters directly in 'chan->dataPacket'.
*/
chan->bufptr = packet->addr;
chan->bufcnt = packet->size;
/*
* This loop will copy characters from circular buffer one at a
* time until the read is satisfied or there are no more characters
* in the circular buffer. Interrupts are disabled while this
* loop executes, but window is opened at bottom of loop to minimize
* interrupt latency.
*/
for (;;) {
/*
* If enough characters were available in the circular buffer
* to satisfy read then return IOM_COMPLETED.
*/
if (chan->bufcnt == 0) {
HWI_restore(imask);
return (IOM_COMPLETED);
}
/*
* If no more characters exist in the CIRC, set chan->dataPacket
* and return IOM_PENDING. Remember that chan->dataPacket is
* used to synchronize with the ISR.
*/
if (CIRC_fullCount(circ) == 0) {
chan->dataPacket = packet;
HWI_restore(imask);
return (IOM_PENDING);
}
/*
* Read a character from the circular buffer and decrement the count.
*/
*chan->bufptr++ = CIRC_readChar(circ);
chan->bufcnt--;
UARTHW_enableRx(hUart);
/* open window for interrupt(s) */
HWI_restore(imask);
imask = HWI_disable();
}
}
/*
* ======== submitWrite ========
* The local routine to handle application writes.
*/
static Int submitWrite(UartChanHandle chan, IOM_Packet *packet)
{
Int status;
Uns imask;
CIRC_Handle circ = &chan->circ;
UARTHW_Handle hUart = chan->port->hUart;
imask = HWI_disable();
/*
* If there's a packet in progress, 'chan->dataPacket' will be non-NULL.
* Just queue up the new job and return IOM_PENDING.
*/
if (chan->dataPacket) {
QUE_enqueue(&chan->pendList, packet);
HWI_restore(imask);
return (IOM_PENDING);
}
/*
* Update local bufptr and bufcnt variables from new packet. We
* don't set 'chan->dataPacket' until we are sure that there's no
* more room in the circular buffer. Unlike the rxIsr, the txIsr
* always takes characters from the circular buffer.
*/
chan->bufptr = packet->addr;
chan->bufcnt = packet->size;
for (;;) {
/*
* 'chan->bufcnt' will reach 0 if we were able to copy all characters
* to the circular buffer. Return IOM_COMPLETED in this case.
*/
if (chan->bufcnt == 0) {
status = IOM_COMPLETED;
break;
}
/*
* Set 'chan->dataPacket' and return IOM_PENDING if there is
* no more room for characters in the the circular buffer. The
* txIsr will copy the remaining characters to the circular buffer
* as room becomes available.
*/
if (CIRC_emptyCount(circ) == 0) {
chan->dataPacket = packet;
status = IOM_PENDING;
break;
}
/*
* Put character into circular buffer and decrement count.
*/
CIRC_writeChar(circ, *chan->bufptr++);
chan->bufcnt--;
/* Open the window for interrupt(s) */
HWI_restore(imask);
imask = HWI_disable();
}
/*
* Interrupts must be disabled here since UART may have only
* one ISR for both rx and tx. An rx ISR may call cbTxHandler()
* and cbTxHandler() is not reentrant.
*/
if (UARTHW_txEmpty(hUart)) {
cbTxHandler(chan->port);
}
HWI_restore(imask);
return (status);
}
/*
* -------- callback functions --------
*/
/*
* ======== cbLineStatus ========
* The interrupt handler routine for a line status change.
*/
static Void cbLineStatus(UartPortHandle port, Int lsrVal)
{
Uns evtMask = port->evtMask;
Uns evtWord = 0;
if (!port->notifyFunc) {
return;
}
if ((evtMask & UARTMD_EVT_BREAK) && (UARTMD_LSR_BRKMASK & lsrVal)) {
evtWord |= UARTMD_EVT_BREAK;
}
if ((evtMask & UARTMD_EVT_PERR) && (UARTMD_LSR_PEMASK & lsrVal)) {
evtWord |= UARTMD_EVT_PERR;
}
if ((evtMask & UARTMD_EVT_FERR) && (UARTMD_LSR_FEMASK & lsrVal)) {
evtWord |= UARTMD_EVT_FERR;
}
if ((evtMask & UARTMD_EVT_OERR) && (UARTMD_LSR_OEMASK & lsrVal)) {
evtWord |= UARTMD_EVT_OERR;
}
if (evtWord) {
(*port->notifyFunc)(evtWord, 0);
}
}
/*
* ======== cbModemStatus ========
* The interrupt handler routine for a modem status change.
*/
static Void cbModemStatus (UartPortHandle port, Int msrVal)
{
Uns evtMask = port->evtMask;
Uns evtWord = 0;
if (!port->notifyFunc) {
return;
}
if ((evtMask & UARTMD_EVT_CTSCHANGE) && (UARTMD_MSR_CTSCHGMASK & msrVal)) {
evtWord |= UARTMD_EVT_CTSCHANGE;
}
if ((evtMask & UARTMD_EVT_DSRCHANGE) && (UARTMD_MSR_DSRCHGMASK & msrVal)) {
evtWord |= UARTMD_EVT_DSRCHANGE;
}
if (evtWord) {
(*port->notifyFunc)(evtWord, msrVal);
}
}
/*
* ======== cbRxHandler ========
* The interrupt handler routine for a receive data ready.
*/
static Void cbRxHandler(UartPortHandle port, Int c)
{
UartChanHandle chan = &port->chans[INPUT];
CIRC_Handle circ = &chan->circ;
UARTHW_Handle hUart = port->hUart;
#if SUPPORTPACKEDCHARS
if (chan->packedChars) {
if (chan->halfWay) {
c = (c << 8) | chan->halfWord;
chan->halfWay = FALSE;
}
else {
chan->halfWord = c;
chan->halfWay = TRUE;
return; /* only 1/2 way there, just return */
}
}
#endif
if (chan->dataPacket) {
*chan->bufptr++ = (Char)c;
chan->bufcnt--;
if (chan->bufcnt == 0) {
getNextPacket(chan);
}
}
else if (CIRC_emptyCount(circ)) {
CIRC_writeChar(circ, (Char)c);
}
else {
/* SYS_abort("cbRxHandler: Rx overrun"); */
}
if (CIRC_isFull(circ)) {
UARTHW_disableRx(hUart);
}
}
/*
* ======== cbTxHandler ========
* The interrupt handler routine for a transmit buffer empty.
* This function is also called from submitWrite() to get the data flowing.
*/
static Void cbTxHandler(UartPortHandle port)
{
Char c;
UartChanHandle chan = &port->chans[OUTPUT];
CIRC_Handle circ = &chan->circ;
UARTHW_Handle hUart = port->hUart;
#if SUPPORTPACKEDCHARS
if (chan->packedChars && chan->halfWay) {
UARTHW_writeChar(hUart, chan->halfWord);
chan->halfWay = FALSE;
}
else {
#else
{
#endif
if (CIRC_fullCount(circ) > 0) {
c = CIRC_readChar(circ);
UARTHW_writeChar(hUart, c);
#if SUPPORTPACKEDCHARS
if (chan->packedChars) {
chan->halfWay = TRUE;
chan->halfWord = (c >> 8);
}
#endif
}
if (chan->dataPacket) {
CIRC_writeChar(circ, *chan->bufptr++);
chan->bufcnt--;
if (chan->bufcnt == 0) {
getNextPacket(chan);
}
}
}
}
/*
* -------- support functions --------
*/
/*
* ======== getNextPacket ========
*/
static Void getNextPacket(UartChanHandle chan)
{
IOM_Packet *donePacket, *nextPacket, *flushPacket;
/* Intialize flushPacket */
flushPacket = NULL;
/* Save complete packet for callback */
donePacket = chan->dataPacket;
/* get next data packet */
nextPacket = QUE_get(&chan->pendList);
/*
* If nextPacket points to head of the queue, then the list is
* empty so there's no pending I/O packets.
*/
if (nextPacket != (IOM_Packet *)&chan->pendList) {
/* Check if packet is a FLUSH packet */
if (nextPacket->cmd != IOM_FLUSH) {
/* Set address and size of next packet */
chan->bufptr = nextPacket->addr;
chan->bufcnt = nextPacket->size;
chan->dataPacket = nextPacket;
}
else {
/* Set flushPacket and clear dataPacket */
flushPacket = nextPacket;
chan->dataPacket = NULL;
}
}
else {
chan->dataPacket = NULL;
}
/* Call the callback for the completed packet */
donePacket->status = IOM_COMPLETED;
chan->cbFxn(chan->cbArg, donePacket);
/*
* Call the callback for flushPacket *after* the callback for
* the completed packet.
*/
if (flushPacket != NULL) {
flushPacket->status = IOM_COMPLETED;
chan->cbFxn(chan->cbArg, flushPacket);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -