XiangXiangRen
总版主
总版主
  • 注册日期2003-02-22
  • 最后登录2015-09-01
  • 粉丝13
  • 关注0
  • 积分1042分
  • 威望472点
  • 贡献值1点
  • 好评度145点
  • 原创分13分
  • 专家分1分
阅读:1608回复:6

DriverNetworks第三课

楼主#
更多 发布于:2003-03-01 13:53
第三课 访问IO端口

中间层驱动和协议驱动可能对IO端口不感兴趣,但是真正开发驱动访问io端口可是真正的硬工夫。用DriverNetworks开发NDIS微端口驱动时访问io端口或者内存映射io端口,基本上有三个步

骤:

1.向注册io端口或者内存地址范围。

2.访问这些端口。

3.注销你注册的东西。

首先是注册,你必须在你的Adapter类中包括KNdisIoRange类或者KNdisMemory的数据成员.例子如下:

class MyAdapter : public KNdisMiniAdapter {
...
KNdisIoRange m_Ports;
KNdisMemoryRange m_Memory;
...
}

然后你在adapter的Initialize函数中访问一个KNdisXxxResource类,从中得到你的微端口驱动所拥有的资源。(当然包括io口)。

最后你就可以初始化你的KNdisIoRange以及KNdisMemoryRange成员了。下面有例子:

