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];
}