uartmd.c
上传用户:dahaojd
上传日期:2008-01-29
资源大小:14357k
文件大小:22k
源码类别:

DSP编程

开发平台:

C/C++

  1. /*
  2.  *  Copyright 2003 by Texas Instruments Incorporated.
  3.  *  All rights reserved. Property of Texas Instruments Incorporated.
  4.  *  Restricted rights to use, duplicate or disclose this code are
  5.  *  granted through contract.
  6.  *  
  7.  */
  8. /* "@(#) DDK 1.11.00.00 11-04-03 (ddk-b13)" */
  9. /*
  10.  *  ======== uartmd.c ========
  11.  */
  12. #include <std.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <atm.h>
  16. #include <hwi.h>
  17. #include <iom.h>
  18. #include <que.h>
  19. #include <uartmd.h>
  20. #include <uarthw.h>
  21. #include <circ.h>
  22. #define INPUT           0
  23. #define OUTPUT          1
  24. #define NUMCHANS        2
  25. /*
  26.  * SUPPORTPACKEDCHARS is used for devices that are not byte-addressable
  27.  * where you want to use the UART to transfer full 16-bits of data.  A
  28.  * character is 16-bits on the 54x and 55x.  SUPPORTPACKEDCHARS and the
  29.  * UARTMD_DevParams.packedChars flag are used to specify that full 16-bits
  30.  * of word should be output.  This is useful when using UART to transfer
  31.  * data (not ASCII). UARTs typically support only 8-bit transfers so we
  32.  * need to do 2 transfers per 16-bit word.
  33.  */
  34. #if defined(_54_) || defined(_55_)
  35. #define SUPPORTPACKEDCHARS      1
  36. #else
  37. #define SUPPORTPACKEDCHARS      0
  38. #endif
  39. /*
  40.  * There is one UartChanObj per direction.  This mini-driver must be
  41.  * opened for input and output separately (does not support IOM_INOUT).
  42.  */
  43. typedef struct UartChanObj {
  44.     Uns                 inUse;          /* TRUE if channel is in use */
  45.     Int                 mode;           /* INPUT or OUTPUT */
  46.     struct UartPortObj  *port;          /* to support multiple UART ports */
  47.     
  48.     IOM_Packet          *dataPacket;    /* current active I/O packet */
  49.     Char                *bufptr;        /* pointer within current buf */
  50.     Uns                 bufcnt;         /* size of remaining I/O job */
  51.     QUE_Obj             pendList;       /* IOM_Packets pending I/O go here */
  52.     CIRC_Obj            circ;           /* circular buffer */
  53.     IOM_TiomCallback    cbFxn;          /* to notify client when I/O complete */
  54.     Ptr                 cbArg;          /* argument for cbFxn() */
  55. #if SUPPORTPACKEDCHARS
  56.     Bool                packedChars;    /* TRUE => output all 16 bits */
  57.     Bool                halfWay;        /* TRUE if we're between 1/2 words */
  58.     Char                halfWord;       /* holds 1/2 word */
  59. #endif
  60.  
  61. } UartChanObj, *UartChanHandle;
  62. /*
  63.  * There is one UartPortObj per UART.
  64.  * This mini-driver supports 'NUMPORTS' UART.
  65.  */
  66. typedef struct UartPortObj {
  67.     UARTHW_Handle               hUart;
  68.     UARTMD_TnotifyHandler       notifyFunc;
  69.     Uns                         evtMask;
  70.     UartChanObj                 chans[NUMCHANS];
  71. } UartPortObj, *UartPortHandle;
  72. /*
  73.  * Forward declaration of IOM mini driver interface functions.  These
  74.  * are only exposed via the IOM function table to avoid namespace pollution.
  75.  */
  76. static Int mdBindDev(Ptr *devp, Int devid, Ptr bindParams);
  77. static Int mdControlChan(Ptr chanp, Uns cmd, Ptr arg);
  78. static Int mdCreateChan(Ptr *mdChan, Ptr drvhandle, String name, Int mode, 
  79.         Ptr optArgs, IOM_TiomCallback cbFxn, Ptr cbArg);
  80. static Int mdDeleteChan(Ptr chanp);
  81. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
  82. /*
  83.  * Control functions.  These functions are called by mdControl() for
  84.  * assorted control commmands.
  85.  */
  86. static Int  controlNotify(UartChanHandle chan, UARTMD_NotifyStruct* notify);
  87. /*
  88.  * Submit functions.  These functions are called by mdSubmitChan() for
  89.  * assorted submit commands.
  90.  */
  91. static Int  submitAbort(UartChanHandle chan, IOM_Packet *packet);
  92. static Int  submitFlush(UartChanHandle chan, IOM_Packet *packet);
  93. static Int  submitRead(UartChanHandle chan, IOM_Packet *packet);
  94. static Int  submitWrite(UartChanHandle chan, IOM_Packet *packet);
  95. /* 
  96.  * Callback functions.  These functions are called by the low-level UARTHW
  97.  * ISR for different event types.
  98.  */
  99. static Void cbLineStatus(UartPortHandle port, Int lsrVal);
  100. static Void cbModemStatus(UartPortHandle port, Int msrVal);
  101. static Void cbRxHandler(UartPortHandle port, Int rxVal);
  102. static Void cbTxHandler(UartPortHandle port);
  103. /*
  104.  * Support functions.
  105.  */
  106. static Void getNextPacket(UartChanHandle chan);
  107. /*
  108.  * Public Mini Driver interface table.
  109.  */
  110. IOM_Fxns UARTMD_FXNS =
  111. {
  112.     &mdBindDev,
  113.     IOM_UNBINDDEVNOTIMPL,
  114.     &mdControlChan,
  115.     &mdCreateChan,
  116.     &mdDeleteChan,
  117.     &mdSubmitChan,
  118. };
  119. /*
  120.  * These functions are called by the UARTHW code.
  121.  */
  122. static UARTHW_Tcallback cbFxns[4] = { 
  123.     (UARTHW_Tcallback)cbModemStatus, 
  124.     (UARTHW_Tcallback)cbTxHandler,
  125.     (UARTHW_Tcallback)cbRxHandler, 
  126.     (UARTHW_Tcallback)cbLineStatus
  127. };
  128. /* This mini-driver supports 'NUMPORTS' UARTs. */
  129. #ifdef _64_
  130. #define NUMPORTS        2       /* 2 ports for dual UART on EVMDM642 board */
  131. #else
  132. #define NUMPORTS        1
  133. #endif
  134. static UartPortObj  ports[NUMPORTS];
  135. /*
  136.  *  ======== UARTMD_init ========
  137.  *  UARTMD_init() initializes the data structures used by this mini-driver.
  138.  */
  139. Void UARTMD_init(Void)
  140. {
  141.     Int i, j;
  142.     /* initialize all uartPortObj fields to '0' */
  143.     memset(ports, 0, sizeof(ports));
  144.     for (i=0; i < NUMPORTS; i++) {
  145.         for (j=0; j < NUMCHANS; j++) {
  146.             /* initialize port->chans */
  147.             QUE_new(&ports[i].chans[j].pendList);
  148.             CIRC_new(&ports[i].chans[j].circ);
  149.             ports[i].chans[j].port = &ports[i];
  150.         }
  151.     }
  152. }
  153. /*
  154.  *  ======== mdBindDev ========
  155.  *  mdBindDev() is called by DEV_init() to bind and initialize the hardware. 
  156.  */
  157. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
  158. {
  159.     UARTMD_DevParams *params = (UARTMD_DevParams *)devParams;
  160.     UARTMD_DevParams defaultParams = UARTMD_DEVPARAMS_DEFAULT;
  161.     UARTHW_Handle hUart;
  162.     if ((Uns)devid > NUMPORTS-1) {
  163.         return (IOM_EBADARGS);
  164.     }
  165.     if (params == NULL) {
  166.         params = &defaultParams;
  167.     }
  168.     /* Check if the version number is supported */
  169.     if (params->versionId != UARTMD_VERSION_1){
  170.         /* Unsupported version */
  171.         return(IOM_EBADARGS);
  172.     }
  173. #if SUPPORTPACKEDCHARS
  174.     ports[devid].chans[INPUT].packedChars = params->packedChars;
  175.     ports[devid].chans[OUTPUT].packedChars = params->packedChars;
  176. #endif
  177.     hUart = UARTHW_open(devid, params->uarthwParams, &ports[devid], cbFxns);
  178.     if (hUart != NULL) {
  179.         ports[devid].hUart = hUart;
  180.         *devp = &ports[devid];
  181.         return (IOM_COMPLETED);
  182.     }
  183.     else {
  184.         return (IOM_EBADIO);
  185.     }
  186. }
  187. /*
  188.  *  ======== mdControlChan ========
  189.  *  The Mini driver ctrl function. Catch all for adding device or vendor
  190.  *  specific functionality to a mini driver.
  191.  */
  192. static Int mdControlChan(Ptr chanp, Uns cmd, Ptr arg)
  193. {
  194.     UartChanHandle chan = (UartChanHandle)chanp;
  195.     UARTHW_Handle hUart = chan->port->hUart;
  196.     Int status;
  197.     if (cmd == UARTMD_REGISTER_NOTIFY) {
  198.         status = controlNotify(chan, arg);
  199.     } 
  200.     else if (cmd == UARTMD_SETBREAK) {
  201.         status = UARTHW_setBreak(hUart, ArgToInt(arg));
  202.     } 
  203.     else if (cmd == UARTMD_GETMODEMSTATUS) {
  204.         status = UARTHW_getModemStatus(hUart, (char*)arg);
  205.     } 
  206.     else if (cmd == UARTMD_SETRTS) {
  207.         status = UARTHW_setRTS(hUart, ArgToInt(arg));
  208.     } 
  209.     else if (cmd == UARTMD_SETDTR) {
  210.         status = UARTHW_setDTR(hUart, ArgToInt(arg));
  211.     } 
  212.     else {
  213.         status = IOM_ENOTIMPL;
  214.     }
  215.         
  216.     return (status);    
  217. }
  218. /*
  219.  *  ======== mdCreateChan ========
  220.  */
  221. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode, 
  222.                          Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
  223. {
  224.     UartChanHandle      chan;
  225.     UartPortHandle      port = (UartPortHandle)devp;
  226.                
  227.     if (mode == IOM_INPUT) {
  228.         chan = &port->chans[INPUT];
  229.         chan->mode = INPUT;
  230.     }
  231.     else if (mode == IOM_OUTPUT) {
  232.         chan = &port->chans[OUTPUT];
  233.         chan->mode = OUTPUT;
  234.     }
  235.     else {
  236.         return (IOM_EBADMODE);
  237.     }
  238.         
  239.     if (ATM_setu(&chan->inUse, TRUE)) {
  240.         return (IOM_EINUSE);
  241.     }
  242.     /*
  243.      * Save the callback function and argument.  cbFxn() is called every
  244.      * time an I/O job completes.
  245.      */
  246.     chan->cbFxn = cbFxn;
  247.     chan->cbArg = cbArg;
  248.     /* chanp will be passed to subsequent mini-driver calls */
  249.     *chanp = chan;
  250.     
  251.     return (IOM_COMPLETED);             
  252. }
  253. /*
  254.  *  ======== mdDeleteChan ========
  255.  *  Deletes an instance of the UART channel. 
  256.  *  All I/O jobs must be completed prior to calling mdDelete().
  257.  */
  258. static Int mdDeleteChan(Ptr chanp)
  259. {
  260.     UartChanHandle chan = (UartChanHandle)chanp;
  261.    
  262.     chan->inUse = FALSE;
  263.         
  264.     return (IOM_COMPLETED);
  265. }
  266. /*
  267.  *  ======== mdSubmitChan ========
  268.  *  The main entry point to the mini driver for read / write operations.
  269.  *  mdSubmitChan() also handles the flush and abort operations.
  270.  */
  271. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
  272. {
  273.     Uns cmd = (packet->cmd);
  274.     Int status;
  275.     
  276.     if (cmd == IOM_READ){
  277.         status = submitRead(chanp, packet);
  278.     }
  279.     else if (cmd == IOM_WRITE){
  280.         status = submitWrite(chanp, packet);
  281.     }
  282.     else if (cmd == IOM_ABORT){
  283.         status = submitAbort(chanp, packet);
  284.     }
  285.     else if (cmd == IOM_FLUSH){
  286.         status = submitFlush(chanp, packet);
  287.     }
  288.     else {
  289.         status = IOM_ENOTIMPL; 
  290.     }
  291.   
  292.     return (status);
  293. }
  294. /*
  295.  *  -------- control functions --------
  296.  */
  297. /*
  298.  *  ======== controlNotify ========
  299.  *  The local routine to handle application call to set the
  300.  *  notification callback and events for which it desires
  301.  *  notifications.
  302.  */
  303. static Int controlNotify(UartChanHandle chan, UARTMD_NotifyStruct * notify)
  304. {
  305.     chan->port->evtMask = notify->evtMask;
  306.     chan->port->notifyFunc = notify->notifyFunc;
  307.   
  308.     return (IOM_COMPLETED);
  309. }
  310. /*
  311.  *  -------- submit functions --------
  312.  */
  313. /*
  314.  *  ======== submitAbort ========
  315.  *  The local routine to handle an IOM_ABORT command.
  316.  */
  317. static Int submitAbort(UartChanHandle chan, IOM_Packet *packet)
  318. {
  319.     IOM_Packet  *dataPacket;
  320.     Uns         imask;
  321.     CIRC_Handle circ = &chan->circ;
  322.     /*
  323.      * Atomically save dataPacket and set chan->dataPacket to NULL.
  324.      * 'chan->dataPacket' is used to synchronize with the ISR.  If the
  325.      * ISR sees chan->dataPacket == NULL, it will not attempt to
  326.      * reload any packets from the pendList.
  327.      */
  328.     imask = HWI_disable();
  329.     CIRC_reset(circ);
  330.     dataPacket = chan->dataPacket;
  331.     chan->dataPacket = NULL;            /* stop all active I/O */
  332. #if SUPPORTPACKEDCHARS
  333.     chan->halfWay = FALSE;
  334. #endif
  335.     
  336.     HWI_restore(imask);
  337.     /*
  338.      * Return all packets in order with their status tagged as aborted.
  339.      * Since chan->dataPacket was set to NULL above, we don't need to
  340.      * worry about synchronizing with the ISR.
  341.      */
  342.     /*
  343.      * Return active dataPacket first.
  344.      */ 
  345.     if (dataPacket != NULL) {
  346.         dataPacket->status = IOM_ABORTED;
  347.         chan->cbFxn(chan->cbArg, dataPacket);
  348.     }
  349.     /*
  350.      * Now remove remaining packets from the pending list and call
  351.      * the callback one at a time.  We use QUE_get() here for code size
  352.      * savings, but we could use QUE_dequeue() since ISR will not
  353.      * reference this queue.
  354.      */
  355.     dataPacket = QUE_get(&chan->pendList);
  356.     while (dataPacket != (IOM_Packet *)&chan->pendList) {
  357.         dataPacket->status = IOM_ABORTED;
  358.         chan->cbFxn(chan->cbArg, dataPacket);
  359.         dataPacket = QUE_get(&chan->pendList);
  360.     }
  361.     packet->status = IOM_COMPLETED;
  362.     return (IOM_COMPLETED);
  363. }
  364. /*
  365.  *  ======== submitFlush ========
  366.  *  The local routine to handle an IOM_FLUSH command.
  367.  */
  368. static Int submitFlush(UartChanHandle chan, IOM_Packet *packet)
  369. {
  370.     Uns         imask;
  371.     Int         status;
  372.      
  373.     /*
  374.      * Abort the current read operation.
  375.      * Wait for all output operations to complete in order.
  376.      */
  377.      
  378.     /*
  379.      * Abort the current read operations 
  380.      */
  381.     if (chan->mode == IOM_INPUT) {
  382.         /* abort and flush are equivalent for input channels */
  383.         return (submitAbort(chan, packet));
  384.     }
  385.     else {
  386.         imask = HWI_disable();
  387.         /*
  388.          * If output is in process, add 'flush' packet to pendList.
  389.          * txIsr will handle flush packet when all output is complete.
  390.          */
  391.         if (chan->dataPacket) {
  392.             packet->status = IOM_PENDING;
  393.             QUE_enqueue(&chan->pendList, packet);
  394.             status = IOM_PENDING;
  395.         }
  396.         else {
  397.             status = IOM_COMPLETED;
  398.         }
  399.         HWI_restore(imask);
  400.     }
  401.     return (status);
  402. }
  403. /*
  404.  *  ======== submitRead ========
  405.  *  The local routine to handle application reads.
  406.  */
  407. static Int submitRead(UartChanHandle chan, IOM_Packet *packet)
  408. {
  409.     CIRC_Handle circ = &chan->circ;
  410.     UARTHW_Handle       hUart = chan->port->hUart;
  411.     Uns         imask;
  412.   
  413.     /*
  414.      * Disable interrupts since several of these variables are
  415.      * shared with the ISR.
  416.      */
  417.     imask = HWI_disable();
  418.     /*
  419.      * If chan->dataPacket is non-NULL, then there is already a packet
  420.      * in process.  Simply enqueue the new packet and return IOM_PENDING.
  421.      */
  422.     if (chan->dataPacket) {
  423.         QUE_enqueue(&chan->pendList, packet);
  424.         HWI_restore(imask);
  425.         return (IOM_PENDING);
  426.     }
  427.     /*
  428.      * Update local bufptr and bufcnt variables from new packet.  We
  429.      * don't set 'chan->dataPacket' until we are sure that no other
  430.      * characters exist in the circular buffer.  The ISR will then
  431.      * put characters directly in 'chan->dataPacket'.
  432.      */
  433.     chan->bufptr = packet->addr;
  434.     chan->bufcnt = packet->size;
  435.     /*
  436.      * This loop will copy characters from circular buffer one at a
  437.      * time until the read is satisfied or there are no more characters
  438.      * in the circular buffer.   Interrupts are disabled while this
  439.      * loop executes, but window is opened at bottom of loop to minimize
  440.      * interrupt latency. 
  441.      */
  442.     for (;;) {
  443.         /*
  444.          * If enough characters were available in the circular buffer
  445.          * to satisfy read then return IOM_COMPLETED.
  446.          */
  447.         if (chan->bufcnt == 0) {
  448.             HWI_restore(imask);
  449.             return (IOM_COMPLETED);
  450.         }
  451.         /*
  452.          * If no more characters exist in the CIRC, set chan->dataPacket
  453.          * and return IOM_PENDING.  Remember that chan->dataPacket is
  454.          * used to synchronize with the ISR.
  455.          */
  456.         if (CIRC_fullCount(circ) == 0) {
  457.             chan->dataPacket = packet;
  458.             HWI_restore(imask);
  459.             return (IOM_PENDING);
  460.         }
  461.         /*
  462.          * Read a character from the circular buffer and decrement the count.
  463.          */ 
  464.         *chan->bufptr++ = CIRC_readChar(circ);
  465.         chan->bufcnt--;
  466.         UARTHW_enableRx(hUart);
  467.         /* open window for interrupt(s) */
  468.         HWI_restore(imask);
  469.         imask = HWI_disable();
  470.     }
  471. }
  472. /*
  473.  *  ======== submitWrite ========
  474.  *  The local routine to handle application writes.
  475.  */
  476. static Int submitWrite(UartChanHandle chan, IOM_Packet *packet)
  477. {
  478.     Int                 status;
  479.     Uns                 imask;
  480.     CIRC_Handle         circ = &chan->circ;
  481.     UARTHW_Handle       hUart = chan->port->hUart;
  482.    
  483.     imask = HWI_disable();
  484.     /*
  485.      * If there's a packet in progress, 'chan->dataPacket' will be non-NULL.
  486.      * Just queue up the new job and return IOM_PENDING.
  487.      */
  488.     if (chan->dataPacket) {
  489.         QUE_enqueue(&chan->pendList, packet);
  490.         HWI_restore(imask);
  491.         return (IOM_PENDING);
  492.     }   
  493.     /*
  494.      * Update local bufptr and bufcnt variables from new packet.  We
  495.      * don't set 'chan->dataPacket' until we are sure that there's no
  496.      * more room in the circular buffer.  Unlike the rxIsr, the txIsr
  497.      * always takes characters from the circular buffer.
  498.      */
  499.     chan->bufptr = packet->addr;
  500.     chan->bufcnt = packet->size;
  501.     for (;;) {
  502.         /* 
  503.          * 'chan->bufcnt' will reach 0 if we were able to copy all characters
  504.          * to the circular buffer.  Return IOM_COMPLETED in this case.
  505.          */
  506.         if (chan->bufcnt == 0) {
  507.             status = IOM_COMPLETED;
  508.             break;
  509.         }
  510.         /*
  511.          * Set 'chan->dataPacket' and return IOM_PENDING if there is
  512.          * no more room for characters in the the circular buffer.  The
  513.          * txIsr will copy the remaining characters to the circular buffer
  514.          * as room becomes available.
  515.          */
  516.         if (CIRC_emptyCount(circ) == 0) {
  517.             chan->dataPacket = packet;
  518.             status = IOM_PENDING;
  519.             break;
  520.         }
  521.         /*
  522.          * Put character into circular buffer and decrement count.
  523.          */
  524.         CIRC_writeChar(circ, *chan->bufptr++);
  525.         chan->bufcnt--;
  526.         /* Open the window for interrupt(s) */
  527.         HWI_restore(imask);
  528.         imask = HWI_disable();
  529.     }
  530.     /*
  531.      * Interrupts must be disabled here since UART may have only
  532.      * one ISR for both rx and tx.  An rx ISR may call cbTxHandler()
  533.      * and cbTxHandler() is not reentrant.
  534.      */
  535.     if (UARTHW_txEmpty(hUart)) {
  536.         cbTxHandler(chan->port);
  537.     }
  538.     HWI_restore(imask);
  539.     return (status);
  540. }
  541. /*
  542.  *  -------- callback functions --------
  543.  */
  544. /*
  545.  *  ======== cbLineStatus ========
  546.  *  The interrupt handler routine for  a line status change.
  547.  */
  548. static Void cbLineStatus(UartPortHandle port, Int lsrVal)
  549. {
  550.     Uns  evtMask = port->evtMask;
  551.     Uns  evtWord = 0;
  552.   
  553.     if (!port->notifyFunc) {
  554.         return;
  555.     }         
  556.       
  557.     if ((evtMask & UARTMD_EVT_BREAK) && (UARTMD_LSR_BRKMASK & lsrVal)) {
  558.         evtWord |= UARTMD_EVT_BREAK;
  559.     }
  560.     
  561.     if ((evtMask & UARTMD_EVT_PERR) && (UARTMD_LSR_PEMASK & lsrVal)) {
  562.         evtWord |= UARTMD_EVT_PERR;
  563.     }
  564.     
  565.     if ((evtMask & UARTMD_EVT_FERR) && (UARTMD_LSR_FEMASK & lsrVal)) {
  566.         evtWord |= UARTMD_EVT_FERR;
  567.     }    
  568.     
  569.     if ((evtMask & UARTMD_EVT_OERR) && (UARTMD_LSR_OEMASK & lsrVal)) {
  570.         evtWord |= UARTMD_EVT_OERR;
  571.     }    
  572.      
  573.     if (evtWord) {
  574.         (*port->notifyFunc)(evtWord, 0); 
  575.     } 
  576. }
  577. /*
  578.  *  ======== cbModemStatus ========
  579.  *  The interrupt handler routine for a modem status change.
  580.  */
  581. static Void cbModemStatus (UartPortHandle port, Int msrVal)
  582. {
  583.     Uns  evtMask = port->evtMask;
  584.     Uns  evtWord = 0;
  585.  
  586.     if (!port->notifyFunc) {
  587.         return;
  588.     }    
  589.   
  590.     if ((evtMask & UARTMD_EVT_CTSCHANGE) && (UARTMD_MSR_CTSCHGMASK & msrVal)) {
  591.         evtWord |= UARTMD_EVT_CTSCHANGE;
  592.     }
  593.  
  594.     if ((evtMask & UARTMD_EVT_DSRCHANGE) && (UARTMD_MSR_DSRCHGMASK & msrVal)) {
  595.         evtWord |= UARTMD_EVT_DSRCHANGE;
  596.     }
  597.   
  598.     if (evtWord) {
  599.         (*port->notifyFunc)(evtWord, msrVal);
  600.     } 
  601. }
  602. /*
  603.  *  ======== cbRxHandler ========
  604.  *  The interrupt handler routine for a receive data ready.
  605.  */
  606. static Void cbRxHandler(UartPortHandle port, Int c)
  607. {
  608.     UartChanHandle      chan = &port->chans[INPUT];
  609.     CIRC_Handle         circ = &chan->circ;
  610.     UARTHW_Handle       hUart = port->hUart;
  611. #if SUPPORTPACKEDCHARS
  612.     if (chan->packedChars) {
  613.         if (chan->halfWay) {
  614.             c = (c << 8) | chan->halfWord;
  615.             chan->halfWay = FALSE;
  616.         }
  617.         else {
  618.             chan->halfWord = c;
  619.             chan->halfWay = TRUE;
  620.             return;     /* only 1/2 way there, just return */
  621.         }
  622.     }
  623. #endif
  624.     if (chan->dataPacket) {
  625.         *chan->bufptr++ = (Char)c;
  626.         chan->bufcnt--;
  627.         if (chan->bufcnt == 0) {
  628.             getNextPacket(chan);
  629.         }
  630.     }
  631.     else if (CIRC_emptyCount(circ)) { 
  632.         CIRC_writeChar(circ, (Char)c);
  633.     }
  634.     else {
  635.         /* SYS_abort("cbRxHandler: Rx overrun"); */
  636.     }
  637.     if (CIRC_isFull(circ)) {
  638.         UARTHW_disableRx(hUart);
  639.     }
  640. }
  641. /*
  642.  *  ======== cbTxHandler ========
  643.  *  The interrupt handler routine for a transmit buffer empty.
  644.  *  This function is also called from submitWrite() to get the data flowing.
  645.  */
  646. static Void cbTxHandler(UartPortHandle port)
  647. {
  648.     Char                c;
  649.     UartChanHandle      chan = &port->chans[OUTPUT];
  650.     CIRC_Handle         circ = &chan->circ;
  651.     UARTHW_Handle       hUart = port->hUart;
  652.     
  653. #if SUPPORTPACKEDCHARS
  654.     if (chan->packedChars && chan->halfWay) {
  655.         UARTHW_writeChar(hUart, chan->halfWord);
  656.         chan->halfWay = FALSE;
  657.     }
  658.     else {
  659. #else
  660.     {
  661. #endif
  662.         if (CIRC_fullCount(circ) > 0) {
  663.             c = CIRC_readChar(circ);
  664.             UARTHW_writeChar(hUart, c);
  665. #if SUPPORTPACKEDCHARS
  666.             if (chan->packedChars) {
  667.                 chan->halfWay = TRUE;
  668.                 chan->halfWord = (c >> 8);
  669.             }
  670. #endif
  671.         }
  672.         if (chan->dataPacket) {
  673.             CIRC_writeChar(circ, *chan->bufptr++);
  674.             chan->bufcnt--;
  675.             if (chan->bufcnt == 0) {
  676.                 getNextPacket(chan);
  677.             }
  678.         }
  679.     }
  680. }
  681. /*
  682.  *  -------- support functions --------
  683.  */
  684. /*
  685.  *  ======== getNextPacket ========
  686.  */
  687. static Void getNextPacket(UartChanHandle chan)
  688. {
  689.     IOM_Packet  *donePacket, *nextPacket, *flushPacket;
  690.     /* Intialize flushPacket */
  691.     flushPacket = NULL;
  692.     /* Save complete packet for callback */
  693.     donePacket = chan->dataPacket;
  694.     /* get next data packet */
  695.     nextPacket = QUE_get(&chan->pendList);
  696.     /* 
  697.      * If nextPacket points to head of the queue, then the list is
  698.      * empty so there's no pending I/O packets.
  699.      */
  700.     if (nextPacket != (IOM_Packet *)&chan->pendList) {
  701.         /* Check if packet is a FLUSH packet */
  702.         if (nextPacket->cmd != IOM_FLUSH) { 
  703.             /* Set address and size of next packet */
  704.             chan->bufptr = nextPacket->addr;
  705.             chan->bufcnt = nextPacket->size;
  706.             chan->dataPacket = nextPacket;
  707.         }
  708.         else {
  709.             /* Set flushPacket and clear dataPacket */
  710.             flushPacket = nextPacket;
  711.             chan->dataPacket = NULL;
  712.         }
  713.     }
  714.     else {
  715.         chan->dataPacket = NULL;
  716.     }
  717.     /* Call the callback for the completed packet */
  718.     donePacket->status = IOM_COMPLETED;
  719.     chan->cbFxn(chan->cbArg, donePacket);
  720.     
  721.     /* 
  722.      * Call the callback for flushPacket *after* the callback for 
  723.      * the completed packet.
  724.      */ 
  725.     if (flushPacket != NULL) {
  726.         flushPacket->status = IOM_COMPLETED;
  727.         chan->cbFxn(chan->cbArg, flushPacket);
  728.     } 
  729. }