VxWorks BSP学习笔记_串口驱动

来源:互联网 发布:管家婆服装软件 编辑:程序博客网 时间:2024/05/20 20:18

VxWorks BSP学习笔记(基于SBC8349E

1.     串口驱动

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

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

Typedef struct sio_drv_funcs           /* driver functions */

{

    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            /* a serial channel */

    {

    SIO_DRV_FUNCS * pDrvFuncs;

    /* device data */

} SIO_CHAN;

 

 

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

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

typedef  struct   /* NS16550_CHAN * */

    {

    /* always goes first */

 

    SIO_DRV_FUNCS *     pDrvFuncs;      /* driver functions */

 

    /* callbacks */

 

    STATUS      (*getTxChar) (); /* pointer to xmitr function */ 

    STATUS      (*putRcvChar) (); /* pointer to rcvr function */

    void *      getTxArg;

    void *      putRcvArg;

 

    UINT8   *regs;     /* NS16552 registers */

    UINT8   level;     /* 8259a interrupt level for this device */

    UINT8   ier;       /* copy of ier */

    UINT8   lcr;       /* copy of lcr, not used by ns16552 driver */

    UINT8   mcr;       /* copy of modem control register */

 

    UINT16      channelMode;   /* such as INT, POLL modes */

    UINT16      regDelta;  /* register address spacing */

    int         baudRate;

    UINT32      xtal;      /* UART clock frequency     */    

    UINT32  options;   /* hardware setup options */

 

} NS16550_CHAN;

 

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

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

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

2)  初始化xx_CHAN

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

4)  重新设置芯片

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

/* driver functions */

 

#ifdef INCLUDE_TTY_DEV

static SIO_DRV_FUNCS ns16550SioDrvFuncs =

    {

    (int (*)()) ns16550Ioctl,

    (int (*)()) ns16550TxStartup,

    (int (*)()) ns16550CallbackInstall,

    (int (*)()) ns16550PollInput,

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

    };

#else  /* INCLUDE_TTY_DEV */

static SIO_DRV_FUNCS ns16550SioDrvFuncs =

    {

    (int (*)()) NULL,

    (int (*)()) NULL,

    (int (*)()) NULL,

    (int (*)()) ns16550PollInput,

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

    };

#endif  /* INCLUDE_TTY_DEV */

 

 

void ns16550DevInit

    (

        NS16550_CHAN * pChan /* pointer to channel */

    )

    {

    int oldlevel = intLock ();

 

    /* initialize the driver function pointers in the SIO_CHAN's */

 

    pChan->pDrvFuncs    = &ns16550SioDrvFuncs;

 

    /* set the non BSP-specific constants */

 

    pChan->getTxChar    = ns16550DummyCallback;

    pChan->putRcvChar   = ns16550DummyCallback;

    pChan->channelMode  = 0;    /* undefined */

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

    pChan->mcr     = MCR_OUT2;

 

    /* reset the chip */

 

    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;  /* set duart mode */

        eumbbar_base[ULCR1] = 0x80;  /* open DLAB */

        eumbbar_base[UAFR1] = 0x00;

        eumbbar_base[UDMB1] = 0x03;  /* for mpc8245 MSB, 9600bps @66Mhz */

    eumbbar_base[UDLB1] = 0x64;  /* LSB */

    eumbbar_base[ULCR1] = 0x03;  /* clear DLAB, no-parity, 1stop bit, 8bit data */

    eumbbar_base[UMCR1] = 0x02;  /* disable loopback mode */

    eumbbar_base[UIER1] = 0x03;  /* Tx empty, Rx interrupt enable */

    }

 

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

    {

        eumbbar_base[UDCR2] = 0x01;  /* set duart mode */

        eumbbar_base[ULCR2] = 0x80;  /* open DLAB */

        eumbbar_base[UAFR2] = 0x00;

        eumbbar_base[UDMB2] = 0x01;  /* for mpc8245 MSB, 9600bps @66Mhz */

    eumbbar_base[UDLB2] = 0xB2;  /* LSB */

    eumbbar_base[ULCR2] = 0x03;  /* clear DLAB, no-parity, 1stop bit, 8bit data */

    eumbbar_base[UMCR2] = 0x02;  /* diable loopback mode */

    eumbbar_base[UIER2] = 0x03;  /* Tx empty, Rx interrupt enable */

    }

 

} /* sysDuartHwInit () */

 

1.4.2          安装串行设备的ISR

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

void sysSerialHwInit2 (void)

    {

    int i;

 

    /* connect serial interrupts */

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

        {

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

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

        intEnable (devDuartParas[i].vector);

 

        }

} /* sysDuartHwInit2 () */

 

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

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

 

SIO_CHAN * sysSerialChanGet

    (

    int channel         /* serial channel */

    )

    {

    if ( (channel < 0) ||

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

    return (SIO_CHAN *) ERROR;

 

    return sysSerialSioChans[channel];

    }

 

 

原创粉丝点击