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 2005中Target菜单中选择 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;
}