sylixos下S3C2440串口驅動實現

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                       SylixOS(TM)
**
**                               Copyright  All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: samsungtty.h
**
** 創   建   人: Han.Hui (韓輝)
**
** 文件創建日期: 2007 年 09 月 20 日
**
** 描        述: tty 驅動.
*********************************************************************************************************/

#ifndef __SAMSUNGTTY_H
#define __SAMSUNGTTY_H

/*********************************************************************************************************
  初始化波特率
*********************************************************************************************************/

#define UART_DEFAULT_BAUD      (SIO_BAUD_115200)                        /*  默認波特率                  */
#define UART_DEFAULT_OPT       (CREAD | CS8)                            /*  默認選項                    */

/*********************************************************************************************************
  485 控制命令
*********************************************************************************************************/

#define RS485_SET              (FIOUSRFUNC + 1)                         /*  485 使能或禁能命令          */
#define RS485_GET              (FIOUSRFUNC + 2)                         /*  獲得串口是否工作在 485 狀態 */

/*********************************************************************************************************
  485 輸入輸出控制
*********************************************************************************************************/

#define RS485_EN               1                                        /*  使能485                     */
#define RS485_DIS              0                                        /*  禁能485                     */

/*********************************************************************************************************
** Function name:           sioChanCreate
** Descriptions:            創建一個 sio 通道
** input parameters:        iChannelNum     硬件通道號
** output parameters:       NONE
** Returned value:          NONE
*********************************************************************************************************/
SIO_CHAN    *sioChanCreate(INT   iChannelNum);

#endif                                                                  /*  __SAMSUNGTTY_H              */
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                       SylixOS(TM)
**
**                               Copyright  All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: samsungtty.c
**
** 創   建   人: Han.Hui (韓輝)
**
** 文件創建日期: 2007 年 09 月 20 日
**
** 描        述: tty 驅動.
**
** BUG:
2009.05.31  串口開中斷的時機有錯誤.
2009.07.21  修正 485 方向角控制錯誤.
2012.12.14  修正 FIFO 滿判斷錯誤.
2014.05.27  startup 僅僅打開 Tx FIFO 空中斷即可.
2014.07.20  加入設備電源管理.
*********************************************************************************************************/
#define  __SYLIXOS_KERNEL
#include "config.h"                                                     /*  工程配置 & 處理器相關       */
#include "SylixOS.h"
#include "uart.h"
#include "samsungtty.h"
/*********************************************************************************************************
  對指定管腳進行操作
*********************************************************************************************************/
#define __COM1_RS485_SEND_START()       BIT_SET(rGPGDAT, 0)
#define __COM1_RS485_SEND_END()         BIT_CLR(rGPGDAT, 0)
/*********************************************************************************************************
  判斷 FIFO 有效個數
*********************************************************************************************************/
#define __COM_FIFO_CNT                  64
#define __COM_FIFO_CNT_MASK             0x7F
/*********************************************************************************************************
  STREAM UART CHANNEL (SIO CHANNEL)
*********************************************************************************************************/
typedef struct {
    SIO_DRV_FUNCS             *pdrvFuncs;                               /*  SIO 驅動程序組              */
    LW_PM_DEV                  pmdev;                                   /*  電源管理節點                */
    
    INT                      (*pcbGetTxChar)();                         /*  中斷回調函數                */
    INT                      (*pcbPutRcvChar)();
    
    PVOID                      pvGetTxArg;                              /*  回調函數句柄                */
    PVOID                      pvPutRcvArg;
    
    INT                        iChannelMode;                            /*  同步 IO 通道模式            */
    
    UCHAR                    (*pfuncHwInByte)(INT);                     /*  物理硬件接收一個字節        */
    VOID                     (*pfuncHwOutByte)(INT, CHAR);              /*  物理硬件發送一個字節        */
    
    INT                        iChannelNum;                             /*  通道號                      */
    INT                        iBaud;                                   /*  波特率                      */
    
    INT                        iHwOption;                               /*  硬件選項                    */
    INT                        iRs485Flag;                              /*  對串口是否要使能485功能     */

} __SAMSUNGSIO_CHANNEL;
typedef __SAMSUNGSIO_CHANNEL  *__PSAMSUNGSIO_CHANNEL;                   /*  指針類型                    */
/*********************************************************************************************************
  SIO 通道控制塊
*********************************************************************************************************/
static __SAMSUNGSIO_CHANNEL     __GsamsungsiochanUart0;
static __SAMSUNGSIO_CHANNEL     __GsamsungsiochanUart1;
static __SAMSUNGSIO_CHANNEL     __GsamsungsiochanUart2;
/*********************************************************************************************************
  UART 驅動程序
*********************************************************************************************************/
static INT   __uartIoctl(SIO_CHAN  *psiochanChan, INT  iCmd, LONG lArg);/*  端口控制                    */
static INT   __uartStartup(SIO_CHAN    *psiochanChan);                  /*  發送                        */
static INT   __uartcbInstall(SIO_CHAN          *psiochanChan,           /*  安裝回調                    */
                             INT                iCallbackType,
                             VX_SIO_CALLBACK    callbackRoute,
                             PVOID              pvCallbackArg);
static INT   __uartPollRxChar(SIO_CHAN    *psiochanChan,
                              PCHAR        pcInChar);                   /*  輪詢接收                    */
