sylixos 串口驱动流程

     在Sylixos 下串口被封装成一个字符设备;

1,我们可以看到内核库源码ty目录下,是内核封装好的字符设备,在开发时我们只要完成相关具体的io操作及回调函数的填充即可:

2,tty 设备的实现:

基本流程,(1)安装驱动操作函数; (2)实现SIO_CHAN 结构体中的回调函数供tty 设备函数进行回调使用,创建 tty 设备,创建收发缓冲区;

(3)需要我们实现 SIO_DRV_FUNCS 中ioctl()、txStartup、callbackInstall 、pollInput、pollOutput这些函数以及在驱动中实现中断函数的注册;

ttyDrv == API_TtyDrvInstall        // 安装TTY设备驱动程序

LW_API 
INT  API_TtyDrvInstall (VOID)
{
    if (_G_iTycoDrvNum > 0) {
        return  (ERROR_NONE);
    }
    
    _G_iTycoDrvNum = iosDrvInstall(_ttyOpen, 
                                   (FUNCPTR)LW_NULL, 
                                   _ttyOpen,
                                   _ttyClose,
                                   _TyRead,
                                   _TyWrite,
                                   _ttyIoctl);
                                    
    DRIVER_LICENSE(_G_iTycoDrvNum,     "GPL->Ver 2.0");
    DRIVER_AUTHOR(_G_iTycoDrvNum,      "Han.hui");
    DRIVER_DESCRIPTION(_G_iTycoDrvNum, "tty driver.");
    
    return  ((_G_iTycoDrvNum > 0) ? (ERROR_NONE) : (PX_ERROR));
}

通过以上代码可知tty 设备使用的相关io 操作的接口;
psio0 = sioChanCreate(BSP_CFG_DBG_UART_CH);          /*  创建串口通道,该部分需要由驱动开发着实现 */
ttyDevCreate("/dev/ttyS0", psio0, 30, 50);       /*  add    tty   device         */
// 该函数创建一个 ttyS0 的设备,并且将 psio0 传递给内核相关操作函数使用

LW_API 
INT  API_TtyDevCreate (PCHAR     pcName,
                       SIO_CHAN *psiochan,
                       size_t    stRdBufSize,
                       size_t    stWrtBufSize)
{
    REGISTER INT           iTemp;
    REGISTER TYCO_DEV     *ptycoDev;
    
    if (LW_CPU_GET_CUR_NESTING()) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "called from ISR.\r\n");
        _ErrorHandle(ERROR_KERNEL_IN_ISR);
        return  (PX_ERROR);
    }
    
    if (_G_iTycoDrvNum <= 0) {    //判断 driver 操作函数是否被注册
        _DebugHandle(__ERRORMESSAGE_LEVEL, "tty Driver invalidate.\r\n");
        _ErrorHandle(ERROR_IO_NO_DRIVER);
        return  (PX_ERROR);
    }
    
    if (psiochan == LW_NULL) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "SIO channel invalidate.\r\n");
        _ErrorHandle(ERROR_IOS_DEVICE_NOT_FOUND);
        return  (PX_ERROR);
    }
    
    if ((pcName == LW_NULL) || (*pcName == PX_EOS)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "device name invalidate.\r\n");
        _ErrorHandle(EFAULT);                                           /*  Bad address                 */
        return  (PX_ERROR);
    }
    
    ptycoDev = (TYCO_DEV *)__SHEAP_ALLOC(sizeof(TYCO_DEV));             /*  分配内存                    */
    if (ptycoDev == LW_NULL) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "system low memory.\r\n");
        _ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
        return  (PX_ERROR);
    }
    
    iTemp = _TyDevInit(&ptycoDev->TYCODEV_tydevTyDev, 
                       stRdBufSize, 
                       stWrtBufSize,
                       (FUNCPTR)_ttyStartup);                           /*  初始化设备控制块            */
    
    if (iTemp != ERROR_NONE) {
        __SHEAP_FREE(ptycoDev);
        _DebugHandle(__ERRORMESSAGE_LEVEL, "system low memory.\r\n");
        _ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
        return  (PX_ERROR);
    }
    
    ptycoDev->TYCODEV_psiochan = psiochan;
    
    sioCallbackInstall(psiochan, SIO_CALLBACK_GET_TX_CHAR,
            (VX_SIO_CALLBACK)_TyITx, (PVOID)ptycoDev);
    sioCallbackInstall(psiochan, SIO_CALLBACK_PUT_RCV_CHAR,
            (VX_SIO_CALLBACK)_TyIRd, (PVOID)ptycoDev);
    
    sioIoctl(psiochan, SIO_MODE_SET, (PVOID)SIO_MODE_INT);
    
    iTemp = (INT)iosDevAddEx(&ptycoDev->TYCODEV_tydevTyDev.TYDEV_devhdrHdr, 
                             pcName, 
                             _G_iTycoDrvNum,
                             DT_CHR);
    if (iTemp) {
        _TyDevRemove(&ptycoDev->TYCODEV_tydevTyDev);
        __SHEAP_FREE(ptycoDev);
        _DebugHandle(__ERRORMESSAGE_LEVEL, "add device error.\r\n");
        _ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
        return  (PX_ERROR);
    
    } else {
        ptycoDev->TYCODEV_tydevTyDev.TYDEV_timeCreate = lib_time(LW_NULL);
                                                                        /*  记录创建时间 (UTC 时间)     */
        return  (ERROR_NONE);
    }
}

