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

📄 uartmd.c

📁 DSP/BIOS Driver Developer Kit 1.11 The DSP/BIOS Driver Developer Kit (DDK) provides a selection of
💻 C
📖 第 1 页 / 共 2 页
字号:

    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 + -