NDIS_STATUS MyAdapter::Initialize(KNdisMedium& Medium,IN KNdisConfig& Config) { //注意这行代码是向导生成的
...
//现在来设法获取资源
KNdisPnpResourceRequest request(Config);
KNdisResource<CmResourceTypePort> Port(request);

//判断获取结果是否有问题
if(!Port.IsValid())
KNDIS_RETURN_ERROR(NDIS_STATUS_NOT_ACCEPTED;

//注册io端口范围
if(!m_Port.IsValid())
KNDIS_RETURN_ERROR(NDIS_STATUS_RESOURCES);
...
}

就是这样,注册结束。下面看怎么访问。

DriverNetworks提供了四种方法来访问你的m_Ports

1.使用in()和out()成员函数, 它们使用一个ULONG型的偏移量作为参数访问io端口,这个偏移量从io范围的开始地址开始计算。看下面的例子:

UCHAR reg = m_Ports.inb(4);
if(reg|1)
m_Ports.outb(4,reg|1);
else
m_Ports.outb(4,0);

2.使用KNdisIoRegister和KNdisMemoryRegister提供了一种访问这些io范围中一些特殊的寄存器的方法。KNdisIoRegister或者KNdisMemoryRegister的对象可以在对KNdisIoRange或

者KNdisMemoryRange对象做[]操作的时候获得。而且KNdisIoRegister和KNdisMemoryRegister对象还可以当作一些基本类型使用,比如它们可以当作ULONG,USHORT,UCHAR等等来访问。看例子



KNdisIoRegister reg = m_Ports[4];
if(UCHAR(reg)|1)
reg |= UCHAR(reg)|1;
else
reg = 0;


3.使用模板!(其实我个人对c++不是太感冒,怎么都感觉DriverNetworks有点太照顾c++人了)DriverNetworks提供两个模板KNdisIoRegisterSafe和KNdisMemoryRegisterSafe作为刚刚2中提

到的两个类的“safe”版本。怎么说呢,非“safe”版本就是说在编译的时候不会检查读取数据的宽度和实际硬件寄存器数据宽度的不同。比方说你试图往一个只有8位的寄存器中写一

个ULONG的数据,象这样 m_Ports.outd(4,1),这编译没问题,但是可能网卡不会象你希望的那么工作。而“safe”版本则可以指定其数据宽度,你可以根据寄存器的实际宽度指定

成ULONG,USHORT,UCHAR这样的类型。如果尝试读写不同的数据宽度的类型,你会得到一个编译错误。例子如下:

ULONG newval = 0;
KNdisIoRegisterSafe<UCHAR> reg = m_Ports[4];
if(UCHAR(reg)|1)
reg|=UCHAR(reg)|1;
else
reg = val; //这里你将得到编译错误!

4.最后一种访问io端口的方式是所谓的直接io访问。这是基于NdisImmediateXxx系列函数的。这提供了一种方法让你的驱动可以在硬件资源已经分配,io或者内存范围已经注册之间就访问实

际网卡硬件。这种情况下,系统会对每一次访问都要进行
硬件资源转换和映射,所以这种方法访问是很慢的。而且只能用在硬件初始化过程中。举个例子,一个驱动在开始必须读一个网卡上的EEPROM,来获得某种信息(比如版卡类型?),然后才

能开始资源分配请求,这种情况下不能不使用这个技术。一般这种方法在即插即用环境中是不推荐的。

DriverNetworks通过KNdisConfig类来支持这种技术。(刚好上一课介绍了这个东西)。这个类有一系列的in()/out()成员函数来访问io口。例子如下:

UCHAR reg = Config.inb(4);
if(reg | 1)
Config.outb(4,reg|1);
else
Config.outb(4.0);

最后是注册的io范围的注销,这很简单,一般在MyAdapter的Halt()函数中做。另一个选择是在Adapter的析构函数中做。只要这样:
m_Ports.Invalidate();
m_Memory.Invalidate();
就可以了。


最新喜欢:

atmanatman
XiangXiangRen
总版主
总版主
  • 注册日期2003-02-22
  • 最后登录2015-09-01
  • 粉丝13
  • 关注0
  • 积分1042分
  • 威望472点
  • 贡献值1点
  • 好评度145点
  • 原创分13分
  • 专家分1分
沙发#
发布于:2003-03-01 14:00
我非常的抱歉!太匆忙了,第二个例子的某一行掉了,很关键的一行,在“//注册io端口范围”一行的下边应该还有一行“m_Ports.Initialize();”装了ds的兄弟们可以帮我检查检查……
lzwf4
驱动小牛
驱动小牛
  • 注册日期2002-10-10
  • 最后登录2006-06-09
  • 粉丝0
  • 关注0
  • 积分22分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-03-01 14:46
太好了!!!!!加油!!!!
lzwf4
驱动小牛
驱动小牛
  • 注册日期2002-10-10
  • 最后登录2006-06-09
  • 粉丝0
  • 关注0
  • 积分22分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
地板#
发布于:2003-03-02 15:16
XiangXiangRen
继续下啊啊!我们这些E文不好的人天天在期待你啊!!!
lzwf4
驱动小牛
驱动小牛
  • 注册日期2002-10-10
  • 最后登录2006-06-09
  • 粉丝0
  • 关注0
  • 积分22分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2003-03-02 15:20
XiangXiangRen,我们能交一朋友吗??我现在在分析W2K的网络内核,但我的E文不太好,有时要看一些DDK文档很难看的,你帮我吗?一些合作,我想对大家都有好处的!!!
我的QQ:39122639
XiangXiangRen
总版主
总版主
  • 注册日期2003-02-22
  • 最后登录2015-09-01
  • 粉丝13
  • 关注0
  • 积分1042分
  • 威望472点
  • 贡献值1点
  • 好评度145点
  • 原创分13分
  • 专家分1分
5楼#
发布于:2003-03-03 09:15
lzwf4:
   我很愿意帮你,我的qq号码是16191935。但是我工作也很忙,我现在每天晚上10点下班,写程序超过13个小时…… 无聊的时候才来这里。 昨天周日,难得休息啊,所以没继续翻,不过你放心好了,我会做到让大家满意为止的。你在DDK上有什么东西看不懂,把主题发给我,我或许帮你翻译一些关键章节。
lzwf4
驱动小牛
驱动小牛
  • 注册日期2002-10-10
  • 最后登录2006-06-09
  • 粉丝0
  • 关注0
  • 积分22分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2003-03-03 19:18
XiangXiangRen:
先谢谢你了,到时真的还要请你帮忙啊!!!
游客

返回顶部