static INT   __uartPollTxChar(SIO_CHAN *, CHAR);                        /*  輪詢發送                    */
static irqreturn_t  __uartIsr(SIO_CHAN  *psiochanChan);                 /*  接收中斷                    */
static VOID  __uartHwOptionAnalyse(INT     iHwOption, 
                                   PUCHAR  pucDataBits, 
                                   PUCHAR  pucStopBits, 
                                   PUCHAR  pucParity);                  /*  分析硬件參數                */
/*********************************************************************************************************
  SIO 驅動程序
*********************************************************************************************************/
static SIO_DRV_FUNCS    __GsiodrvUartDrvFunc = {
             (INT (*)(SIO_CHAN *,INT, PVOID))__uartIoctl,
             __uartStartup,
             __uartcbInstall,
             __uartPollRxChar,
             (INT (*)(SIO_CHAN *, CHAR))__uartPollTxChar
};
/*********************************************************************************************************
** Function name:           __uartHwOptionAnalyse
** Descriptions:            分析 SIO 通道硬件參數
** input parameters:        iHwOption                   硬件參數
** output parameters:       pucDataBits,                數據位數
                            pucStopBits,                結束位
                            pucParity                   校驗位
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static VOID   __uartHwOptionAnalyse (INT     iHwOption, 
                                     PUCHAR  pucDataBits, 
                                     PUCHAR  pucStopBits, 
                                     PUCHAR  pucParity)
{
    if ((iHwOption & CS8) == CS8) {                                     /*  確定數據位數                */
        *pucDataBits = 8;
    } else if (iHwOption & CS7) {
        *pucDataBits = 7;
    } else if (iHwOption & CS6) {
        *pucDataBits = 6;
    } else {
        *pucDataBits = 5;
    }
    
    if (iHwOption & STOPB) {                                            /*  確定結束位                  */
        *pucStopBits = TWO_STOPBIT;
    } else {
        *pucStopBits = ONE_STOPBIT;
    }
    
    if (iHwOption & PARENB) {                                           /*  確定校驗位                  */
        if (iHwOption & PARODD) {
            *pucParity = CHK_ODD;
        } else {
            *pucParity = CHK_EVEN;
        }
    } else {
        *pucParity = CHK_NONE;
    }
}
/*********************************************************************************************************
** Function name:           sioChanCreate
** Descriptions:            創建一個 sio 通道
** input parameters:        iChannelNum     硬件通道號
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/12/20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
SIO_CHAN    *sioChanCreate (INT   iChannelNum)
{
    static PLW_PM_ADAPTER    pmadapter = LW_NULL;
    __PSAMSUNGSIO_CHANNEL    psamsungsiochanUart;
    SIO_CHAN                *psiochan;
    
    UCHAR                    ucDataBits;
    UCHAR                    ucStopBits;
    UCHAR                    ucParity;
    
    if (pmadapter == LW_NULL) {
        pmadapter =  pmAdapterFind("inner_pm");
        if (pmadapter == LW_NULL) {
            printk(KERN_ERR "can not find power manager.\n");
        }
    }

    switch (iChannelNum) {
    
    case COM0:
        pmDevInit(&__GsamsungsiochanUart0.pmdev, pmadapter, 10, LW_NULL);
        __GsamsungsiochanUart0.pmdev.PMD_pcName = "uart0";
        psamsungsiochanUart              = &__GsamsungsiochanUart0;
        psamsungsiochanUart->pdrvFuncs   = &__GsiodrvUartDrvFunc;       /*  SIO FUNC                    */
        psamsungsiochanUart->iChannelNum = COM0;
        
        API_InterVectorConnect(VIC_CHANNEL_UART0, 
                               (PINT_SVR_ROUTINE)__uartIsr, 
                               (PVOID)&__GsamsungsiochanUart0,
                               "uart0_isr");                            /*  安裝操作系統中斷向量表      */
        break;
    
    case COM1:
        pmDevInit(&__GsamsungsiochanUart1.pmdev, pmadapter, 11, LW_NULL);
        __GsamsungsiochanUart1.pmdev.PMD_pcName = "uart1";
        psamsungsiochanUart              = &__GsamsungsiochanUart1;
        psamsungsiochanUart->pdrvFuncs   = &__GsiodrvUartDrvFunc;       /*  SIO FUNC                    */
        psamsungsiochanUart->iChannelNum = COM1;
        
        API_InterVectorConnect(VIC_CHANNEL_UART1, 
                               (PINT_SVR_ROUTINE)__uartIsr, 
                               (PVOID)&__GsamsungsiochanUart1,
                               "uart1_isr");                            /*  安裝操作系統中斷向量表      */
        break;
    
    case COM2:
        pmDevInit(&__GsamsungsiochanUart2.pmdev, pmadapter, 12, LW_NULL);
        __GsamsungsiochanUart2.pmdev.PMD_pcName = "uart2";
        psamsungsiochanUart              = &__GsamsungsiochanUart2;
        psamsungsiochanUart->pdrvFuncs   = &__GsiodrvUartDrvFunc;       /*  SIO FUNC                    */
        psamsungsiochanUart->iChannelNum = COM2;
        
        API_InterVectorConnect(VIC_CHANNEL_UART2, 
                               (PINT_SVR_ROUTINE)__uartIsr, 
                               (PVOID)&__GsamsungsiochanUart2,
                               "uart2_isr");                            /*  安裝操作系統中斷向量表      */
        break;
    
    default:
        return  (LW_NULL);                                              /*  通道號錯誤                  */
    }
    
    psiochan = (SIO_CHAN *)psamsungsiochanUart;
    
    psamsungsiochanUart->iChannelMode = SIO_MODE_INT;                   /*  使用中斷模式                */
    psamsungsiochanUart->iBaud        = UART_DEFAULT_BAUD;              /*  初始化波特率                */
    psamsungsiochanUart->iHwOption    = UART_DEFAULT_OPT;               /*  硬件狀態                    */
    psamsungsiochanUart->iRs485Flag   = RS485_DIS;                      /*  默認不使用485功能           */
    
    __uartHwOptionAnalyse(UART_DEFAULT_OPT,
                          &ucDataBits,
                          &ucStopBits,
                          &ucParity);                                   /*  獲得具體參數                */
                          
    uartInit(iChannelNum, UNUSE_INF, ucDataBits, ucStopBits, 
             ucParity, UART_DEFAULT_BAUD, LW_NULL);
             
    return  (psiochan);
}
/*********************************************************************************************************
** Function name:           __uartcbInstall
** Descriptions:            SIO 通道安裝回調函數
** input parameters:        psiochanChan                 通道
**                          iCallbackType                回調類型
**                          callbackRoute                回調函數
**                          pvCallbackArg                回調參數
** output parameters:       NONE
** Returned value:          錯誤號
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT   __uartcbInstall(SIO_CHAN          *psiochanChan,
                             INT                iCallbackType,
                             VX_SIO_CALLBACK    callbackRoute,
                             PVOID              pvCallbackArg)
{
    __PSAMSUNGSIO_CHANNEL     psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan;
    
    switch (iCallbackType) {
    
    case SIO_CALLBACK_GET_TX_CHAR:                                      /*  發送回電函數                */
        psamsungsiochanUart->pcbGetTxChar = callbackRoute;
        psamsungsiochanUart->pvGetTxArg   = pvCallbackArg;
        return    (ERROR_NONE);
        
    case SIO_CALLBACK_PUT_RCV_CHAR:                                     /*  接收回電函數                */
        psamsungsiochanUart->pcbPutRcvChar = callbackRoute;
        psamsungsiochanUart->pvPutRcvArg   = pvCallbackArg;
        return    (ERROR_NONE);
        
    default:
        _ErrorHandle(ENOSYS);
        return    (PX_ERROR);
    }
}
/*********************************************************************************************************
** Function name:           __uart485Delay
** Descriptions:            uart1 485 模式軟延遲, 由於 485 收發器換向頻率限制, 所以在發送前後, 必須加入
                            軟件延遲, 此程序在 gcc -O3 -Os 測試通過
** input parameters:        iTimes          延遲循環數量 (一般爲 40)
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static VOID  __uart485Delay (INT  iTimes)
{
    volatile int    i;
    
    for (; iTimes > 0; iTimes--) {
        for (i = 0; i < 15; i++);
    }
}
/*********************************************************************************************************
** Function name:           __uartStartup
** Descriptions:            SIO 通道發送(沒有使用中斷)
** input parameters:        psiochanChan                 通道
** output parameters:       NONE
** Returned value:          SIO 通道控制塊指針
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT   __uartStartup (SIO_CHAN    *psiochanChan)
{
    __PSAMSUNGSIO_CHANNEL     psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan;
    CHAR                      cTx;
    
    switch (psamsungsiochanUart->iChannelNum) {
    
    case COM0:
        INTER_CLR_SUBMSK(BIT_SUB_TXD0);                                 /*  使能 FIFO 空中斷            */
        break;
    
    case COM1:
        if (psamsungsiochanUart->iRs485Flag == RS485_EN) {              /*  485 模式使用查詢發送方式    */
            __COM1_RS485_SEND_START();                                  /*  485 換向(發送模式)          */
            __uart485Delay(40);                                         /*  短延遲                      */
            do {
                if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, &cTx)
                    != ERROR_NONE) {
                    break;                                              /*  發送完畢                    */
                }
                while (rUFSTAT1 & (1 << 14));                           /*  FIFO 未滿                   */
                WrUTXH1(cTx);                                           /*  發送數據                    */
            } while (1);
            while ((rUTRSTAT1 & (1 << 2)) == 0);                        /*  等待發送緩衝器爲空          */
            __COM1_RS485_SEND_END();                                    /*  485 換向(接收模式)          */
            __uart485Delay(40);                                         /*  短延遲                      */
        
        } else {                                                        /*  全雙工模式採用中斷髮送      */
            INTER_CLR_SUBMSK(BIT_SUB_TXD1);                             /*  使能 FIFO 空中斷            */
        }
        break;
        
    case COM2:
        INTER_CLR_SUBMSK(BIT_SUB_TXD2);                                 /*  使能 FIFO 空中斷            */
        break;
    }
    
    return    (ERROR_NONE);
}
/*********************************************************************************************************
** Function name:           __uartPollRxChar
** Descriptions:            SIO 通道輪詢接收
** input parameters:        psiochanChan                 通道
** output parameters:       pcInChar                     接收的字節
** Returned value:          接收的個數
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT   __uartPollRxChar (SIO_CHAN    *psiochanChan, PCHAR  pcInChar)
{
    __PSAMSUNGSIO_CHANNEL     psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan;
    
    switch (psamsungsiochanUart->iChannelNum) {
    
    case COM0:
        if (rUFSTAT0 & __COM_FIFO_CNT_MASK) {
            *pcInChar = RdURXH0();
        } else {
            _ErrorHandle(EAGAIN);
            return  (PX_ERROR);
        }
        break;
        
    case COM1:
        if (rUFSTAT1 & __COM_FIFO_CNT_MASK) {
            *pcInChar = RdURXH1();
        } else {
            _ErrorHandle(EAGAIN);
            return  (PX_ERROR);
        }
        break;
        
    case COM2:
        if (rUFSTAT2 & __COM_FIFO_CNT_MASK) {
            *pcInChar = RdURXH2();
        } else {
            _ErrorHandle(EAGAIN);
            return  (PX_ERROR);
        }
        break;
    }
    
    return    (ERROR_NONE);
}
/*********************************************************************************************************
** Function name:           __uartPollTxChar
** Descriptions:            SIO 通道輪詢發送
** input parameters:        psiochanChan                 通道
**                          cOutChar                     發送的字節
** output parameters:       NONE
** Returned value:          發送的個數
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT   __uartPollTxChar (SIO_CHAN   *psiochanChan, CHAR  cOutChar)
{
    __PSAMSUNGSIO_CHANNEL     psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan;
    
    switch (psamsungsiochanUart->iChannelNum) {
    
    case COM0:
        while (rUFSTAT0 & (1 << 14));                                   /*  FIFO 未滿                   */
        WrUTXH0(cOutChar);                                              /*  發送數據                    */
        break;
        
    case COM1:
        while (rUFSTAT1 & (1 << 14));                                   /*  FIFO 未滿                   */
        WrUTXH1(cOutChar);                                              /*  發送數據                    */
        break;
        
    case COM2:
        while (rUFSTAT2 & (1 << 14));                                   /*  FIFO 未滿                   */
        WrUTXH2(cOutChar);                                              /*  發送數據                    */
        break;
    }
    
    return    (ERROR_NONE);
}
/*********************************************************************************************************
** Function name:           __uartIsr
** Descriptions:            SIO 通道中斷處理函數
** input parameters:        psiochanChan                 通道
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static irqreturn_t  __uartIsr (SIO_CHAN  *psiochanChan)
{
    __PSAMSUNGSIO_CHANNEL     psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan;
    UCHAR                     ucData;
    
    switch (psamsungsiochanUart->iChannelNum) {
    
    case COM0:
        if (rSUBSRCPND & BIT_SUB_TXD0) {
            INTER_CLR_SUBSRCPND(BIT_SUB_TXD0);                          /*  清除發送中斷                */
        }
        if (rSUBSRCPND & BIT_SUB_RXD0) {
            INTER_CLR_SUBSRCPND(BIT_SUB_RXD0);                          /*  清除接收中斷                */
        }
        INTER_CLR_PNDING(BIT_UART0);                                    /*  清除中斷標誌                */
        while (((rUFSTAT0 >> 8) & __COM_FIFO_CNT_MASK) < __COM_FIFO_CNT) {
                                                                        /*  TxFIFO 未滿                 */
            if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, 
                (PCHAR)&ucData) != ERROR_NONE) {                        /*  發送結束                    */
                INTER_SET_SUBMSK(BIT_SUB_TXD0);                         /*  發送結束                    */
                break;
            } else {
                WrUTXH0(ucData);                                        /*  發送數據                    */
            }
        }
        while (rUFSTAT0 & __COM_FIFO_CNT_MASK)  {                       /*  需要接收數據                */
            ucData = RdURXH0();
            psamsungsiochanUart->pcbPutRcvChar(psamsungsiochanUart->pvPutRcvArg, ucData);
        }
        break;
        
    case COM1:
        if (rSUBSRCPND & BIT_SUB_TXD1) {
            INTER_CLR_SUBSRCPND(BIT_SUB_TXD1);                          /*  清除發送中斷                */
        }
        if (rSUBSRCPND & BIT_SUB_RXD1) {
            INTER_CLR_SUBSRCPND(BIT_SUB_RXD1);                          /*  清除接收中斷                */
        }
        INTER_CLR_PNDING(BIT_UART1);                                    /*  清除中斷標誌                */
        while (((rUFSTAT1 >> 8) & __COM_FIFO_CNT_MASK) < __COM_FIFO_CNT) {
                                                                        /*  TxFIFO 未滿                 */
            if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, 
                (PCHAR)&ucData) != ERROR_NONE) {                        /*  發送結束                    */
                INTER_SET_SUBMSK(BIT_SUB_TXD1);                         /*  發送結束                    */
                break;
            } else {
                WrUTXH1(ucData);                                        /*  發送數據                    */
            }
        }
        while (rUFSTAT1 & __COM_FIFO_CNT_MASK)  {                       /*  需要接收數據                */
            ucData = RdURXH1();
            psamsungsiochanUart->pcbPutRcvChar(psamsungsiochanUart->pvPutRcvArg, ucData);
        }
        break;
        
    case COM2:
        if (rSUBSRCPND & BIT_SUB_TXD2) {
            INTER_CLR_SUBSRCPND(BIT_SUB_TXD2);                          /*  清除發送中斷                */
        }
        if (rSUBSRCPND & BIT_SUB_RXD2) {
            INTER_CLR_SUBSRCPND(BIT_SUB_RXD2);                          /*  清除接收中斷                */
        }
        INTER_CLR_PNDING(BIT_UART2);                                    /*  清除中斷標誌                */
        while (((rUFSTAT2 >> 8) & __COM_FIFO_CNT_MASK) < __COM_FIFO_CNT) {
                                                                        /*  TxFIFO 未滿                 */
            if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, 
                (PCHAR)&ucData) != ERROR_NONE) {                        /*  發送結束                    */
                INTER_SET_SUBMSK(BIT_SUB_TXD2);                         /*  發送結束                    */
                break;
            } else {
                WrUTXH2(ucData);                                        /*  發送數據                    */
            }
        }
        while (rUFSTAT2 & __COM_FIFO_CNT_MASK) {                        /*  需要接收數據                */
            ucData = RdURXH2();
            psamsungsiochanUart->pcbPutRcvChar(psamsungsiochanUart->pvPutRcvArg, ucData);
        }
        break;
    }
    
    return  (LW_IRQ_HANDLED);
}
/*********************************************************************************************************
** Function name:           __uartIoctl
** Descriptions:            SIO 通道控制
** input parameters:        psiochanChan                 通道
**                          iCmd                         命令
**                          lArg                         參數
** output parameters:       NONE
** Returned value:          命令執行結果
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT   __uartIoctl (SIO_CHAN  *psiochanChan, INT  iCmd, LONG  lArg)
{
    __PSAMSUNGSIO_CHANNEL   psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan;
    
    UCHAR                   ucDataBits;
    UCHAR                   ucStopBits;
    UCHAR                   ucParity;
    
    switch (iCmd) {
    
    case SIO_BAUD_SET:                                                  /*  設置模特率                  */
        __uartHwOptionAnalyse(psamsungsiochanUart->iHwOption,
                              &ucDataBits,
                              &ucStopBits,
                              &ucParity);                               /*  獲得具體參數                */
        uartInit(psamsungsiochanUart->iChannelNum, UNUSE_INF, 
                 ucDataBits, ucStopBits, 
                 ucParity, (INT)lArg, LW_NULL);                         /*  初始化串口                  */
        psamsungsiochanUart->iBaud = (INT)lArg;
        break;
        
    case SIO_BAUD_GET:                                                  /*  獲得波特率                  */
        *((LONG *)lArg) = psamsungsiochanUart->iBaud;
        break;
    
    case SIO_HW_OPTS_SET:                                               /*  設置硬件參數                */
        __uartHwOptionAnalyse((INT)lArg,
                              &ucDataBits,
                              &ucStopBits,
                              &ucParity);                               /*  獲得具體參數                */
        uartInit(psamsungsiochanUart->iChannelNum, UNUSE_INF, 
                 ucDataBits, ucStopBits, 
                 ucParity, psamsungsiochanUart->iBaud, LW_NULL);        /*  初始化串口                  */
        psamsungsiochanUart->iHwOption = (INT)lArg;                     /*  記錄信息                    */
        break;
        
    case SIO_HW_OPTS_GET:                                               /*  獲取硬件參數                */
        *((INT *)lArg) = psamsungsiochanUart->iHwOption;
        break;
    
    case SIO_OPEN:                                                      
        switch (psamsungsiochanUart->iChannelNum) {
        
        case COM0:
            pmDevOn(&psamsungsiochanUart->pmdev);
            INTER_CLR_PNDING((1u << VIC_CHANNEL_UART0));
            INTER_CLR_SUBMSK(BIT_SUB_RXD0);                             /*  打開接收中斷                */
            API_InterVectorEnable(VIC_CHANNEL_UART0);                   /*  使能串口中斷                */
            break;
            
        case COM1:
            pmDevOn(&psamsungsiochanUart->pmdev);
            INTER_CLR_PNDING((1u << VIC_CHANNEL_UART1));
            INTER_CLR_SUBMSK(BIT_SUB_RXD1);                             /*  打開接收中斷                */
            API_InterVectorEnable(VIC_CHANNEL_UART1);                   /*  使能串口中斷                */
            break;
            
        case COM2:
            pmDevOn(&psamsungsiochanUart->pmdev);
            INTER_CLR_PNDING((1u << VIC_CHANNEL_UART2));
            INTER_CLR_SUBMSK(BIT_SUB_RXD2);                             /*  打開接收中斷                */
            API_InterVectorEnable(VIC_CHANNEL_UART2);                   /*  使能串口中斷                */
            break;
        }
        break;
        
    case SIO_HUP:                                                       /*  關閉串口                    */
        switch (psamsungsiochanUart->iChannelNum) {
        
        case COM0:
            pmDevOff(&psamsungsiochanUart->pmdev);
            API_InterVectorDisable(VIC_CHANNEL_UART0);
            INTER_CLR_PNDING((1u << VIC_CHANNEL_UART0));
            break;
            
        case COM1:
            pmDevOff(&psamsungsiochanUart->pmdev);
            API_InterVectorDisable(VIC_CHANNEL_UART1);
            INTER_CLR_PNDING((1u << VIC_CHANNEL_UART1));
            break;
            
        case COM2:
            pmDevOff(&psamsungsiochanUart->pmdev);
            API_InterVectorDisable(VIC_CHANNEL_UART2);
            INTER_CLR_PNDING((1u << VIC_CHANNEL_UART2));
            break;
        }
        break;
        
    case RS485_SET:                                                     /*  設置 485 狀態               */
        if (psamsungsiochanUart->iChannelNum == COM1) {
            psamsungsiochanUart->iRs485Flag  =  (INT)lArg;
            if (lArg) {
                rGPGCON = (rGPGCON & ~(0x3)) | (0x1);                   /*  GPG0 輸出                   */
                BIT_CLR(rGPGUP, 0);                                     /*  使能上拉                    */
                __COM1_RS485_SEND_END();                                /*  結束髮送狀態                */
            }
        }
        break;
        
    case RS485_GET:                                                     /*  獲取 485 狀態               */
        *((LONG *)lArg) = psamsungsiochanUart->iRs485Flag;
        break;
        
    default:
        _ErrorHandle(ENOSYS);
        return    (ENOSYS);
    }
    
    return    (ERROR_NONE);
}
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                       SylixOS(TM)
**
**                               Copyright  All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: uart.h
**
** 創   建   人: Han.Hui (韓輝)
**
** 文件創建日期: 2007 年 09 月 20 日
**
** 描        述: uart 驅動.
*********************************************************************************************************/

