您的位置:逆风者 VC++ 正文
 添加时间:2007-09-01 原文发表:2007-08-31 人气:116 来源:vckbase.com

本文章共5354字,分4页,当前第3页,快速翻页:
 

  函数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实际上就是访问第一个寄存器。因为硬件设备寄存器的物理地址一定是在512MB(CE支持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;

*ppStaticAddress=ioPortBase

这种情况只属于x86平台,是IO空间就可以直接访问,即使是用户模式。
  SerInit函数接着初始化SER_INFO结构体成员,之后调用SL_Init函数,这个函数在ser16550中定义,负责初始化SER16550_INFO结构体,在这个结构体中保存串口8个寄存器的地址。SerInit函数执行完毕后COM_Init函数创建接收缓冲区,然后调用StartDispatchThread函数初始化中断并且创建IST。StartDispatchThread函数在内部调用InterruptInitialize函数关联SysIntr和Event,然后调用InterruptDone函数告诉内核当前串口可以中断处理,接着调用CreateThread函数创建IST线程。(over吧,再往下说就和串口硬件有关了,看多了没注释的代码我也烦!!)
 

本文章更多内容<<上一页 - 1 - 2 - 3 - 4 - 下一页>>
相关文章

编写、加载和存取插件程序(Plug-Ins)
通过串口收发短消息(下)
一个打印报表的简单的类
QQ界面的模拟实现(下)
USB有关的编程
杂谈:人与软件
通用权限管理模块的设计与实现
基于TCP的局域网多用户通信、文件传送程序详
通用图像类算法扩充库
ASP.NET 专栏:编写高性能 Web 应用程序的1
介绍一种数据库远程备份方案
QQ魔法表情实现原理
支持数据项查找功能的树控制(CTreeCtrl)类
把 C# 语言开发的控件内嵌在网页里面
使用免费界面换肤软件 USkin
一个关于#include的问题
如何用代码动态添加控件
C 程序的外部变量与函数
通过串口收发短消息(上)
更改屏幕显示数据的作弊程序

相关评论


本文章所属分类:首页 VC++

  热门关键字: