source: svn/newcon3bcm2_21bu/nexus/modules/uart/7552/src/nexus_uart.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 23.1 KB
Line 
1/***************************************************************************
2 *     (c)2007-2011 Broadcom Corporation
3 *
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13 *
14 *  Except as expressly set forth in the Authorized License,
15 *
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 *
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: nexus_uart.c $
39 * $brcm_Revision: 11 $
40 * $brcm_Date: 11/11/11 7:10p $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/uart/7425/src/nexus_uart.c $
47 *
48 * 11   11/11/11 7:10p jtna
49 * SW7425-1708: added NEXUS_UartModule_Standby_priv
50 *
51 * 10   8/24/10 8:48a erickson
52 * SW7125-495: second fix for NEXUS_Uart_P_RxCallback_isr. required
53 *  additional logic on wrap if rptr == 0.
54 *
55 * 9   8/4/10 2:30p erickson
56 * SW7125-495: fix memory corruption in NEXUS_Uart_P_RxCallback_isr
57 *
58 * 8   6/10/09 4:18p jgarrett
59 * PR 55902: Checking in fixes from HDI team
60 *
61 * 7   4/2/09 11:21a cnovak
62 * PR52362: Fix release build warnings.
63 *
64 * 6   3/9/09 9:27a erickson
65 * PR52362: rework to improve uart performance
66 *
67 * PR52362/3   3/6/09 4:59p cnovak
68 * PR52362: Code review changes: Use Nexus event callback instead of task
69 *  callback. Rename functions to _isr where appropriate. Fix tab/space
70 *  issues.
71 *
72 * PR52362/2   2/27/09 3:46p cnovak
73 * PR52362: Final cleanup and bug fixes.
74 *
75 * PR52362/1   2/23/09 10:11a cnovak
76 * PR52362: Checkpoint. Modify driver to use burt's interrupt mode.
77 *
78 * 5   1/26/09 12:05p erickson
79 * PR51468: global variable naming convention
80 *
81 * 4   1/26/09 11:08a erickson
82 * PR51468: global variable naming convention
83 *
84 * 3   7/16/08 8:40a erickson
85 * PR44659: fix fifo depth logic
86 *
87 * 2   3/8/08 7:22a erickson
88 * PR40103: convert to TaskCallback
89 *
90 * 1   1/18/08 2:21p jgarrett
91 * PR 38808: Merging to main branch
92 *
93 * Nexus_Devel/4   12/5/07 7:07p jgarrett
94 * PR 37931: Finalizing implmentation
95 *
96 * Nexus_Devel/3   11/21/07 11:12a erickson
97 * PR37423: update
98 *
99 * Nexus_Devel/2   11/20/07 2:23p erickson
100 * PR37423: simplify module init
101 *
102 * Nexus_Devel/1   11/20/07 1:28p erickson
103 * PR37423: added uart, gpio, spi modules
104 *
105 **************************************************************************/
106#include "nexus_uart_module.h"
107#include "burt.h"
108#include "priv/nexus_uart_standby_priv.h"
109#include "nexus_platform_features.h"
110
111BDBG_MODULE(nexus_uart);
112
113NEXUS_ModuleHandle g_NEXUS_uartModule;
114struct {
115    NEXUS_UartModuleSettings settings;
116    BURT_Handle urt;
117} g_NEXUS_uart;
118
119/****************************************
120* Module functions
121***************/
122
123void NEXUS_UartModule_GetDefaultSettings(NEXUS_UartModuleSettings *pSettings)
124{
125    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
126}
127
128NEXUS_ModuleHandle NEXUS_UartModule_Init(const NEXUS_UartModuleSettings *pSettings)
129{
130    BURT_Settings urtSettings;
131    BERR_Code rc;
132
133    BDBG_ASSERT(!g_NEXUS_uartModule);
134    g_NEXUS_uartModule = NEXUS_Module_Create("uart", NULL);
135    if (pSettings) {
136        g_NEXUS_uart.settings = *pSettings;
137    }
138    else {
139        NEXUS_UartModule_GetDefaultSettings(&g_NEXUS_uart.settings);
140    }
141
142    BURT_GetDefaultSettings(&urtSettings, g_pCoreHandles->chp);
143    rc = BURT_Open(&g_NEXUS_uart.urt, g_pCoreHandles->chp, g_pCoreHandles->reg, g_pCoreHandles->bint, &urtSettings);
144    if (rc) {rc = BERR_TRACE(rc); return NULL;}
145
146    return g_NEXUS_uartModule;
147}
148
149void NEXUS_UartModule_Uninit()
150{
151    BURT_Close(g_NEXUS_uart.urt);
152    NEXUS_Module_Destroy(g_NEXUS_uartModule);
153    g_NEXUS_uartModule = NULL;
154}
155
156/****************************************
157* API functions
158***************/
159
160BDBG_OBJECT_ID(NEXUS_Uart);
161
162typedef struct NEXUS_Uart
163{
164    BDBG_OBJECT(NEXUS_Uart)
165    bool opened;
166    bool txCallbackArmed;
167    bool rxCallbackArmed;
168    BURT_ChannelHandle urtChannel;
169    NEXUS_UartSettings settings;
170    uint8_t *pTxFifo;
171    unsigned txRead;
172    unsigned txWrite;
173    uint8_t *pRxFifo;
174    unsigned rxRead;
175    unsigned rxWrite;
176    NEXUS_UartStatus status;
177
178    /* Internal callbacks */
179    BKNI_EventHandle txEvent;
180    NEXUS_EventCallbackHandle txEventCallback;
181
182    /* User callbacks */
183    NEXUS_TaskCallbackHandle txDoneCallback;
184    NEXUS_IsrCallbackHandle errorCallback;
185    NEXUS_IsrCallbackHandle rxReadyCallback;
186} NEXUS_Uart;
187
188static NEXUS_Uart g_NEXUS_uarts[NEXUS_NUM_UARTS];
189
190static void NEXUS_Uart_P_RxCallback_isr(NEXUS_UartHandle uart);
191static void NEXUS_Uart_P_TxCallback(void * context);
192static void NEXUS_Uart_P_DataReady_isr(void * context, int param);
193
194static int NEXUS_Uart_P_FifoData_isr(int rPtr, int wPtr, int size)
195{
196    /* if wPtr == rPtr, it is empty. */
197    if ( wPtr >= rPtr )
198        return wPtr - rPtr;
199    else
200        return (size - rPtr) + wPtr;
201}
202
203static int NEXUS_Uart_P_FifoFreeSpace_isr(int rPtr, int wPtr, int size)
204{
205    /* -1 is required to prevent overflowing the buffer. */
206    if ( wPtr >= rPtr )
207        return (size - wPtr) + rPtr - 1;
208    else
209        return rPtr - wPtr - 1;
210}
211
212void NEXUS_Uart_GetDefaultSettings(NEXUS_UartSettings *pSettings)
213{
214    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
215    pSettings->rxBufferSize = 256;
216    pSettings->txBufferSize = 256;
217    pSettings->baudRate = 38400;
218    pSettings->parity = NEXUS_UartParity_eNone;
219    pSettings->dataBits = NEXUS_UartDataBits_e8;
220    pSettings->stopBits = NEXUS_UartStopBits_e1;
221}
222
223NEXUS_UartHandle NEXUS_Uart_Open(unsigned index, const NEXUS_UartSettings *pSettings)
224{
225    BERR_Code errCode;
226    unsigned totalChannels;
227    NEXUS_UartSettings settings;
228    NEXUS_UartHandle uart;
229
230    BURT_GetTotalChannels(g_NEXUS_uart.urt, &totalChannels);
231    if ( index >= totalChannels || index >= NEXUS_NUM_UARTS )
232    {
233        BDBG_ERR(("unable to open Uart[%d]", index));
234        errCode = BERR_TRACE(BERR_INVALID_PARAMETER);
235        return NULL;
236    }
237
238    if ( g_NEXUS_uarts[index].opened == true )
239    {
240        BDBG_ERR(("UART %d is already open", index));
241        errCode = BERR_TRACE(BERR_NOT_SUPPORTED);
242        return NULL;
243    }
244
245    if ( NULL == pSettings )
246    {
247        NEXUS_Uart_GetDefaultSettings(&settings);
248        pSettings = &settings;
249    }
250
251    uart = &g_NEXUS_uarts[index];
252    BKNI_Memset(uart, 0, sizeof(*uart));
253    BDBG_OBJECT_SET(uart, NEXUS_Uart);
254    uart->opened = true;
255    uart->errorCallback = NEXUS_IsrCallback_Create(uart, NULL);
256    uart->rxReadyCallback = NEXUS_IsrCallback_Create(uart, NULL);
257    uart->txDoneCallback = NEXUS_TaskCallback_Create(uart, NULL);
258
259    errCode = BKNI_CreateEvent(&uart->txEvent);
260    if (errCode) {
261        errCode = BERR_TRACE(errCode);
262        goto error;
263    }
264
265    uart->txEventCallback = NEXUS_RegisterEvent(uart->txEvent, NEXUS_Uart_P_TxCallback, uart);
266    if (NULL == uart->txEventCallback) {
267        errCode = BERR_TRACE(NEXUS_OUT_OF_DEVICE_MEMORY);
268        goto error;
269    }
270
271    if ( pSettings->txBufferSize == 0 && pSettings->rxBufferSize == 0 )
272    {
273        errCode = BERR_TRACE(BERR_INVALID_PARAMETER);
274        goto error;
275    }
276
277    if ( pSettings->txBufferSize > 0 )
278    {
279        uart->pTxFifo = BKNI_Malloc(pSettings->txBufferSize);
280        if ( NULL == uart->pTxFifo )
281        {
282            errCode = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
283            goto error;
284        }
285    }
286
287    if ( pSettings->rxBufferSize > 0 )
288    {
289        uart->pRxFifo = BKNI_Malloc(pSettings->rxBufferSize);
290        if ( NULL == uart->pRxFifo )
291        {
292            errCode = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
293            goto error;
294        }
295    }
296
297    errCode = NEXUS_Uart_SetSettings(uart, pSettings);
298    if ( errCode )
299    {
300        errCode = BERR_TRACE(errCode);
301        goto error;
302    }
303
304    return uart;
305
306error:
307    NEXUS_Uart_Close(uart);
308    return NULL;
309}
310
311void NEXUS_Uart_Close(NEXUS_UartHandle uart)
312{
313    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
314
315    if (uart->urtChannel)
316    {
317        BURT_EnableRxInt(uart->urtChannel, false);
318        BURT_EnableTxInt(uart->urtChannel, false);
319        BURT_CloseChannel(uart->urtChannel);
320    }
321    if ( uart->pTxFifo )
322    {
323        BKNI_Free(uart->pTxFifo);
324    }
325    if ( uart->pRxFifo )
326    {
327        BKNI_Free(uart->pRxFifo);
328    }
329
330    NEXUS_IsrCallback_Destroy(uart->errorCallback);
331    NEXUS_IsrCallback_Destroy(uart->rxReadyCallback);
332    NEXUS_TaskCallback_Destroy(uart->txDoneCallback);
333
334    if (uart->txEventCallback) {
335        NEXUS_UnregisterEvent(uart->txEventCallback);
336    }
337    if (uart->txEvent) {
338        BKNI_DestroyEvent(uart->txEvent);
339    }
340
341    BKNI_Memset(uart, 0, sizeof(*uart));
342}
343
344void NEXUS_Uart_GetSettings(NEXUS_UartHandle uart, NEXUS_UartSettings *pSettings)
345{
346    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
347    *pSettings = uart->settings;
348}
349
350NEXUS_Error NEXUS_Uart_SetSettings(NEXUS_UartHandle uart, const NEXUS_UartSettings *pSettings)
351{
352    NEXUS_Error errCode;
353    NEXUS_UartSettings settings;
354
355    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
356
357    if ( NULL == pSettings )
358    {
359        NEXUS_Uart_GetDefaultSettings(&settings);
360        pSettings = &settings;
361    }
362
363    if ( uart->urtChannel )
364    {
365        if ( pSettings->baudRate != uart->settings.baudRate ||
366             pSettings->dataBits != uart->settings.dataBits ||
367             pSettings->stopBits != uart->settings.stopBits ||
368             pSettings->parity != uart->settings.parity )
369        {
370            /* BURT does not support changing these on the fly.  Close the channel and re-open it */
371            BURT_CloseChannel(uart->urtChannel);
372            uart->urtChannel = NULL;
373        }
374    }
375
376    if ( NULL == uart->urtChannel )
377    {
378        BURT_ChannelSettings channelSettings;
379
380        BURT_GetChannelDefaultSettings(g_NEXUS_uart.urt, uart-g_NEXUS_uarts, &channelSettings);
381        channelSettings.rxIntMode = true;
382        channelSettings.txIntMode = true;
383        channelSettings.rxEnable = channelSettings.txEnable = true;
384        channelSettings.baud = pSettings->baudRate;
385        channelSettings.bits = (pSettings->dataBits == NEXUS_UartDataBits_e7)?BURT_DataBits_eDataBits7:BURT_DataBits_eDataBits8;
386        switch ( pSettings->parity )
387        {
388        case NEXUS_UartParity_eNone:
389            channelSettings.parity = BURT_Parity_eNone;
390            break;
391        case NEXUS_UartParity_eOdd:
392            channelSettings.parity = BURT_Parity_eOdd;
393            break;
394        case NEXUS_UartParity_eEven:
395            channelSettings.parity = BURT_Parity_eEven;
396            break;
397        default:
398            return BERR_TRACE(BERR_INVALID_PARAMETER);
399        }
400
401        errCode = BURT_OpenChannel(g_NEXUS_uart.urt, &uart->urtChannel, uart-g_NEXUS_uarts, &channelSettings);
402        if ( errCode )
403        {
404            return BERR_TRACE(errCode);
405        }
406        uart->txRead = uart->txWrite = 0;
407        uart->rxRead = uart->rxWrite = 0;
408        uart->rxCallbackArmed = true;
409
410        /* Register our DataReady isr with BURT. Once we registered an ISR callback,
411           BURT will not use the event mechanism.
412        */
413        BURT_RegisterCallback(uart->urtChannel, NEXUS_Uart_P_DataReady_isr);
414    }
415
416    NEXUS_IsrCallback_Set(uart->errorCallback, &pSettings->error);
417    NEXUS_IsrCallback_Set(uart->rxReadyCallback, &pSettings->rxReady);
418    NEXUS_TaskCallback_Set(uart->txDoneCallback, &pSettings->txDone);
419
420    uart->settings = *pSettings;
421
422    return BERR_SUCCESS;
423}
424
425NEXUS_Error NEXUS_Uart_Read(NEXUS_UartHandle uart, void *pData, size_t numBytes, size_t *pBytesRead)
426{
427    size_t rxReadIndex;
428    size_t bytesRemaining;
429    size_t numBytesRead=0;
430    uint8_t *pCharData = (uint8_t *)pData;
431    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
432    BDBG_ASSERT(NULL != pData);
433    BDBG_ASSERT(NULL != pBytesRead);
434
435    /* We need to use the rxWrite pointer to determine bytes remaining. Do it
436       in a critical section so we don't collide with the RX isr.
437    */
438    BKNI_EnterCriticalSection();
439    /* Find out how many bytes are in our FIFO */
440    bytesRemaining = NEXUS_Uart_P_FifoData_isr(uart->rxRead, uart->rxWrite, uart->settings.rxBufferSize);
441    /* Capture the read index pointer while in the critical section */
442    rxReadIndex = uart->rxRead;
443    /* Let ISR know we're ready to be called again. Do this now because we've just taken
444       a snapshot of how much data there is, so we need to be called again when new data
445       shows up.
446    */
447    uart->rxCallbackArmed = true;
448    BKNI_LeaveCriticalSection();
449
450    /* If it's more than the caller can take, adjust */
451    if (bytesRemaining > numBytes) {
452        bytesRemaining = numBytes;
453    }
454
455    while (numBytesRead < bytesRemaining)
456    {
457        pCharData[numBytesRead++] = uart->pRxFifo[rxReadIndex++];
458        if (rxReadIndex >= uart->settings.rxBufferSize)
459        {
460            rxReadIndex = 0;
461        }
462    }
463
464    *pBytesRead = numBytesRead;
465
466    BKNI_EnterCriticalSection();
467    /* We've read all the data we can from the FIFO. Do a block move of our read index pointer */
468    uart->rxRead = rxReadIndex;
469    BKNI_LeaveCriticalSection();
470
471
472    return BERR_SUCCESS;
473}
474
475NEXUS_Error NEXUS_Uart_Write(NEXUS_UartHandle uart, const void *pData, size_t bufferSize, size_t *pBytesWritten)
476{
477    size_t txWriteIndex;
478    size_t sizeRemaining;
479    size_t numBytesWritten=0;
480    uint8_t *pCharData = (uint8_t *)pData;
481    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
482    BDBG_ASSERT(NULL != pData);
483    BDBG_ASSERT(NULL != pBytesWritten);
484
485    /* We can't send bytes directly into BURT if there is data in our nexus
486       FIFO, otherwise we interrupt the TX Callback sequence. The safest way
487       to do this is to push everything into our fifo and let all the TX
488       activity get handled by our TX callback.
489    */
490    BKNI_EnterCriticalSection();
491    sizeRemaining = NEXUS_Uart_P_FifoFreeSpace_isr(uart->txRead, uart->txWrite, uart->settings.txBufferSize);
492    txWriteIndex = uart->txWrite;
493    BKNI_LeaveCriticalSection();
494
495    /* If caller is giving us more than we can take, adjust... */
496    if (bufferSize > sizeRemaining) {
497        bufferSize = sizeRemaining;
498    }
499
500    while (numBytesWritten < bufferSize)
501    {
502        uart->pTxFifo[txWriteIndex++] = pCharData[numBytesWritten++];
503        if ( txWriteIndex >= uart->settings.txBufferSize )
504        {
505            txWriteIndex = 0;
506        }
507    }
508
509    *pBytesWritten = numBytesWritten;
510
511    BKNI_EnterCriticalSection();
512    uart->txWrite = txWriteIndex;
513    /* Arm the callback so user gets notified when output FIFO drains */
514    uart->txCallbackArmed = true;
515    BKNI_LeaveCriticalSection();
516
517    /* Notify the TX task */
518    BKNI_SetEvent(uart->txEvent);
519
520
521    return BERR_SUCCESS;
522}
523
524NEXUS_Error NEXUS_Uart_GetStatus(NEXUS_UartHandle uart, NEXUS_UartStatus *pStatus)
525{
526    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
527    BDBG_ASSERT(NULL != pStatus);
528
529    *pStatus = uart->status;
530
531    return BERR_SUCCESS;
532}
533
534static void NEXUS_Uart_P_RxCallback_isr(NEXUS_UartHandle uart)
535{
536    NEXUS_Error rc;
537    unsigned sizeRemaining;
538    uint32_t maxRead;
539    BERR_Code errCode;
540
541    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
542
543    if (BURT_IsRxDataAvailable_Isr(uart->urtChannel) == false) {
544        return;
545    }
546
547    sizeRemaining = NEXUS_Uart_P_FifoFreeSpace_isr(uart->rxRead, uart->rxWrite, uart->settings.rxBufferSize);
548
549    if (sizeRemaining == 0) {
550        rc = BERR_TRACE(NEXUS_OUT_OF_DEVICE_MEMORY);
551        return;
552    }
553
554    if (uart->rxWrite < uart->rxRead) {
555        maxRead = sizeRemaining;
556    }
557    else {
558        if (uart->rxRead) {
559            maxRead = uart->settings.rxBufferSize - uart->rxWrite;
560        }
561        else {
562            maxRead = uart->settings.rxBufferSize - uart->rxWrite - 1;
563        }
564    }
565
566    if (maxRead)
567    {
568        uint32_t bytesRead;
569        BURT_RxError error;
570
571        /* This is safe, but could be more optimal if it involved fewer function calls by grouping data */
572        errCode = BURT_Read_Isr(uart->urtChannel, uart->pRxFifo + uart->rxWrite, maxRead, &bytesRead, &error);
573        /* Ignore the return error code. It only gets set if the RX error code
574           is non-zero. We only need to look at the RX error code
575        */
576        if ( error != BURT_RxError_eNoError )
577        {
578            switch ( error )
579            {
580            default:
581                break;
582            case BURT_RxError_eReceiverOverRun:
583                uart->status.rxOverrun++;
584                BDBG_WRN(("Receiver Overrun on UART %d", uart-g_NEXUS_uarts));
585                break;
586            case BURT_RxError_eReceiverFrameError:
587                uart->status.rxFrameError++;
588                BDBG_WRN(("Receiver Frame Error on UART %d", uart-g_NEXUS_uarts));
589                break;
590            case BURT_RxError_eReceiverParityError:
591                uart->status.rxParityError++;
592                BDBG_WRN(("Receiver Parity Error on UART %d", uart-g_NEXUS_uarts));
593                break;
594            }
595            if ( uart->settings.error.callback )
596            {
597                NEXUS_IsrCallback_Fire_isr(uart->errorCallback);
598            }
599        }
600
601        uart->rxWrite += bytesRead;
602        uart->status.rxBytes += bytesRead;
603        if ( uart->rxWrite >= uart->settings.rxBufferSize )
604        {
605            uart->rxWrite = 0;
606        }
607    }
608
609    /* Re-enable RX interrupt. We need an ISR version of this call... */
610    BURT_EnableRxInt(uart->urtChannel, true);
611
612    if ( uart->rxCallbackArmed && uart->settings.rxReady.callback )
613    {
614        NEXUS_IsrCallback_Fire_isr(uart->rxReadyCallback);
615        /* Don't fire the RX task again until it's ready */
616        uart->rxCallbackArmed = false;
617    }
618}
619
620static void NEXUS_Uart_P_TxCallback(void *context)
621{
622    NEXUS_UartHandle uart = (NEXUS_UartHandle)context;
623    unsigned bytesRemaining;
624    unsigned maxWrite;
625    uint32_t urtBufferSize=0;
626    BERR_Code errCode;
627
628    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
629
630    BKNI_EnterCriticalSection();
631    bytesRemaining = NEXUS_Uart_P_FifoData_isr(uart->txRead, uart->txWrite, uart->settings.txBufferSize);
632
633    /* Calculate the max bytes we can send into BURT, up to the end of our
634       circular buffer. Trying to handle the wrap would be too complicated.
635    */
636    maxWrite = (uart->txRead <= uart->txWrite) ? bytesRemaining : (uart->settings.txBufferSize - uart->txRead);
637    BKNI_LeaveCriticalSection();
638
639    /* If we have no data to transmit, it means a) we just completed transmitting
640       all our data or b) BURT is receiving data -- at which point it always
641       informs us of the TX ready interrupt because it doesn't mask properly
642    */
643    if (maxWrite == 0)
644    {
645        if (uart->txCallbackArmed && uart->settings.txDone.callback) {
646            NEXUS_TaskCallback_Fire(uart->txDoneCallback);
647            uart->txCallbackArmed = false;
648        }
649        return;
650    }
651
652    /* Don't loop here. Send what we can and let the tx interrupt tell us when to
653       send more.
654    */
655    if ((urtBufferSize=BURT_GetAvailTxFifoCnt_Isr(uart->urtChannel)) > 0 )
656    {
657        if (urtBufferSize > maxWrite) {
658            urtBufferSize = maxWrite;
659        }
660        errCode = BURT_Write(uart->urtChannel, uart->pTxFifo + uart->txRead, urtBufferSize);
661        if ( errCode )
662        {
663            errCode = BERR_TRACE(errCode);
664            return;
665        }
666        BKNI_EnterCriticalSection();
667        uart->txRead += urtBufferSize;
668        /* The reason this simple check works is because we limited our transmit size
669           above so we didn't have to deal with the buffer wrap.
670        */
671        if (uart->txRead >= uart->settings.txBufferSize)
672        {
673            uart->txRead = 0;
674        }
675        BKNI_LeaveCriticalSection();
676        uart->status.txBytes += urtBufferSize;
677    }
678}
679
680static void NEXUS_Uart_P_DataReady_isr(void * context, int param)
681{
682    NEXUS_Error rc;
683    NEXUS_UartHandle uart;
684
685    /* BURT doesn't let us pass in our own context so we need to search our list */
686    {
687        int i;
688        for (i = 0; i < NEXUS_NUM_UARTS; i++) {
689            if (g_NEXUS_uarts[i].urtChannel == context) {
690                break;
691            }
692        }
693        if (i == NEXUS_NUM_UARTS) {
694            /* Failed to find our uart */
695            rc = BERR_TRACE(BERR_INVALID_PARAMETER);
696            return;
697        }
698        uart = &g_NEXUS_uarts[i];
699    }
700
701    BDBG_OBJECT_ASSERT(uart, NEXUS_Uart);
702
703    /* RX: param == 0; TX: param == 1. No enum types in burt.h */
704    switch (param) {
705        case 0:
706            /* Handle RX at ISR time */
707            NEXUS_Uart_P_RxCallback_isr(uart);
708            break;
709        case 1:
710            /* Handle TX in deferred task */
711            BKNI_SetEvent_isr(uart->txEvent);
712            break;
713        default:
714            rc = BERR_TRACE(param);
715    }
716
717    return;
718}
719
720NEXUS_Error NEXUS_UartModule_Standby_priv(bool enabled, const NEXUS_StandbySettings *pSettings)
721{
722#if NEXUS_POWER_MANAGEMENT
723    unsigned i;
724    NEXUS_Error rc;
725    BSTD_UNUSED(pSettings);
726   
727    if (enabled) {
728        for (i=0; i<NEXUS_NUM_UARTS; i++) {
729            NEXUS_UartHandle uart = &g_NEXUS_uarts[i];
730            if (uart->opened) {
731                BURT_CloseChannel(uart->urtChannel); /* BURT_CloseChannel disables both Rx and Tx interrupts */
732            }
733        }
734    }
735    else {
736        for (i=0; i<NEXUS_NUM_UARTS; i++) {
737            NEXUS_UartHandle uart = &g_NEXUS_uarts[i];
738            if (uart->opened) {
739                rc = NEXUS_Uart_SetSettings(uart, &uart->settings); /* NEXUS_Uart_SetSettings calls BURT_OpenChannel */
740                if (!rc) { return BERR_TRACE(rc); }
741            }
742        }
743    }
744    return NEXUS_SUCCESS;
745#else
746    BSTD_UNUSED(pSettings);
747    BSTD_UNUSED(enabled);
748    return NEXUS_SUCCESS;
749#endif
750}
751
Note: See TracBrowser for help on using the repository browser.