#ifndef __UART_H
#define __UART_H

/*********************************************************************************************************
  MACRO
*********************************************************************************************************/
#define COM0            0                                               /*  串口 0                      */
#define COM1            1                                               /*  串口 1                      */
#define COM2            2                                               /*  串口 2                      */

#define CHK_ODD         0x4                                             /*  奇校驗                      */
#define CHK_EVEN        0x5                                             /*  偶校驗                      */
#define CHK_NONE        0x0                                             /*  沒有校驗                    */

#define USE_INF         1                                               /*  使用紅外模式                */
#define UNUSE_INF       0                                               /*  不使用紅外模式              */

#define ONE_STOPBIT     0                                               /*  一個停止位                  */
#define TWO_STOPBIT     1                                               /*  兩個停止位                  */
/*********************************************************************************************************
** Function name:           uartInit
** Descriptions:            初始化 UART
** input parameters:        iCom                串口號
**                          iInFrared           是否使用紅外模式
**                          iData               數據位數
**                          iStopBit            結束位
**                          iCheck              校驗方法
**                          iBaud               波特率
**                          pvIsrRoutine        中斷服務函數, 爲NULL表示不允許中斷
** output parameters:       NONE
** Returned value:          正確返回 0,  錯誤返回 -1
*********************************************************************************************************/
int  uartInit(int   iCom,
              int   iInFrared,
              int   iData,
              int   iStopBit,
              int   iCheck,
              int   iBaud,
              void *pvIsrRoutine);
                  
