当前位置: 首页 > news >正文

网站开发总结经验和教训国家工程建设质量奖网站

网站开发总结经验和教训,国家工程建设质量奖网站,红桥集团网站建设,潍坊 优化型网站建设我想即使读者看过微软的关于驱动开发的培训教材和CE帮助文档中的驱动部分#xff0c;头脑中仍然一片茫然。要想真正了解驱动程序必须结合一些驱动程序源码#xff0c;在此我以串口驱动程序#xff08;COM16550#xff09;中初始化过程为线索简单讲一讲驱动开发的基础知识。…我想即使读者看过微软的关于驱动开发的培训教材和CE帮助文档中的驱动部分头脑中仍然一片茫然。要想真正了解驱动程序必须结合一些驱动程序源码在此我以串口驱动程序COM16550中初始化过程为线索简单讲一讲驱动开发的基础知识。   Windows CE下的串口驱动程序能够处理所有I/O行为类似串口的设备包括基于16450、16550 UART通用异步收发芯片的设备和一些采用DMA的设备常见的有9针串口、红外I/O口、Modem等。在%_WINCEROOT%\Public\Common\OAK\Drivers\Serial目录下COM_MDD2子目录包含新的串口驱动MDD层函数代码。COM16550子目录包含串口驱动PDD层代码。SER16550子目录包含的一系列函数专用于控制与16550兼容的UART这样PDD层的主要工作就是调用SER16550中的函数。还有一个ISR16550子目录包含的是串口驱动程序专用的可安装ISR中断服务例程而很多硬件设备驱动程序采用CE默认的可安装ISR giisr.dll。一般串口设备相应的注册表设置例子及意义如下 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial_1] 键意义SysIntrdword:13串口1的中断ID为十进制13IoBasedword:02F8串口1的IO空间首地址为十六进制2F8IoLendword:8串口1的IO空间长度为8个字节DeviceArrayIndexdword:0串口1的索引是1的由来Orderdword:0串口1驱动的加载顺序DeviceTypedword:0串口1的设备类型DevConfighex: 10,00 ....串口1在与Modem设备通讯时的配置如波特率、奇偶校检等FriendlyNameCOM1:串口1在拨号程序中显示的名字TspUnimodem.dll串口1 被用于与Modem设备通讯的时候要加载的TSPTAPI Service providerDLLPrefixCOM串口1的流接口的前缀Dllcom16550.Dll串口1的驱动程序DLL SysIntr由CE在文件Nkintr.h中预定义用于唯一标识中断设备。OEM可以在文件Oalintr.h中定义自己的SysIntr。常见的预定义SysIntr有SYSINTR_NOP中断只由ISR处理IST不再处理SYSINTR_RESCHED重新调度线程SYSINTR_DEVICES由CE预定义的设备中断ID的基值SYSINTR_PROFILE、SYSINTR_TIMING、SYSINTR_FIRMWARE等都是基于SYSINTR_DEVICES定义的。IoBase是串口1的IO地址空间的首地址IoLen是IO空间的大小。IO地址空间只存在于x86平台如果在其它平台硬件寄存器必须映射到物理地址空间那子键的名称为MemBase和MemLen。在x86平台更多硬件的寄存器由于IO空间的局限也映射到物理地址空间。DeviceArrayIndex是设备的索引用于区分同类型的设备。Prefix是流驱动程序的前缀当应用程序调用CreateFile函数传递COM1:参数时文件系统负责与串口驱动程序通信串口驱动程序是在CE启动时由device.exe加载的。下面从MDD层函数COM_Init开始探索串口驱动的初始化过程。COM_Init是在串口设备被检测后由设备管理器device.exe调用的主要的作用是初始化设备它的唯一参数Identifier是由device.exe传递的其类型是一个字符串指针字符串的内容是HLM\Drivers\Active\xxxx是一个十进制数device.exe会跟踪系统中每个驱动程序把加载的驱动程序记录在Active键下。COM_Init先分配一个HW_INDEP_INFO结构体这个结构体是独立于串口硬件的头信息MDD、PDD、SER16550都包含自己独特的结构体具体的结构体定义请参见串口驱动源码分配之后再初始化结构体中每个成员初始化结构体后调用 OpenDeviceKey((LPCTSTR)Identifier)打开HLM\Drivers\Active\xx\Key包含的注册表路径在这里路径一般为HLM\Drivers\BuiltIn\Serial即串口的驱动程序信息在注册表中所处的位置。COM_Init接着在HLM\Drivers\BuiltIn\Serial下查询DeviceArrayIndex、Priority256的值Priority256指定了驱动程序的优先级如果没有就用默认的优先级。接下来调用GetSerialObject(DeviceArrayIndex)这个函数由PDD层定义返回HWOBJ结构体这个结构体主要包含PDD层和SER16550定义的函数的指针。也就是说MDD通过调用这个函数才能调用底层实现的函数。接下来的大多数工作都是调用底层函数实现初始化。第一个调用的底层函数SerInit主要设置由用户设置的硬件配置例如线路控制、波特率。它调用Ser_GetRegistryData函数得到保存在注册表中的硬件信息Ser_GetRegistryData在内部调用系统提供的DDKReg_GetIsrInfoDDK和DDKReg_GetWindowInfo函数得到在HLM\Drivers\BuiltIn\Serial下保存的IRQ、SysIntr、IsrDll、IsrHandler、IoBase、IoLen。IRQ是逻辑中断号IsrDll表示当前驱动程序的可安装ISR所在的DLL名称IsrHandler 表示可安装ISR的函数名称。在这里顺便提一下可安装ISR读者在我以前发表的关于OAL的文章中可以了解到OEM在OEMInit函数中关联IRQ和SysIntr当硬件设备发生中断时ISR会禁止同级和低级中断然后根据IRQ返回关联的SysIntr内核根据ISR返回的SysIntr唤醒相应的ISTSysIntr与IST创建的Event关联IST处理中断之后调用InterruptDone解除中断禁止。在OEMInit中关联的缺点是一旦编译了CE内核后就无法添加这种关联了而一些硬件设备会随时插拔或者共享中断要关联这样的硬件设备解决方法就是可安装ISR可安装ISR专用于处理指定的硬件设备发出的中断所以如果硬件设备需要可安装ISR必须在注册表中添加IsrDll、IsrHandler。多数硬件设备采用CE默认的可安装ISR giisr.dll格式如下IsrDllgiisr.dll IsrHandlerISRHandler 如果一个硬件驱动程序需要可安装ISR而开发者又不想自己写一个那么可以利用giisr.dll来实现。除了在注册表中添加如上所示外还要在驱动程序中调用相关函数注册可安装ISR。伪代码如下g_IsrHandle LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq); GIISR_INFO Info; PHYSICAL_ADDRESS PortAddress {PhysAddr, 0}; TransBusAddrToStatic(BusType, dwBusNumber, PortAddress, dwAddrLen, dwIOSpace, (PVOID)PhysAddr) Info.SysIntr dwSysIntr; Info.CheckPort TRUE; Info.PortIsIO (dwIOSpace) ? TRUE : FALSE; Info.UseMaskReg TRUE; Info.PortAddr PhysAddr 0x0C; Info.PortSize sizeof(DWORD); Info.MaskAddr PhysAddr 0x10; KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, Info, sizeof(Info), NULL, 0, NULL); LoadIntChainHandler函数负责注册可安装ISR参数1为DLL名称参数2为ISR函数名称参数3为IRQ。TransBusAddrToStatic函数在后面讲。如果要利用giisr.dll作为可安装ISR必须先填充GIISR_INFO结构体CheckPortTRUE表示giisr要检测指定的寄存器来确定当前发出中断的是否是这个设备。PortIsIO表示寄存器地址属于哪个地址空间FALSE表示是内定空间TRUE表示IO空间。UseMaskRegTRUE表示设备有一个掩码寄存器专用于指定当前设备是否是中断源也就是发出中断而MaskAddr表示掩码寄存器的地址。如果对Info.Mask赋值那么PortAddr表示一个特殊的寄存器地址这个寄存器的值与Mask的值运算的结果如果为真则证明当前设备是中断源否则返回SYSINTR_CHAIN表示当前ISR没有处理中断内核将调用ISR链中下一个ISR如果UseMaskRegTRUE那么MaskReg寄存器的值与PortAddr指定的寄存器的值运算的结果如果为真则证明当前设备是中断源。函数SerInit接着调用函数Ser_InternalMapRegisterAddresses转换IO地址并且映射地址Ser_InternalMapRegisterAddresses在内部调用系统提供的HalTranslateBusAddress(Isa, 0, ioPhysicalBase, inIoSpace, ioPhysicalBase)函数将与总线相关的地址转换为系统地址参数1为总线类型参数2为总线号参数3为要转换的地址PHYSICAL_ADDRESS类型实际是LARGE_INTEGER型参数4指定寄存器地址属于IO地址空间还是物理地址空间参数5返回转换后的物理地址。观察HalTranslateBusAddress的源码得知如果是在x86平台这个函数除了把参数3赋给了参数5其余什么都没有做而非x86平台将inIoSpace的值置为0表示一定是物理地址。在调用HalTranslateBusAddress前要确定从注册表中得到的寄存器地址到底是属于哪个地址空间的例如ULONG inIoSpace 1; ///1表示是IO空间 PHYSICAL_ADDRESS ioPhysicalBase {iobase, 0}; ///相当于ioPhysicalBase.LowPart iobase 在地址转换后就要将转换后的地址映射到驱动程序一般IST和应用程序一样运行在用户模式能够访问的虚拟地址空间0x80000000以下和ISR能够访问的静态虚拟地址空间中0x80000000以上。例如如果地址属于物理地址空间 ioPortBase (PUCHAR)MmMapIoSpace(ioPhysicalBase, Size, FALSE); TransBusAddrToStatic(Isa, 0, ioPhysicalBase, Size, inIoSpace, ppStaticAddress); MmMapIoSpace函数负责将物理地址映射到驱动程序能够访问的虚拟地址空间中通过源码分析MmMapIoSpace在内部分别调用pVirtualAddress VirtualAlloc(0, SourceSize, MEM_RESERVE, PAGE_NOACCESS); VirtualCopy(pVirtualAddress, (PVOID)(SourcePhys 8), SourceSize, PAGE_PHYSICAL | PAGE_READWRITE |  (CacheEnable ? 0 : PAGE_NOCACHE)); VirtualAlloc分配一块和MemLen一样大小的虚拟地址空间因为参数1为0所以内核自动分配。一般MemLen小于2MB所以会在应用程序的地址空间中分配。VirtualCopy负责将硬件设备寄存器的物理地址与VirtualAlloc分配的虚拟地址做一个映射关系这样驱动程序访问PvirtualAddress实际上就是访问第一个寄存器。因为硬件设备寄存器的物理地址一定是在512MBCE支持RAM的最大值以上所以除了最后的参数要加PAGE_PHYSICAL外第二个参数物理地址也要右移8位或者除以256。映射硬件寄存器当然PAGE_NOCACHE是必须加的。TransBusAddrToStatic函数负责将物理地址映射到ISR能够访问的静态虚拟地址空间中当出现中断共享时ISR要负责访问硬件设备的某一个寄存器来判断中断源所以将寄存器的物理地址映射到静态虚拟地址空间中是必要的ISR只能访问静态的虚拟地址空间。所谓静态虚拟地址空间是指在OEMAddressTable中定义的虚拟地址空间当然是0x80000000以上。在x86平台一般这个表只定义RAM的物理地址与虚拟地址对应关系而硬件设备的寄存器地址并不在该表中定义所以如果要创建一块静态的虚拟地址空间供ISR访问必须在此之前调用CreateStaticMapping函数在0xC4000000到0xE0000000虚拟地址空间中分配。TransBusAddrToStatic函数在内部就是调用了CreateStaticMapping函数。注硬件设备的寄存器地址也可以在OEMAddressTable中定义。如果地址属于IO空间 ioPortBase (PUCHAR)ioPhysicalBase.LowPart; *ppStaticAddressioPortBase 这种情况只属于x86平台是IO空间就可以直接访问即使是用户模式。SerInit函数接着初始化SER_INFO结构体成员之后调用SL_Init函数这个函数在ser16550中定义负责初始化SER16550_INFO结构体在这个结构体中保存串口8个寄存器的地址。SerInit函数执行完毕后COM_Init函数创建接收缓冲区然后调用StartDispatchThread函数初始化中断并且创建IST。StartDispatchThread函数在内部调用InterruptInitialize函数关联SysIntr和Event然后调用InterruptDone函数告诉内核当前串口可以中断处理接着调用CreateThread函数创建IST线程。over吧再往下说就和串口硬件有关了看多了没注释的代码我也烦
http://www.zqtcl.cn/news/761199/

