Windows CE 6.0的内核传输无关层(KITL)分析(3)

OEMKitlStartup 函数首先完成KITL所需参数的检测和配置,通过调用OALArgsInit和OALArgsQuery检测并配置KITL所需的参数,如果OEMs商家在这两函数中没有配置KITL参数,则pKITLArgs指针为空,就采用默认的配置。亿道公司的EELiod PXA270 ARM开发平台采用LAN91C111芯片作为网卡控制,其中OAL_KITL_FLAGS_ENABLED | OAL_KITL_FLAGS_DHCP | OAL_KITL_FLAGS_VMINI标志表明在该平台中使用DHCP和VMINI(Virtual Miniport),且使能KITL传输。参数配置成功后,调用OALKitlInit 函数初始化KITL。

$(_PLATFORMROOT)\xsbase270\src\oal\Kitl\Kitl.c

BOOL OEMKitlStartup (void)

{

BOOL rc = FALSE;

OAL_KITL_ARGS *pKITLArgs, KITLArgs;

CHAR *pszDeviceId;

KITL_RETAILMSG(ZONE_KITL_OAL, ("+OEMKitlStartup\r\n"));

// Check and initialize the BSP Args area

OALArgsInit((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);

// Look for bootargs left by the bootloader or left over from an earlier boot.

pKITLArgs = (OAL_KITL_ARGS*) OALArgsQuery(OAL_ARGS_QUERY_KITL);

KITLOutputDebugString("---In OEMKitlStartup: MAC Address: %x-%x-%x\r\n",pKITLArgs->mac[0],pKITLArgs->mac[1],pKITLArgs->mac[2]);

pszDeviceId = (CHAR*) OALArgsQuery(OAL_ARGS_QUERY_DEVID);

// If no KITL arguments were found (typically provided by the bootloader), then select

// some default settings.

if (pKITLArgs == NULL)

{

KITLOutputDebugString("pKITLArgs is NULL\r\n");

memset(&KITLArgs, 0, sizeof(OAL_KITL_ARGS));

// By default, enable: KITL, DHCP, and VMINI...

KITLArgs.flags = (OAL_KITL_FLAGS_ENABLED | OAL_KITL_FLAGS_DHCP | OAL_KITL_FLAGS_VMINI);

// Use built-in LAN91C111 controller for KITL.

KITLArgs.devLoc.IfcType = Internal;

KITLArgs.devLoc.BusNumber = 0;

KITLArgs.devLoc.PhysicalLoc = (PVOID)(XSBASE270_BASE_REG_PA_SMSC_ETHERNET + 0x300);

KITLArgs.devLoc.LogicalLoc = (DWORD)KITLArgs.devLoc.PhysicalLoc;

pKITLArgs = &KITLArgs;

}

if (pszDeviceId == NULL)

{

KITL_RETAILMSG(ZONE_ERROR, ("ERROR: Unable to locate Device ID buffer\r\n"));

}

else if (pszDeviceId[0] == '\0')

{

// We don't yet have the Ethernet controller's MAC address (this is obtained

// in the initialization function. Store a base name for the device, and

// signal that it should be extended with the MAC address later.

strncpy(pszDeviceId, BSP_DEVICE_PREFIX, OAL_KITL_ID_SIZE);

pKITLArgs->flags |= OAL_KITL_FLAGS_EXTNAME;

}

// Finally call KITL library.

rc = OALKitlInit(pszDeviceId, pKITLArgs, g_kitlDevices);

KITL_RETAILMSG(ZONE_KITL_OAL, ("-OEMKitlStartup(rc = %d)\r\n", rc));

return(rc);

}

OALKitlInit函数本质上是输出OEMKitlStartup函数中所配置的KITL参数调试信息和检测参数的有效性,同时通过调用OALKitlFindDevice函数查找KITL设备,在保存KITL配置信息后再调用内核的KitlInit 函数对KITL正是初始化

$(_PLATFORMROOT)\common\src\common\Kitl\Kitl.c

BOOL OALKitlInit(

LPCSTR deviceId, OAL_KITL_ARGS *pArgs, OAL_KITL_DEVICE *pDevice

) {

BOOL rc = FALSE;

KITL_RETAILMSG(ZONE_KITL_OAL, (

"+OALKitlInit('%hs', 0x%08x - %d/%d/0x%08x, 0x%08x)\r\n", deviceId,

pArgs->flags, pArgs->devLoc.IfcType, pArgs->devLoc.BusNumber,

pArgs->devLoc.LogicalLoc, pDevice

));

// Display KITL parameters

……

// If KITL is disabled simply return

if ((pArgs->flags & OAL_KITL_FLAGS_ENABLED) == 0) {

KITL_RETAILMSG(ZONE_WARNING, ("WARN: OALKitlInit: KITL Disabled\r\n"));

rc = TRUE;

goto cleanUp;

}

// Find if we support device on given location

g_kitlState.pDevice = OALKitlFindDevice(&pArgs->devLoc, pDevice);

if (g_kitlState.pDevice == NULL) {

KITL_RETAILMSG(ZONE_ERROR, (

"ERROR: OALKitlInit: No supported KITL device at interface %d "

"bus %d location 0x%08x\r\n", pArgs->devLoc.IfcType,

pArgs->devLoc.BusNumber, pArgs->devLoc.LogicalLoc

));

goto cleanUp; }

// Save KITL configuration

memcpy(g_kitlState.deviceId, deviceId, sizeof(g_kitlState.deviceId));

memcpy(&g_kitlState.args, pArgs, sizeof(g_kitlState.args));

// Start KITL in desired mode

if (!KitlInit((pArgs->flags & OAL_KITL_FLAGS_PASSIVE) == 0)) {

KITL_RETAILMSG(ZONE_ERROR, ("ERROR: OALKitlInit: KitlInit failed\r\n"));

goto cleanUp; }

rc = TRUE;

cleanUp:

KITL_RETAILMSG(ZONE_KITL_OAL, ("-OALKitlInit(rc = %d)\r\n", rc));

return rc;

}

KitlInit函数属于KITL内核,编译在kitlcore.lib中,该函数初始化基于调试消息(KITL_SVC_DBGMSG)、文本shell和点对点文件系统(KITL_SVC_PPSH)和内核调试器(Kernel Debugger)三种默认KITL服务客户端。然后调用StartKitl函数启动KITL服务

$(_PRIVATEROOT)\WINCEOS\COREOS\NK\KITL\ethdbg.c

BOOL KitlInit (BOOL fStartKitl)

{

// Initialize default clients

NewClient (KITL_SVC_DBGMSG, KITL_SVCNAME_DBGMSG, FALSE);

NewClient (KITL_SVC_PPSH, KITL_SVCNAME_PPSH, FALSE);

NewClient (KITL_SVC_KDBG, KITL_SVCNAME_KDBG, FALSE);

InitTimerList ();

return fStartKitl? StartKitl (TRUE) : TRUE;

}

KitlInit函数的入口参数fStartKitl表明KITL包含的操作模式,当传入的参数为 TRUE 时,KITL工作在主动模式(active),这时目标平台启动时自动初始化像内核调试器(Kernel Debug)一样的所有默认的KITL客户服务,KITL服务然后再调用OEMKitlInit函数,并注册系统所需的所有默认客户服务,这种模式适合于那些具有固定连接的开发处理;当传入参数为 FALSE 时,KITL工作在被动模式(passive),在这种模式下,设备启动时并不初始化KITL及其客户服务,KITL必须完成自身及其所有默认的客户服务的初始化,余下的过程跟主动模式一样。被动模式比较适合调试器不是必须的情况,它的好处是允许用户创建一个不必同桌面系统(PC)工具绑定在一起的设备,甚至可以为移动设备,当设备需要同桌面系统连接时,设备便初始化一个同桌面系统相连的KITL服务。目前所有的嵌入式移动设备都采用这个方式同PC相连(比如利用ActiveSync)。

但在设备启动时用户必须确定设备所进入的工作模式,Platform Builder 提供了一个KTS_PASSIVE_MODE标志符供用户选择KITL工作模式,在Platform Builder中,KITL工作模式默认设置为主动模式,即在设备启动时自动初始化KITL并建立一个连接,可以通过Platform Builder的IDE中Connectivity Options菜单更该KITL的模式。从安装有Windows CE 6.0 Visual Studio 2005Target菜单中选择 Connectivity Options菜单,并弹出的对话框中选择“Core Service Settings”,当“KITL Settings ”设置中的“Enable KITL on device boot”选中时,KITL为主动模式,当清除该选项时KITL为被动模式。

StartKitl 函数首先判断KITL启动条件,如果已经启动,则直接返回,否则先调用OEMKitlInit函数初始化网络硬件,同时填充KITL传输中极为重要KITLTRANSPORT.结构体内容,并对从OEMKitlInit函数中获取的KITLTRANSPORT结构体中的内容配置情况进行判断,同时对在KitlInit函数中初始化的三种客户服务进行注册。然后对KITL连接情况进行判断,在被动模下,还需要调用KITLInitializeInterrupt初始化并注册KITL中断(具体可参考KITLInitializeInterrupt实现部分)。

$(_PRIVATEROOT)\WINCEOS\COREOS\NK\KITL\ethdbg.c

static BOOL StartKitl (BOOL fInit)

{

// KITL already started?

if (!fInit && (KITLGlobalState & KITL_ST_DESKTOP_CONNECTED)) {

return TRUE;

}

// Detect/initialize ethernet hardware, and return address information

if (!OEMKitlInit (&Kitl))

return FALSE;

// verify that the Kitl structure is initialized.

if (!Kitl.pfnDecode || !Kitl.pfnEncode || !Kitl.pfnRecv || !Kitl.pfnSend || !Kitl.pfnGetDevCfg || !Kitl.pfnSetHostCfg) {

return FALSE;

}

// pfnEnableInt can not be null if using interrupt

if (((UCHAR) KITL_SYSINTR_NOINTR != Kitl.Interrupt) && !Kitl.pfnEnableInt) {

return FALSE;

}

if (Kitl.dwPhysBuffer || Kitl.dwPhysBufLen) {

KITLOutputDebugString("\r\n!Kitl buffer specified by OAL is not required, ignore...\r\n");

}

Kitl.dwPhysBuffer = (DWORD)g_KitlBuffer;

//Kitl.dwPhysBufLen = sizeof(g_KitlBuffer);

Kitl.WindowSize = KITL_MAX_WINDOW_SIZE;

KITLGlobalState |= KITL_ST_KITLSTARTED; // indicate (to kdstub) that KITL has started

// If the initialized flag is already set, we are being called from the power on routine,

// so reinit the HW, but not any state.

if (!(KITLGlobalState & KITL_ST_ADAPTER_INITIALIZED)) {

// perform the initial handshake with the desktop

if (!KITLConnectToDesktop ()) {

KITLOutputDebugString ("\r\n!Unable to establish KITL connection with desktop!\r\n");

return FALSE;

}

// Set up kernel function pointers

KITLGlobalState |= KITL_ST_ADAPTER_INITIALIZED;

if ((Kitl.dwBootFlags & KITL_FL_DBGMSG)

&& KITLRegisterDfltClient (KITL_SVC_DBGMSG, 0, NULL, NULL)) {

g_pNKGlobal->pfnWriteDebugString = KITLWriteDebugString;

}

if (Kitl.dwBootFlags & KITL_FL_PPSH) {

KITLRegisterDfltClient (KITL_SVC_PPSH, 0, NULL, NULL);

}

// only perform cleanboot if it's connected at boot. Cleanboot flag is

// ignored if it's started dynamically.

if (fInit && (Kitl.dwBootFlags & KITL_FL_CLEANBOOT)) {

NKForceCleanBoot();

}

// if OEM calls KitlInit (FALSE), KITLInitializeInterrupt will

// not be called in SystemStartupFuc. We need to initialize

// interrupt here (when RegisterClient is called)

if (IsSystemReady () && !InSysCall ()) {

KITLInitializeInterrupt ();

}

}

return TRUE;

}

OEMKitlInit函数主要根据在OEMKitlStartup 函数保存的KITL所选用通信设备类型相应的调用不同的网络硬件初始化函数,如果采用以太网,则调用OALKitlEthInit,如果采用串行口,则调用OALKitlSerialInit函数,如果初始化成功,则对KITLTRANSPORT.结构体中的电源控制函数指针赋值,WinCE56.0移植的帮助文档中特意提到了两个函数指针。

$(_PLATFORMROOT)\common\src\common\Kitl\ Kitl.c

BOOL OEMKitlInit(PKITLTRANSPORT pKitl)

{

BOOL rc = FALSE;

KITL_RETAILMSG(ZONE_KITL_OAL, ("+OEMKitlInit(0x%08x)\r\n", pKitl));

switch (g_kitlState.pDevice->type) {

#ifdef KITL_ETHER

case OAL_KITL_TYPE_ETH:

rc = OALKitlEthInit(

g_kitlState.deviceId, g_kitlState.pDevice,

&g_kitlState.args, pKitl

);

break;

#endif

#ifdef KITL_SERIAL

case OAL_KITL_TYPE_SERIAL:

rc = OALKitlSerialInit(

g_kitlState.deviceId, g_kitlState.pDevice,

&g_kitlState.args, pKitl

);

break;

#endif

}

if (rc) {

pKitl->pfnPowerOn = OALKitlPowerOn;

pKitl->pfnPowerOff = OALKitlPowerOff;

} else {

pKitl->pfnPowerOn = NULL;

pKitl->pfnPowerOff = NULL;

}

KITL_RETAILMSG(ZONE_KITL_OAL, ("-OEMKitlInit(rc = %d)\r\n", rc));

return rc;

}

OALKitlEthInit函数完成对以太网硬件设备进行初始化,其中比较关键的硬件的获取位置,即pDriver = (OAL_KITL_ETH_DRIVER*)pDevice->pDriver;该指针指向一个具体硬件设备的各种实现过程(EELiod平台,初始化-> pfnInit,对应LAN91CInit),对亿道公司的EELiod开发平台,采用LAN91C111芯片,其对于的以太网设备实现结构体为OAL_ETHDRV_LAN91C,如下:并查询所使用的中断号。

#define OAL_ETHDRV_LAN91C { \

LAN91CInit, NULL, NULL, LAN91CSendFrame, LAN91CGetFrame, \

LAN91CEnableInts, LAN91CDisableInts, \

NULL, NULL, LAN91CCurrentPacketFilter, LAN91CMulticastList \

}