/*********************************************************************************************************
** Function name:           uartSendByte
** Descriptions:            UART 發送一個字節的數據
** input parameters:        iCom                串口號
**                          ucData              數據
** output parameters:       NONE
** Returned value:          正確返回 0,  錯誤返回 -1
*********************************************************************************************************/
int  uartSendByte(int  iCom, unsigned char  ucData);

/*********************************************************************************************************
** Function name:           uartSendByteCnt
** Descriptions:            UART 發送指定長度的數據
** input parameters:        iCom                串口號
**                          pucData             數據緩衝區
** output parameters:       NONE
** Returned value:          NONE
*********************************************************************************************************/
void uartSendByteCnt(int             iCom, 
                     unsigned char  *pucData,
                     int             iCnt);
                         
/*********************************************************************************************************
** Function name:           uartSendString
** Descriptions:            UART 發送一個字符串
** input parameters:        iCom                串口號
**                          pcData              字符串
** output parameters:       NONE
** Returned value:          NONE
*********************************************************************************************************/
void uartSendString(int   iCom, char  *pcData);

/*********************************************************************************************************
** Function name:           debugChannelInit
** Descriptions:            初始化調試接口
** input parameters:        iChannelNum                 通道號
** output parameters:       NONE
** Returned value:          NONE
*********************************************************************************************************/
void debugChannelInit(int   iChannelNum);