3, SIO_DRV_FUNCS 中的txStartup 调用时间:

可以通过阅读源码发现在API_TtyDevCreate的 _TyDevInit函数中将该函数作为回掉函数给ptyDev->TYDEV_pfuncTxStartup,每次启动发送时 ptyDev->TYDEV_pfuncTxStartup 调用到 _ttyStartup,

_ttyStartup调用到我们在驱动中实现的pDrvFuncs->txStartup(ptycoDev->TYCODEV_psiochan) ;

在txStartup函数中,我们需要从将缓冲区的数据发送到uart 的fifo 中,并使能发送中断,代码可以参考如下:

static INT  SioStartup (SIO_CHAN  *psiochanChan)
{
    __PSIO_CHANNEL pChan = (__PSIO_CHANNEL)psiochanChan;
    CHAR           outChar;

	if (pChan->pcbGetTxChar(pChan->pvGetTxArg, &outChar) != ERROR_NONE) {
	    return ERROR_NONE;                                              /* 如果没有数据,直接返回       */
	}

    while(readl(&pChan->regs->txcount) >= JM7200_UART_FIFO_LEN);

    /*
     *  使能发送中断
     */
    writel(readl(&pChan->regs->intr) | JM7200_UART_INT_TX_ENABLE, &pChan->regs->intr);

	/*
	 *  发送数据
	 */
    writel(outChar, &pChan->regs->fifo);

    return  (ERROR_NONE);
}

由代码追踪 可以发现 pcbGetTxChar 是由 callbackInstall注册回调函数实现。

3,callbackInstall 就是驱动中用来注册发送 和接收回调函数的;

callbackInstall  在API_TtyDevCreate 被调用,可以看到:

psiochanUart->pcbGetTxChar   = _TyITx;

psiochanUart->pcbPutRcvChar = _TyIRd;

    sioCallbackInstall(psiochan, SIO_CALLBACK_GET_TX_CHAR,
            (VX_SIO_CALLBACK)_TyITx, (PVOID)ptycoDev);
    sioCallbackInstall(psiochan, SIO_CALLBACK_PUT_RCV_CHAR,
            (VX_SIO_CALLBACK)_TyIRd, (PVOID)ptycoDev);
static INT  xxxSioCbInstall (SIO_CHAN        *psiochanChan,
                              INT              iCallbackType,
                              VX_SIO_CALLBACK  callbackRoute,
                              PVOID            pvCallbackArg)
{
    __PSIO_CHANNEL          psiochanUart = (__PSIO_CHANNEL)psiochanChan;

    if (!psiochanUart) {                                                /*  参数检查                    */
        _ErrorHandle(EINVAL);
        return  (PX_ERROR);
    }

    switch (iCallbackType) {

    case SIO_CALLBACK_GET_TX_CHAR:                                      /*  发送回调函数                */
        psiochanUart->pcbGetTxChar = callbackRoute;
        psiochanUart->pvGetTxArg   = pvCallbackArg;
        return  (ERROR_NONE);

    case SIO_CALLBACK_PUT_RCV_CHAR:                                     /*  接收回调函数                */
        psiochanUart->pcbPutRcvChar = callbackRoute;
        psiochanUart->pvPutRcvArg   = pvCallbackArg;
        return  (ERROR_NONE);

    default:
        _ErrorHandle(ENOSYS);
        return  (PX_ERROR);
    }
}

4,串口中断处理函数:

    中断处理函数中一般要处理将 接收中断产生的数据提交到给串口接收缓冲区或者将 发送缓冲区的数据发送到硬件fifo 中;

   这部分也可以使用信号量来处理,将发送和接收数据通过信号机制提交到tty缓冲区,这样可以避免中断上部分可以快速处理完中断;

static irqreturn_t  xxxSioIsr (SIO_CHAN  *psiochanChan, ULONG  ulVector)
{
    clear_irq //清中断
    
   //处理发送中断产生的数据
    outChar = readl(&pChan->regs->fifo) & 0xff;
    pChan->pcbPutRcvChar(pChan->pvPutRcvArg, outChar);// 提交到内核代码中处理
    

    // 处理发送中断产生的数据
    pChan->pcbGetTxChar(pChan->pvGetTxArg, &outChar)  // 从内核tty层取出数据写到fifo下
    writel(outChar, &pChan->regs->fifo);
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值