并填充KITL传输结构体KITLTRANSPORT中的必须项和IPV4结构体中项,最后初始化并激活一个虚拟微型网桥(Virtual Miniport bridge)。

$(_PLATFORMROOT)\\common\src\common\Kitl\Kitleth.c

BOOL OALKitlEthInit(

LPSTR deviceId, OAL_KITL_DEVICE *pDevice, OAL_KITL_ARGS *pArgs,

KITLTRANSPORT *pKitl

) {

BOOL rc = FALSE;

OAL_KITL_ETH_DRIVER *pDriver;

UINT32 irq, sysIntr;

KITL_RETAILMSG(ZONE_KITL_OAL, (

"+OALKitlEthInit('%S', '%s', 0x%08x, 0x%08x)\r\n",

deviceId, pDevice->name, pArgs, pKitl

));

// Cast driver config parameter

pDriver = (OAL_KITL_ETH_DRIVER*)pDevice->pDriver;

if (pDriver == NULL) {

KITL_RETAILMSG(ZONE_ERROR, ("ERROR: KITL device driver is NULL\r\n"));

goto cleanUp;

}

// Call InitDmaBuffer if there is any

if (pDriver->pfnInitDmaBuffer != NULL) {

if (!pDriver->pfnInitDmaBuffer(

(DWORD)g_oalKitlBuffer, sizeof(g_oalKitlBuffer)

)) {

KITL_RETAILMSG(ZONE_ERROR, (

"ERROR: KITL call to pfnInitDmaBuffer failed\r\n"

));

goto cleanUp;

}

}

// Call pfnInit

if (!pDriver->pfnInit(

(UCHAR*)pArgs->devLoc.PhysicalLoc, pArgs->devLoc.LogicalLoc, pArgs->mac

)) {

KITL_RETAILMSG(ZONE_ERROR, ("ERROR: KITL call to pfnInit failed\r\n"));

goto cleanUp;

}

// Extend name if flag is set

if ((pArgs->flags & OAL_KITL_FLAGS_EXTNAME) != 0) {

OALKitlCreateName(deviceId, pArgs->mac, deviceId);

}

// Now we know final name, print it

KITL_RETAILMSG(ZONE_INIT, ("KITL: *** Device Name %s ***\r\n", deviceId));

// Map and enable interrupt

if ((pArgs->flags & OAL_KITL_FLAGS_POLL) != 0) {

sysIntr = KITL_SYSINTR_NOINTR;

} else {

// Get IRQ, when interface is undefined use Pin as IRQ

if (pArgs->devLoc.IfcType == InterfaceTypeUndefined) {

irq = pArgs->devLoc.Pin;

} else {

if (!OEMIoControl(

IOCTL_HAL_REQUEST_IRQ, &pArgs->devLoc, sizeof(pArgs->devLoc),

&irq, sizeof(irq), NULL

)) {

KITL_RETAILMSG(ZONE_WARNING, (

"WARN: KITL can't obtain IRQ for KITL device\r\n"

));

irq = OAL_INTR_IRQ_UNDEFINED;

}

}

// Get SYSINTR for IRQ

if (irq != OAL_INTR_IRQ_UNDEFINED) {

UINT32 aIrqs[3];

aIrqs[0] = -1;

aIrqs[1] = (pArgs->devLoc.IfcType == InterfaceTypeUndefined)

? OAL_INTR_TRANSLATE

: OAL_INTR_FORCE_STATIC;

aIrqs[2] = irq;

if (

OEMIoControl(

IOCTL_HAL_REQUEST_SYSINTR, aIrqs, sizeof(aIrqs), &sysIntr,

sizeof(sysIntr), NULL

) && sysIntr != SYSINTR_UNDEFINED

) {

KITL_RETAILMSG(ZONE_INIT, ("KITL: using sysintr 0x%x\r\n", sysIntr));

} else {

KITL_RETAILMSG(ZONE_WARNING, (

"WARN: KITL can't obtain SYSINTR for IRQ %d\r\n", irq

));

sysIntr = KITL_SYSINTR_NOINTR;

}

} else {

sysIntr = KITL_SYSINTR_NOINTR;

}

}

if (sysIntr == KITL_SYSINTR_NOINTR) {

KITL_RETAILMSG(ZONE_WARNING, (

"WARN: KITL will run in polling mode\r\n"

));

}

//-----------------------------------------------------------------------

// Initalize KITL transport structure

//-----------------------------------------------------------------------

memcpy(pKitl->szName, deviceId, sizeof(pKitl->szName));

pKitl->Interrupt = (UCHAR)sysIntr;

pKitl->WindowSize = OAL_KITL_WINDOW_SIZE;

pKitl->FrmHdrSize = KitlEthGetFrameHdrSize();

pKitl->dwPhysBuffer = 0;

pKitl->dwPhysBufLen = 0;

pKitl->pfnEncode = KitlEthEncode;

pKitl->pfnDecode = KitlEthDecode;

pKitl->pfnSend = KitlEthSend;

pKitl->pfnRecv = KitlEthRecv;

pKitl->pfnEnableInt = KitlEthEnableInt;

pKitl->pfnGetDevCfg = KitlEthGetDevCfg;

pKitl->pfnSetHostCfg = KitlEthSetHostCfg;

//-----------------------------------------------------------------------

// Initalize KITL IP4 state structure

//-----------------------------------------------------------------------

g_kitlEthState.pDriver = pDriver;

g_kitlEthState.flags = pArgs->flags;

g_kitlEthState.deviceMAC[0] = (UINT8)pArgs->mac[0];

g_kitlEthState.deviceMAC[1] = (UINT8)(pArgs->mac[0] >> 8);

g_kitlEthState.deviceMAC[2] = (UINT8)pArgs->mac[1];

g_kitlEthState.deviceMAC[3] = (UINT8)(pArgs->mac[1] >> 8);

g_kitlEthState.deviceMAC[4] = (UINT8)pArgs->mac[2];

g_kitlEthState.deviceMAC[5] = (UINT8)(pArgs->mac[2] >> 8);

g_kitlEthState.deviceIP = pArgs->ipAddress;

g_kitlEthState.kitlServerMAC[0] = 0xFF;

g_kitlEthState.kitlServerMAC[1] = 0xFF;

g_kitlEthState.kitlServerMAC[2] = 0xFF;

g_kitlEthState.kitlServerMAC[3] = 0xFF;

g_kitlEthState.kitlServerMAC[4] = 0xFF;

g_kitlEthState.kitlServerMAC[5] = 0xFF;

g_kitlEthState.kitlServerIP = 0xFFFFFFFF;

g_kitlEthState.kitlServerPort = htons(KITL_SERVER_PORT);

g_kitlEthState.dhcpXId = pArgs->mac[2] | 0x17016414;

g_kitlEthState.dhcpState = DHCP_BOUND;

// Get or renew DHCP address

if ((pArgs->flags & OAL_KITL_FLAGS_DHCP) != 0) {

// KITL isn't running let use direct functions for send/receive

g_kitlEthState.pfnSend = pKitl->pfnSend;

g_kitlEthState.pfnRecv = pKitl->pfnRecv;

// Get or renew address from DHCP server

GetAddressDHCP(pArgs->ipAddress);

}

// When KITL is running we should call sync function for send

g_kitlEthState.pfnSend = KitlSendRawData;

// There should not be direct receive

g_kitlEthState.pfnRecv = NULL;

#ifdef KITL_ETHER

// Activate VMINI bridge...

if ((pArgs->flags & OAL_KITL_FLAGS_VMINI) != 0) {

VBridgeInit();

VBridgeKSetLocalMacAddress((char*)pArgs->mac);

}

#endif

// Result depends on fact if we get IP address

rc = (g_kitlEthState.deviceIP != 0);

cleanUp:

KITL_RETAILMSG(ZONE_KITL_OAL, ("-OALKitlEthInit(rc = %d)\r\n", rc));

return rc;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值