#endif                                                                  /*  __UART_H                    */
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                       SylixOS(TM)
**
**                               Copyright  All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: uart.c
**
** 創   建   人: Han.Hui (韓輝)
**
** 文件創建日期: 2007 年 09 月 20 日
**
** 描        述: uart 驅動.
*********************************************************************************************************/
#define  __SYLIXOS_KERNEL
#include "config.h"
#include "uart.h"
#include "SylixOS.h"
/*********************************************************************************************************
  宏定義
*********************************************************************************************************/
#define __COM0_CLKBIT       (1 << 10)                                   /*  COM0 在 CLKCON 中的位置     */
#define __COM1_CLKBIT       (1 << 11)                                   /*  COM1 在 CLKCON 中的位置     */
#define __COM2_CLKBIT       (1 << 12)                                   /*  COM2 在 CLKCON 中的位置     */

#define __COM0_GPIO         ((1 << 2) | (1 << 3))                       /*  COM0 在 IO 口線中的位置     */
#define __COM1_GPIO         ((1 << 4) | (1 << 5))                       /*  COM1 在 IO 口線中的位置     */
#define __COM2_GPIO         ((1 << 6) | (1 << 7))                       /*  COM2 在 IO 口線中的位置     */

#define __COM0_GPHCON       ((0x2 <<  4) | (0x2 <<  6))                 /*  COM0 在 GPHCON 中的設置     */
#define __COM1_GPHCON       ((0x2 <<  8) | (0x2 << 10))                 /*  COM1 在 GPHCON 中的設置     */
#define __COM2_GPHCON       ((0x2 << 12) | (0x2 << 14))                 /*  COM1 在 GPHCON 中的設置     */