相关文章:

  • 一 网站建设管理基本情况设计类的网站
  • wordpress产品编辑如何优化wordpress
  • 网站后台更新缓存失败网站平台规划方案
  • 网站开发需求分析主要内容saas建站系统是怎么实现的
  • 做qq头像的网站有哪些wordpress怎么部署到虚拟linux服务器
  • 征求网站建设企业网站建设word
  • 市民服务中心网站建设小型公众号开发
  • 服装网站建设策划书论文基层建设刊物网站
  • 网站建设合同技术开发合同范本wordpress备份和还原
  • 物流信息平台网站建设一流本科专业建设点网站
  • 天猫网站建设的目标是什么装潢设计软件
  • 电商网站首页图片网站功能模块建设
  • 邮件服务器是不是网站服务器黄江网站建设公司
  • 科技部网站方案网页设计网站设计欣赏
  • 自贡建设机械网站网站策划与运营课程认知
  • 公司做网站该注意哪些廊坊seo
  • 网站开发目录高尔夫 wordpress
  • 三只松鼠网站建设不做网站做百家号
  • 石家庄网站关键词推广淘宝网站建设设计模板
  • 马鞍山什么房产网站做的好网速
  • 国外做兼职网站软件园二期做网站的公司
  • 淘客网站备案教程网页设计与制作教程十四五规划
  • 哪些网站可以做外部锚文本网页设计个人简历怎么做
  • 福州网站营销北京著名网站建设公司
  • 导购网站开发 源码wordpress 获取总页数
  • 网站名查找wordpress评论人
  • 网络推广最好的网站有哪些wordpress怎么用万网域名
  • 大连仟亿科技网站建设公司 概况网络信用贷款哪个好
  • 配置了iis打不开网站外贸建站哪个最便宜
  • 酒店网站建设描述免费建站网站有哪些