370 likes | 511 Views
Windows CE 5.0 总线驱动程序架构. 刘斌 北京数智动力科技有限公司. 概述. 什么是总线驱动程序?为什么需要?能做什么? 架构 新的总线驱动程序命名空间 注册表 资源分配 IOCTLs Application Child 辅助函数. 什么是总线驱动程序 ?. 加载 / 卸载驱动程序 物理总线上的硬件 在总线驱动程序没有直接管理的物理总线上加载驱动程序 管理物理总线 调用 ActivateDeviceEx() 加载设备驱动程序 为从属驱动程序提供服务. 为何需要总线驱动程序 ?. 旧版本的限制 .
E N D
Windows CE 5.0总线驱动程序架构 刘斌 北京数智动力科技有限公司
概述 • 什么是总线驱动程序?为什么需要?能做什么? • 架构 • 新的总线驱动程序命名空间 • 注册表 • 资源分配 • IOCTLs • Application • Child • 辅助函数
什么是总线驱动程序? • 加载/卸载驱动程序 • 物理总线上的硬件 • 在总线驱动程序没有直接管理的物理总线上加载驱动程序 • 管理物理总线 • 调用 ActivateDeviceEx() 加载设备驱动程序 • 为从属驱动程序提供服务
旧版本的限制 • 驱动程序和加载它们的实体间没有任何关联 • 根据句柄不能得到流的名称 • 程序不知道谁加载的它们
现在能够做到的! • 总线驱动程序加载/卸载从属驱动程序并重新列举他们的总线. • 从属驱动程序可以与总线驱动程序通讯请求服务 (比如. 电源管理) • 应用程序可以列举设备, 总线, 和他们支持的接口
总线驱动程序提供的保护! • 恢复时, 总线驱动程序可以防止访问已经移除的设备: • Installable ISR • Bus agnostic driver’s power callback • 恢复时, 从属驱动程序可以调用总线驱动程序查看硬件是否依然存在. • IOCTL_BUS_IS_CHILD_REMOVED
新的总线命名空间 以前 • 加载多个实例, 如大于15个端口的COM • 任何应用程序可以发送电源管理 IOCTL,这将造成驱动程序的电源状态混乱? 现在 • 命名空间可以创建无限制的实例 • 命名空间可以根据总线调用和非总线调用提供保护
<BusEnum> \ BCR1: Com1: DSK1: <PCI Bus> BuiltIn_2 BuiltIn_1 BuiltIn_4 BuiltIn_3 GPS1: <Display> (GWES) WAV1: UFN1: DSK2: <TI1250> <App loaded> PCI_0_0_0 PCI_0_1_0 PCI_0_2_0 PCI_0_3_0 PCI_0_4_0 DSK4: NDS1: DSK3: TI1250_0_0 TI1250_1_0 USBFN_0_0 Driver Hierarchy Apps call Load/unload
可以借鉴的Quality 例程 可以参考CE 5.0中的以下Production Quality Drivers (PQD) : • PCCard • PCIBus • USBFn • SDBus • BusEnum (replaces RegEnum) • (new in Mobile 5.0) RootBus driver
新的总线命名空间 • 总线驱动程序通过注册表通知设备管理器驱动之间的从属关系 • 总线驱动程序经由ActivateDeviceEx()提供“BusName”, “BusParent” • 驱动程序在设备标示中提供(可选) “BusPrefix” • DeviceManager 通过新的API形成层次结构 • 总线驱动程序使用总线名称为从属驱动程序提供服务
新旧名称 • DM支持使用不同的命名空间调用CreateFile() • 旧的命名空间 (e.g., “COM1:”) 以前CE中的使用方法 • “$bus” 命名空间(e.g., “$bus\PCIBUS_0_1_0”) • 用于系统访问; driver support required to create handles with these names • $bus 也可以用于总线驱动程序提供的服务
启用 $bus 命名空间 • 在驱动程序的 IClass注册表项中公布 DMCLASS_PROTECTEDBUSNAMESPACE GUID • 使用CreateFile(“<$bus name>”)来打开Open() • 设置 dwAccess 参数中的DEVACCESS_BUSNAMESPACE 位 • Open是系统访问 • 驱动程序根据该位打开了哪些句柄来决定接受/拒绝其它操作 • $bus 名称可用来与驱动程序的父总线驱动程序进行通讯,以获得诸如加载、卸载和电源管理之类的服务。
检查总线访问标志 DWORD PCI_Open (DWORD dwContext, DWORD dwAccessMode, DWORD dwShareMode) { OPEN_CONTEXT *pContext = (OPEN_CONTEXT*) LocalAlloc(LPTR, sizeof(OPEN_CONTEXT)); if (pContext == NULL) return 0; if (dwAccessMode & DEVACCESS_BUSNAMESPACE) { // This is a bus access pContext->fPriviledgedAccess = TRUE; } else { // This is a regular access pContext->fPriviledgedAccess = FALSE; } ... // Initialize the rest of the structure return (DWORD) pContext; }
约束访问 BOOL PCI_IOControl(HANDLE pOpenHead, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) { BOOL fRet = FALSE; if (pContext->fPriviledgedAccess == TRUE) { // This is a bus access, so allow // system operations. ... } else { // This is a regular access. Fail the call // if it is a system operation. ... } return fRet; }
注册表 • 在IClass注册表项中公布DMCLASS_PROTECTEDBUSNAMESPACE GUID ({B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}) • 在注册表项后增加 “=%b” • 可以指定驱动程序的“BusIoctl”键值来启用post-init IOCTL ( IOCTL_BUS_POSTINIT)
注册表示例 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn] "Dll"="BusEnum.dll" "BusName"="BuiltIn" "Flags"=dword:8 "BusIoctl"=dword:2a0048 "InterfaceType"=dword:0 "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"
总线驱动程序怎样使用注册表? WCHAR szBusName[ ] = L”BuiltIn_3”; HANDLE hParent = GetDeviceHandleFromContext(pszActiveReg); REGINI rgRegIni[2] = { { L”BusParent”, REG_DWORD, hParent, sizeof(hParent) }, { L”BusName”, REG_SZ, szBusName, sizeof(szBusName) } }; HANDLE hChildDevice = ActivateDeviceEx(szChildRegPath, 2, rgRegIni, NULL);
I/O 资源管理器 • 支持 “dense” 资源和 “sparse” 资源 • Dense资源一般标为可共享资源 • Dense资源的典型代表为IRQs, 在一些平台中为可共享的 • Dense资源的最大数量可以通过注册表配置(在4.2中为 64) • 使用ResourceRequestEx() 可以得到共享资源的排他访问 • 在程序中可以使用ResourceCreateList和 ResourceDestroyList创建和删除资源列表 • IORM APIs
与IORM交互 if (!ResourceRequest(RESMGR_IOSPACE, pInfo->IoBase.Reg[Io], pInfo->IoLen.Reg[Io])) { goto PCIRequestResources_Fail; } IrqFlag = 0; if ((pInfo->DevFlags & DEVFLAGS_IRQ_EXCLUSIVE) != 0) { IrqFlag = RREXF_REQUEST_EXCLUSIVE; } if (!ResourceRequestEx(RESMGR_IRQ, Irq, 1, IrqFlag)) { goto PCIRequestResources_Fail; }
总线驱动程序 IOCTLs 应用程序调用 • 加载/卸载 子驱动程序调用 • Power Operations • Device Removable Media Management • Device Configuration Space Access • Device Bus Address Translation
加载/卸载操作 • IOCTL_BUS_DEACTIVATE_CHILD – 卸载由Bus Name指定的从属驱动程序 • IOCTL_BUS_ACTIVATE_CHILD – 加载由Name指定的从属驱动程序 • IOCTL_BUS_NAME_PREFIX – 访问Bus Name使用的前缀(prefix)
现在如何使用CreateFile • CreateFile(“COM7:”) 返回对应设备的“传统的” 文件句柄 • CreateFile(“\$device\COM7”) 返回“传统的” 文件句柄。可用于传统的命名规则不能胜任时的设备访问 • CreateFile(“\$bus\ PCMCIA_0_0_0”) 返回 PCMCIA总线0,设备0,功能0的“系统” 文件句柄
App. 卸载驱动 #include <ceddk.h> ... LPWSTR pszParentBusName = L”$bus\\BuiltIn_3”; HANDLE hBusDriver = CreateFile(pszParentBusName, 0, 0, NULL, OPEN_EXISTING, 0, NULL); if (hBusDriver != INVALID_HANDLE_VALUE) { // Fail! } WCHAR szBusName[] = L”$bus\\PCI_0_2_0”; BOOL fSuccess = DeviceIoControl(hBusDriver, IOCTL_BUS_DEACTIVATE_CHILD, (PVOID) szBusName, sizeof(szBusName), NULL, 0, NULL, NULL);
电源管理 • IOCTL_BUS_SET_POWER_STATE – 改变指定从属驱动程序(By Bus Name)总线电源的级别. 从属驱动程序向它们的总线驱动程序请求此服务 • IOCTL_BUS_GET_POWER_STATE –获得指定从属驱动程序总线电源的级别
可移动媒体的管理 • CE’s “PnP” 结构的一部分 • IOCTL_BUS_IS_CHILD_REMOVED – 从属驱动程序可以用此来检测媒体是否移除. 也可以在从属驱动电源管理的回调中调用
访问设备配置空间 • IOCTL_BUS_GET_CONFIGURE_DATA – 读取指定(By Bus Name)子驱动程序的配置空间 • IOCTL_BUS_SET_CONFIGURE_DATA – 写入指定(By Bus Name)子驱动程序的配置空间 • 不同总线的配置空间名称不同 • 对于 PCI, 支持PCI_WHICHSPACE_CONFIG • 对于PCCARD, 对于32Bit卡支持PCCARD_PCI_CONFIGURATION_SPACE
设备总线地址转换 • IOCTL_BUS_TRANSLATE_SYSTEM_ADDRESS – 转换实际系统地址到逻辑总线地址 • 用于 DMA • 替换 HalTranslateSystemAddress • IOCTL_BUS_TRANSLATE_BUS_ADDRESS – 转换总线物理地址到系统实际地址 • 替换 HalTranslateBusAddress
辅助 APIs 为何要用辅助 API? • 加快驱动程序开发速度 • 访问上层驱动程序 • 使用简单的过程调用 IOCTL
辅助 APIs • CreateBusAccessHandle • Pass returned bus access handle to other Helper APIs • GetDeviceConfigurationData • SetDevicePowerState • TranslateBusAddr • BusIoControl • Pass arbitrary IOCTL to bus parent • CloseBusAccessHandle
Calling Bus Parent In XXX_Init(), create the bus handle and get a virtual address to the FIFO Memory Window. pContext->hBusAccess = CreateBusAccessHandle(pszActiveKey); HANDLE hkDevice = OpenDeviceKey(pszActiveKey); DDKWINDOWINFO wini = { sizeof(wini) }; DDKReg_GetWindowInfo(hkDevice, &wini); PHYSICAL_ADDRESS PortAddress = { 0 }; PortAddress.LowPart = wini.memWindows[WINDOW_FIFO_NUM].dwBase; BusTransBusAddrToVirtual(pContext->hBusAccess, (INTERFACE_TYPE) wini.dwInterfaceType, wini.dwBusNumber, PortAddress, wini.memWindows[WINDOW_FIFO_NUM].dwLen, &dwAddrSpace, &pContext->pFifoAddr); ...
Calling Bus Parent In XXX_IOControl(IOCTL_POWER_SET), set the power state for the device. CEDEVICE_POWER_STATE dx = *(CEDEVICE_POWER_STATE*)pOutBuffer; SetDevicePowerState(pContext->hBusAccess, dx, NULL); In XXX_Deinit(), free to the FIFO Memory Window and close the bus access handle. if (pContext->pbFifoAddr) { MmUnmapIoSpace(pContext->pbFifoAddr, 0); } CloseBusAccessHandle(pContext->hBusAccess);
Call To Action • 成为驱动开发者计划的成员 • http://msdn.microsoft.com/embedded/usewinemb/ce/drivers/driverdev/default.aspx • 发布自己的驱动程序 • http://msdn.microsoft.com/embedded/usewinemb/ce/drivers/supdrivers/default.aspx
Tools & Resources Build Develop Websites msdn.microsoft.com/embedded msdn.microsoft.com/mobility Newsgroups microsoft.public.pocketpc.developer smartphone.developer dotnet.framework.compactframework microsoft.public.windowsxp.embedded windowsce.platbuilder windowsce.embedded.vc Blogs blogs.msdn.com/mikehall blogs.msdn.com/windowsmobilevsdteamnetcfteam Tools Windows CE 5.0 Eval KitWindows XP Embedded Eval Kit Windows Mobile 5.0 Eval Kit
大会注意事项 请在课程结束后填写课程培训反馈表,参加抽奖。 请填写资料袋内的蓝色大会满意度反馈表,到大会接待台领取 《Windows Mobile手机应用开发》工具书。 您还可以: 参加Windows Mobile动手实验室; 参观微软及合作伙伴展区; 体验基于 Windows Mobile平台开发的最新硬件产品及解决方案。