#define __COM0_MASK         ((0x3 <<  4) | (0x3 <<  6))                 /*  COM0 在 GPHCON 中的區域     */
#define __COM1_MASK         ((0x3 <<  8) | (0x3 << 10))                 /*  COM1 在 GPHCON 中的區域     */
#define __COM2_MASK         ((0x3 << 12) | (0x3 << 14))                 /*  COM2 在 GPHCON 中的區域     */
/*********************************************************************************************************
** Function name:           uartInit
** Descriptions:            初始化 UART
** input parameters:        iCom                串口號
**                          iInFrared           是否使用紅外模式
**                          iData               數據位數
**                          iStopBit            結束位
**                          iCheck              校驗方法
**                          iBaud               波特率
**                          pvIsrRoutine        中斷服務函數, 爲NULL表示不允許中斷
** output parameters:       NONE
** Returned value:          正確返回 0,  錯誤返回 -1
** Created by:              Hanhui
** Created Date:            2007/09/18
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
int     uartInit (int   iCom,
                  int   iInFrared,
                  int   iData,
                  int   iStopBit,
                  int   iCheck,
                  int   iBaud,
                  void *pvIsrRoutine)
{
    unsigned int        uiUBRDIVn;                                      /*  波特率發生器值              */
    unsigned int        uiULCONn;                                       /*  線控制器值                  */
    unsigned int        uiUCONn;                                        /*  串口控制寄存器值            */
    unsigned int        uiUFCONn;                                       /*  FIFO 控制寄存器值           */
    
    unsigned int        uiInterEn;                                      /*  是否允許中斷                */
    
    if (iData < 5) {                                                    /*  數據位數錯誤                */
        return  (-1);
    }
    iData -= 5;                                                         /*  確定寄存器中的值            */
    
    uiInterEn = (pvIsrRoutine == (void *)0) ? 0 : 1;                    /*  確定是否需要中斷            */
    
    iBaud = (iBaud << 4);                                               /*  baud = baud * 16            */
    iBaud = PCLK / iBaud;
    iBaud = (int)(iBaud - 0.5);
    
    uiUBRDIVn = iBaud;                                                  /*  波特率                      */
    
    uiULCONn  = ((iInFrared << 6)
              |  (iCheck    << 3)
              |  (iStopBit  << 2)
              |  (iData));                                              /*  基本控制信息                */
    
    uiUCONn   = ((0x00 << 10)                                           /*  PCLK                        */
              |  (1 << 9)                                               /*  Tx Interrupt Type LEVEL     */
              |  (1 << 8)                                               /*  Rx Interrupt Type LEVEL     */
              |  (1 << 7)                                               /*  Rx Time Out Enable          */
              |  (0 << 6)                                               /*  Rx Error Status             */
                                                                        /*  Interrupt Disable           */
              |  (0 << 5)                                               /*  Loopback Mode Disable       */
              |  (0 << 4)
              |  (1 << 2)                                               /*  Tx Interrupt or poll        */
              |  (1));                                                  /*  Rx Interrupt or poll        */
    
    uiUFCONn  = ((0x0 << 6)                                             /*  Tx FIFO Trigger Level 0     */
              |  (0x2 << 4)                                             /*  Rx FIFO Trigger Level 16    */
              |  (1 << 2)                                               /*  Tx FIFO Reset               */
              |  (1 << 1)                                               /*  Rx FIFO Reset               */
              |  (1));                                                  /*  FIFO Enable                 */

    if (iCom == COM0) {                                                 /*  設置 UART0 的 管腳          */

        rGPHCON &= ~(__COM0_MASK);
        rGPHCON |=   __COM0_GPHCON;
        rGPHUP  &= ~(__COM0_GPIO);                                      /*  使用上拉電阻                */
        
        rCLKCON |=   __COM0_CLKBIT;                                     /*  時鐘掛接                    */

        rUCON0   = 0;
        rUFCON0  = uiUFCONn;
        rUMCON0  = 0;                                                   /*  關閉流控                    */
        rULCON0  = uiULCONn;
        rUCON0   = uiUCONn;
        rUBRDIV0 = uiUBRDIVn;
        
        if (uiInterEn) {                                                /*  鏈接中斷服務函數            */
            API_InterVectorConnect(VIC_CHANNEL_UART0, 
                                   (PINT_SVR_ROUTINE)pvIsrRoutine,
                                   LW_NULL,
                                   "uart0_isr");
            INTER_CLR_MSK((1u << VIC_CHANNEL_UART0));                   /*  解除屏蔽中斷                */
            INTER_CLR_SUBMSK(BIT_SUB_RXD0);                             /*  打開接收中斷                */
        }
    
    } else if (iCom == COM1) {                                          /*  設置 UART1 的 管腳          */
    
        rGPHCON &= ~(__COM1_MASK);
        rGPHCON |=   __COM1_GPHCON;
        rGPHUP  &= ~(__COM1_GPIO);                                      /*  使用上拉電阻                */
        
        rCLKCON |=   __COM1_CLKBIT;                                     /*  時鐘掛接                    */
        
        rUCON1   = 0;
        rUFCON1  = uiUFCONn;
        rUMCON1  = 0;                                                   /*  關閉流控                    */
        rULCON1  = uiULCONn;
        rUCON1   = uiUCONn;
        rUBRDIV1 = uiUBRDIVn;
        
        if (uiInterEn) {                                                /*  鏈接中斷服務函數            */
            API_InterVectorConnect(VIC_CHANNEL_UART1, 
                                   (PINT_SVR_ROUTINE)pvIsrRoutine,
                                   LW_NULL,
                                   "uart1_isr");
            INTER_CLR_MSK((1u << VIC_CHANNEL_UART1));                   /*  解除屏蔽中斷                */
            INTER_CLR_SUBMSK(BIT_SUB_RXD1);                             /*  打開接收中斷                */
        }
    
    } else if (iCom == COM2) {                                          /*  設置 UART2 的 管腳          */
        
        rGPHCON &= ~(__COM2_MASK);
        rGPHCON |=   __COM2_GPHCON;
        rGPHUP  &= ~(__COM2_GPIO);                                      /*  使用上拉電阻                */
        
        rCLKCON |=   __COM2_CLKBIT;                                     /*  時鐘掛接                    */
        
        rUCON2   = 0;
        rUFCON2  = uiUFCONn;
        rUMCON2  = 0;                                                   /*  關閉流控                    */
        rULCON2  = uiULCONn;
        rUCON2   = uiUCONn;
        rUBRDIV2 = uiUBRDIVn;
        
        if (uiInterEn) {                                                /*  鏈接中斷服務函數            */
            API_InterVectorConnect(VIC_CHANNEL_UART2, 
                                   (PINT_SVR_ROUTINE)pvIsrRoutine,
                                   LW_NULL,
                                   "uart2_isr");
            INTER_CLR_MSK((1u << VIC_CHANNEL_UART2));                   /*  解除屏蔽中斷                */
            INTER_CLR_SUBMSK(BIT_SUB_RXD2);                             /*  打開接收中斷                */
        }
    
    } else {                                                            /*  串口出錯                    */
        
        return  (-1);
    }
    
    return  (0);
}
/*********************************************************************************************************
** Function name:           uartSendByte
** Descriptions:            UART 發送一個字節的數據
** input parameters:        iCom                串口號
**                          ucData              數據
** output parameters:       NONE
** Returned value:          正確返回 0,  錯誤返回 -1
** Created by:              Hanhui
** Created Date:            2007/09/18
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
int     uartSendByte (int   iCom, unsigned char  ucData)
{
    switch (iCom) {
    
    case COM0:
        while (rUFSTAT0 & (1 << 14));
        while (((rUFSTAT0) >> 8) & 0x3F);                               /*  Tx_FIFO IS EMPTY            */
        WrUTXH0(ucData);
        break;
        
    case COM1:
        while (rUFSTAT1 & (1 << 14));
        while (((rUFSTAT1) >> 8) & 0x3F);                               /*  Tx_FIFO IS EMPTY            */
        WrUTXH1(ucData);
        break;
    
    case COM2:
        while (rUFSTAT2 & (1 << 14));
        while (((rUFSTAT2) >> 8) & 0x3F);                               /*  Tx_FIFO IS EMPTY            */
        WrUTXH2(ucData);
        break;
    
    default:                                                            /*  串口號錯誤                  */
        return  (1);
    }
    
    return  (0);
}
/*********************************************************************************************************
** Function name:           uartSendByteCnt
** Descriptions:            UART 發送指定長度的數據
** input parameters:        iCom                串口號
**                          pucData             數據緩衝區
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/09/18
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
void    uartSendByteCnt (int             iCom, 
                         unsigned char  *pucData,
                         int             iCnt)
{
    for (; iCnt != 0; iCnt--) {
        uartSendByte(iCom, *pucData);                                   /*  發送數據                    */
        pucData++;
    }
}
/*********************************************************************************************************
** Function name:           uartSendString
** Descriptions:            UART 發送一個字符串
** input parameters:        iCom                串口號
**                          pcData              字符串
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/09/18
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
void     uartSendString (int   iCom, char  *pcData)
{
    if (!pcData) {                                                      /*  指針爲空                    */
        return;
    }
    
    while (*pcData != '\0') {                                           /*  發送字符串                  */
        uartSendByte(iCom, (unsigned char)*pcData);
        pcData++;
    }
}
/*********************************************************************************************************
** Function name:           debugChannelInit
** Descriptions:            初始化調試接口
** input parameters:        iChannelNum                 通道號
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2007/09/24
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
void    debugChannelInit (int  iChannelNum)
{
    uartInit(iChannelNum, UNUSE_INF, 8, ONE_STOPBIT, CHK_NONE, 115200, (void *)0);
}
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章