您的位置:首页 > 其它

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

2011-12-25 22:52 330 查看
 
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息