天天看点

VxWorks BSP学习笔记_串口驱动1.     串口驱动

VxWorks BSP学习笔记(基于SBC8349E)

1.     串口驱动

1.1   串行驱动程序的重要结构

以下结构指出了驱动程序函数的入口点  ../target/h/sioLib.h

Typedef struct sio_drv_funcs          

{

    int     (*ioctl)

        (

        SIO_CHAN * pSioChan,

        int    cmd,

        void *     arg

        );

    int     (*txStartup)

        (

        SIO_CHAN * pSioChan

        );

    int     (*callbackInstall)

        (

        SIO_CHAN * pSioChan,

        int    callbackType,

        STATUS     (*callback)(void *, ...),

        void *     callbackArg

        );

    int     (*pollInput)

        (

        SIO_CHAN * pSioChan,

        char *     inChar

        );

    int     (*pollOutput)

        (

        SIO_CHAN * pSioChan,

        char       outChar

        );

}SIO_DRV_FUNCS;

typedef struct sio_chan           

    {

    SIO_DRV_FUNCS * pDrvFuncs;

} SIO_CHAN;

在串行设备的驱动程序中,必须有一个包含指向SIO_DRV_FUNCS指针的结构(XX_CHAN),这个结构可以包含设备的其他信息以及提供给高层协议的回调函数。以16550为例:

../target/h/drv/sio/ns16552Sio.h

typedef  struct  

    {

    SIO_DRV_FUNCS *     pDrvFuncs;     

    STATUS      (*getTxChar) ();  

    STATUS      (*putRcvChar) ();

    void *      getTxArg;

    void *      putRcvArg;

    UINT8   *regs;    

    UINT8   level;    

    UINT8   ier;      

    UINT8   lcr;      

    UINT8   mcr;      

    UINT16      channelMode;  

    UINT16      regDelta; 

    int         baudRate;

    UINT32      xtal;          

    UINT32  options;  

} NS16550_CHAN;

1.2   串行驱动程序的初始化函数

串行设备驱动程序的初始化函数应该包含下面的内容:

1)  包含一个指向xx_DRV结构的指针;

2)  初始化xx_CHAN;

3)  初始化驱动程序必要的内容;

4)  重新设置芯片

../target/src/drv/sio/ns16550Sio.c

#ifdef INCLUDE_TTY_DEV

static SIO_DRV_FUNCS ns16550SioDrvFuncs =

    {

    (int (*)()) ns16550Ioctl,

    (int (*)()) ns16550TxStartup,

    (int (*)()) ns16550CallbackInstall,

    (int (*)()) ns16550PollInput,

    (int (*)(SIO_CHAN *,char))ns16550PollOutput

    };

#else 

static SIO_DRV_FUNCS ns16550SioDrvFuncs =

    {

    (int (*)()) NULL,

    (int (*)()) NULL,

    (int (*)()) NULL,

    (int (*)()) ns16550PollInput,

    (int (*)(SIO_CHAN *,char))ns16550PollOutput

    };

#endif 

void ns16550DevInit

    (

        NS16550_CHAN * pChan

    )

    {

    int oldlevel = intLock ();

    pChan->pDrvFuncs    = &ns16550SioDrvFuncs;

    pChan->getTxChar    = ns16550DummyCallback;

    pChan->putRcvChar   = ns16550DummyCallback;

    pChan->channelMode  = 0;   

    pChan->options      = (CLOCAL | CREAD | CS8);

    pChan->mcr     = MCR_OUT2;

    ns16550InitChannel (pChan);

    intUnlock (oldlevel);

}

1.3   回调安装函数以及驱动各函数的实现

SIO_DRV_FUNCS结构中的各函数的实现

1.4   串行设备的安装

1.4.1          串行设备的初始化

sysDuartHwInit(),由usrInit()函数调用,初始化了驱动程序相关的xx_CHAN结构。调用了xxDevInit()函数初始化硬件,设置中断未连接标志。该函数在内核初始化之前完成。使用16550芯片的例子:

void sysDuartHwInit (void)

    {

    int i;

    eumbbar_base = (char *)CCSBAR;

    for (i = 0; i < N_DUART_CHANNELS; i++)

        {

    ns16550Chan[i].regs        = (UINT8 *)devDuartParas[i].baseAdrs;

    ns16550Chan[i].level    = devDuartParas[i].intLevel;

    ns16550Chan[i].channelMode = SIO_MODE_INT;

    ns16550Chan[i].regDelta    = devDuartParas[i].regSpace;

    ns16550Chan[i].baudRate     = DUART_BAUD;

    ns16550Chan[i].xtal     = sysClkFreqGet();

    ns16550DevInit (&ns16550Chan[i]);

        }

    if (ns16550Chan[0].channelMode == SIO_MODE_INT)

    {

        eumbbar_base[UDCR1] = 0x01; 

        eumbbar_base[ULCR1] = 0x80; 

        eumbbar_base[UAFR1] = 0x00;

        eumbbar_base[UDMB1] = 0x03; 

    eumbbar_base[UDLB1] = 0x64; 

    eumbbar_base[ULCR1] = 0x03; 

    eumbbar_base[UMCR1] = 0x02; 

    eumbbar_base[UIER1] = 0x03; 

    }

    if (ns16550Chan[1].channelMode == SIO_MODE_INT)

    {

        eumbbar_base[UDCR2] = 0x01; 

        eumbbar_base[ULCR2] = 0x80; 

        eumbbar_base[UAFR2] = 0x00;

        eumbbar_base[UDMB2] = 0x01; 

    eumbbar_base[UDLB2] = 0xB2; 

    eumbbar_base[ULCR2] = 0x03; 

    eumbbar_base[UMCR2] = 0x02; 

    eumbbar_base[UIER2] = 0x03; 

    }

}

1.4.2          安装串行设备的ISR

sysDuartHwInit2()由usrRoot任务中的sysClkConnnect()函数调用,安装了设备的中断服务程序。这个函数在系统初始化之后执行,此时系统已经可以执行中断连接了。

void sysSerialHwInit2 (void)

    {

    int i;

    for (i = 0; i < N_DUART_CHANNELS; i++)

        {

        (void) intConnect ((VOIDFUNCPTR *)((int)devDuartParas[i].vector),

                           (VOIDFUNCPTR)ns16550Int, (int)&ns16550Chan[i] );

        intEnable (devDuartParas[i].vector);

        }

}

1.4.3          串行设备描述符与通道号的转换

sysSerialChanGet()的作用是将串行设备通道的索引转换为该通道的设备描述符。通常目标机代理会使用这个函数以获得通道的指针,usrRoot()任务也会用到该函数。

SIO_CHAN * sysSerialChanGet

    (

    int channel        

    )

    {

    if ( (channel < 0) ||

         (channel >= (int)NELEMENTS(sysSerialSioChans)) )

    return (SIO_CHAN *) ERROR;

    return sysSerialSioChans[channel];

    }

继续阅读