起来真是雷人,最近几天纠结与一个最基本的概念,就是NDIS与WinSock关系,想来想去都没有想明白,真实汗Ing,赶紧找了篇精美的文章来扫盲一下。

原文如下:

文章转自http://www.cnblogs.com/sankye/articles/1651280.html

1.WinCE的网络通信架构

WinCE的网络通信架构如图1所示,WinCE的网络通信架构中一个重要的角色是网络结构规范(NetworkDriver Interface Specification,NDIS),它支持多种网络媒体,以及提供包括TCP/IP等多种网络协议。

图1 WINCE通信网络的层

其中最上层的Wins0ck是提供给应用层的接口,一般开发网络应用都会用Winsock接口来开发。NDIS位于协议驱动层下面,而位于硬件驱动Miniport Driver之上。协议驱动层通过调用NDIS封装层的接口函数,实现与底层硬件驱动的交互。对于协议层来说,NDIS相当于一个Miniport Driver,而对于底层的硬件驱动来说,NDIS相当于上层的协议层,所以NDIS起到承上启下的作用,也起到对底层硬件接口的规范作用。

2.WinCE网络驱动架构和实现原理

在WinCE中,网卡驱动的实现原理如图2所示,在上层的协议驱动层看来,它调用NDIS接口函数访问网络设备,其具体实现过程(如图2虚线框),是通过调用底层的Miniport Driver接口函数来实现。在WinCE系统中NDIS接口函数库是Microsoft开发好的,所以开发winCE下的网卡驱动就是编写一个Miniport Driver,它向上导出接口函数与NDIS接口实现对接,向下直接管理网卡硬件。

图2 WINCE网络驱动原理

3.网络驱动的编程与实现

3.1网络驱动接口的实现流程

在WinCE中,应用层通过调用NDIS接口(图3实线框)实现与底层硬件的交互,而NDIS接口是微软已经开发好的,被定义成一个数据结构体的形式。开发网卡驱动就是写一个Miniport Driver,导出相应的Miniport接口函数(图3的虚线框),这些接口函数会在系统注册一个Miniport Driver的时候与NDIS封装层的接口函数对接,这样内核协议层通过调用NDIS的接口就可以访问底层硬件。

图3 网络驱动接口实现流程

微软定义的与Miniport Driver相关的NDIS标准接口总共有18个,针对不同的网络设备其接口的实现也不尽相同,本流程图中罗列出的是CS89OO网卡驱动所实现的接口函数,具体的接口实现可参照Platform Builder的帮助文档。

3.2网络驱动接口的具体实现

实际网络驱动的编写,就是理解wincE下网络驱动程序的构架,然后针对实际的硬件编写代码,实现相应的中间层Miniport Driver接口函数。下面结合利用WinCE5.0内核在脉冲发生器嵌入式主板上移植编写嵌入式CS8900网卡驱动程序的实例,介绍网卡驱动程序Miniport Driver接口的具体实现(由于本驱动的硬件设备是CS8900,所以在函数接口的取名上一律用CS8900代替Miniport Driver)。

3.2.1网络驱动程序的入口函数

DriverEntry,该函数中首先调用NdisMinitializeWrapper函数来通知NDIS Library要注册一个Miniport。然后初始化MINIPORT结构体,所有的Miniport的相关接口函数都会赋到 MINIPORT 结构中, 最后调用NdisMRegisterMiniport来注册Miniport。通过此函数,实现了Miniport Driver接口与NDIS接口的对接。

3.2.2网络设备的初始化接口

Miniportlnitialize, 该函数为调用函数CS8900RegisterAdapter来完成网络设备的初始化,而CS8900RegisterAdapter 又会调用CS8900Initialize,CS8900Initialize函数会相继调用:findCS,查找网络设备;resetCS,重启网络控制器,并设置工作模式为16bit的I/0模式;InitIrq,开启网络控制器的中断;initCS,设置临时的物理地址,为网络控制器设置与嵌入式芯片之间中断的硬件连接,以及总线读写的时序。

3.2.3网络数据包的发送

WinCE网络数据发送的流程:当上层协议驱动要发数据时,调用NdisSend请求NDIS发送数据包,NDIS将会调用紧接其下的中间层驱动的CS8900Send,该函数首先调用NdisQueryPacket,得到需要发送包的数据信息,并拷贝到一个缓冲区暂存,这样做的目的是保证包数据不被丢失。然后调用CS8900RequestTransmit,向网络控制器发送传送数据的请求,最后调用函数CS8900CopyTxFrame完成数据包的发生。

3.2.4网络数据的接收和中断

网络设备的接收数据包时通过中断实现,当网络接口接收到新数据包时,发送完成或者报错误信息及连接状态都会出发中断,通常中断处理程序通过检测硬件状态寄存器判断是哪种情况。

当网络设备有数据到来的时候,将触发中断,相应的中断处理程序接管中断后,将调用Miniport Driver所注册的中断处理例程CS8900Isr,通过读取CS8900的中断寄存器判断是否是接收到数据中断,如果是就调用数据接收函数CS8900ReceiveEvent。Miniport Driver通常在这里把网卡上的数据拷贝到Miniport Driver缓冲区队列中去,出于效率的考虑,Miniport Driver这时可能不会立即通知上层处理新的数据,因为很可能,马上还有随后的新的数据到来,当接收到的包的数量达到一定程度的时候,驱动程序的接收线程会调用函数NdisMIndicateReceivePacket指示新的NDIS新数据的到来。

3.2.5Miniport Driver其他接口

CS8900Reset,复位硬件网卡;

CS8900Querylnformation,网卡信息查询函数;

CS8900Setlnformation,设置网卡信息函数。

3.2.6 驱动下实现的CS8900A的几个函数

1.读写ReadPacketPage和WritePacketPage。这两个函数通常并不被EthDbg驱动程序的使用者直接调用。而是这个两个函数向其他EthDbg驱动程序接口函数提供了最基本的读写CS8900A的PacketPage内部的控制与状态寄存器和收发缓冲区的功能。

在源文件%_WINCEROOT%/PLATFORM/COMMON/SRC/COMMON/ETHDRV/CS8900A/cs8900a.c中定义了一个静态全局指针变量g_pCS8900:

STATIC CS8900A_REGS *g_pCS8900;

其类型CS8900A_ERGSS是在同一源文件中定义的结构体:

Typedef struct{

Unsigned _int16 DATA0;

Unsigned _int16 DATA1;

Unsigned _int16 TXCMD;

Unsigned _int16 TXLENGTH;

Unsigned _int16 ISQ;

Unsigned _int16 PAGEIX;

Unsigned _int16 PAGE0;

Unsigned _int16 PAGE1;

}CS8900A_REGS;

显然,静态全局指针变量g_Pcs8900所指向的CS8900A_REGSS结构体数据专门用于映射CS8900A的8个I/O端口,g_Pcs8900指针的实际取值就应该是这8个I/O端口的基地址。ReadPacketPage和WritePacketPage两个函数的实现对CS8900A的PacketPage读写就是通过这个g_Pcs8900指针进行的。

2.硬件初始化函数CS8900AInit。CS8900AInit函数的功能是执行对CS8900A以太网控制器芯片的硬件初始化,并且设置其工作模式至一个确定的状态。CS8900AInit函数在%_WINCEROOT%/PLATFORM/DEVICEEMULATOR/SRC/DRIVERS/ETHERNET/cs8900a.c源文件中实现,其函数定义:

BOOL CS8900AInit(UINT *pAddress, UINT32 offset, UNIT16 MAC[3]);

*pAddress指针参数记录以太网控制器的I/O端口基地址。Offset成员则是偏移地址,在当前的CS8900AInit函数中它没有被使用。Mac数组记录以太网端口的48位MAC地址。

如果把对全局变量g_pCS8900赋值看作是CS8900AInit函数执行的第一步,则它的第二个执行步骤就是检测CS8900A以太网控制器芯片是否在目标硬件平台上真实存在:

If (ReadPacketPage(EISA_NUMBER)!=CS8900A_EISA_NUMBER)

{

OALMSGS(OAL_ERROR,(L”ERROR:CS8900AInit:Failed detect chip/r/n”));

Goto Exit;

}

检测CS8900A芯片是否存在的依据是读取PacketPage中便宜地址为0的产品ID寄存器,这是个只读的寄存器。如果读取EISA_NUMBER寄存器返回的16为数值是0X630E,则CS8900A芯片存在,否则不存在,CS8900AInit函数中止执行,并且向它的调用者返回FALSE表示执行失败。

CS8900AInit函数执行的第三个步骤就是通过软件操作出发CS8900A芯片复位:

WritePacketPage(SELT_CTL,SELF_CTL_RESET);

接下来,CS8900AInt函数接下来执行两个步骤:

1)等待CS8900A芯片软件复位后完成芯片初始化;

2)等待CS8900A芯片外置的用于存放芯片初始化配置信息的EEPROM存储器可被访问;

接下来CS8900AInit函数要为受CS8900A芯片控制的以太网端口设置MAC地址,方法是写INDIVIDUAL_ADDRESS寄存器:

WritePacketPage(INDIVIDUAL_ADDRESS + 0,mac[0]);

WritePacketPage(INDIVIDUAL_ADDRESS + 0,mac[1]);

WritePacketPage(INDIVIDUAL_ADDRESS + 0,mac[2]);

CS8900AInit剩下的代码就是配置CS8900A以太网控制器的收发数据帧的模式,分为以下四个步骤:

1)配置允许CS8900A以太网控制器芯片接收的以太网数据帧类型:

WritePacketPage(RX_CTL,RX_CTL_RX_OK|RX_CTL_INDIVIDUAL|RX_CTL_BRODCAST);

2)配置CS8900A以太网控制器芯片以中断方式接收数据帧:

WritePacketPage(RX_CFG,RX_CFG_RX_OK_IE);

3)配置CS8900A以太网控制器芯片选择使用第0号中断引脚;

WritePacketPage(INTERRUPT_NUMBER,0);

4)配置CS8900A以太网控制器芯片使之允许接收发送数据帧:

WritePacketPage(LINE_CTL,LINE_CTL_RX_OK|LINE_CTL_TX_ON);

3.发送以太网数据帧。CS8900ASendFrame函数的功能是向以太网发出一个数据帧。其函数原型:

UINT16 CS8900ASendFrame(UINT8 *pData, UINT32 length);

pData参数是指向待发送数据在主机中存放位置的地址指针,length参数记录是以字节为单位的待发送数据的长度。尽管函数的返回值类型定义为UINT16,但是它实际返回的是知识函数执行是否成功的BOOL值。

CS8900ASendFrame函数按照以下步骤完成数据的发送任务:

1)写发送命令和数据长度:

OUTPORT16(&g_pCS8900->TXCMD,TX_CMD_START_ALL);

OUTPORT16(&g_pCS8900->TXLENGTH,length);

这里的宏定义TX_CMD_START_ALL的实际数值(3<<6),它把发送命令端口TxCMD的第6位和第7位(TTxStart)置1,其作用是限定只有当整个数据帧都被写入CS8900A时才开始向外部网络发送数据。

2)检测CS8900A芯片已准备好接收来自主机的待发送数据:

Count = RETRY_COUNT;

While(count-->0){

If((ReadPacketPage(BUS_ST) & BUS_ST_TX_RDY)!=0) break;

}

If (count ==0) goto cleanup;

总线状态寄存器BusST(PacketPage内偏移地址为0138H)的第8位(Rdy4TxNOW)用于CS8900A芯片向主机通知已准备好接收数据,该位置1表示CS8900A已准备好接收来自主机的待发送数据。以上代码采用的是轮询而非中断的方式查询CS8900A芯片是否准备就绪,另一个更好的办法是,将缓冲配置寄存器BufCFG的第8位(Rdy4TxiE)置1,当CS8900A芯片准备好接收待发送数据时将向主机发出中断信号。

3)将待发送的数据依次写入CS8900A的数据端口:

Length = (length + 1)>>1;

While (length-- >0) {

OUTPORT16(&G_Pcs8900->DATA0, *(UINT16*)pData);

pData += sizeof(UINT16);

}

4.接收以太网数据帧CS8900AGetFrame函数。数据帧接收必定要涉及中断,还很有可能要使用DMA操作将接收到的数据从CS8900A芯片搬移到主机中。网络数据如果通过了CS8900A芯片的地址过滤器的筛选(单播地址或广播地址的数据帧),则CS8900A开始接收数据。如果一个数据帧被CS8900A全部接收完毕,具有有效的以太网数据帧长度并且CRC校验无错误,则CS8900A向主机触发RxOK中断,则主机通过CS8900A的数据端口将数据帧读出。

CS8900AGetFrame函数的原型定义如下:

UINT16 CS8900AGetFrame(UINT8 *pData, UINT16 *pLength);

pData参数是主机用来存放接收到的数据帧的内缓冲区起始地址,pLength参数所指向的内存单元记录接收缓冲区的以字节为单位的长度。CS8900AGetFrame函数的返回值是以字节为单位的实际接收到的数据的长度。

CS8900AGetFrame函数首先读CS8900A的ISQ端口,并且判断是否有RxOK中断存在:

Isq = INPORT16(&g_Pcs8900->ISQ);

If ((isq & ISQ_ID_MASK) == RX_EVENT_ID && (isq & RX_EVENT_RX_OK)!=0{

……

}

按照CS8900A的中断机制运行原理,当有中断事件发生时,除反映在事件寄存器的对应位外,还要把该事件寄存器关联到ISQ端口,然后触发中断引脚。此时,ISQ端口的最低6位记录所关联的寄存器的内部偏移地址,其余为是关联寄存器的数据内容。CS8900A芯片共有5个寄存器可以关联到它的ISQ端口,除3个时间寄存器(接收事件寄存器RxEvent、发送事件寄存器TxEvent和缓冲区事件寄存器BufEvent)外,另外两个是接收帧丢失计数器RxMISS和发送冲突计数器TxCOL。所以CS8900AGetFrame函数检测到RxOK中断必须满足两个条件:接收事件寄存器RxEvent(PacketPage内偏移地址为0124H)被关联到ISQ端口,并且其中的RxOK位(第8位)被置1.

如果这两个条件均满足,则主机可以从CS8900A的数据端口读取数据了。读取数据的操作可以按以下的顺序进行:首先是本次数据接收的状态和以字节为单位的数据总长度:

//Get RxStatus and length

Status = INPORT16(&G_Pcs8900->DATA0);

length = INPORT16(&G_Pcs8900->DATA0);

然后是由length指定字节数总长度的帧数据。

如果主机所提供的接收数据缓冲区不够用,则终止数据接收操作并且指令CS8900A丢弃接收到的数据:将接收配置寄存器RxCFG的第6位(Skip_1)置位。这会将当前存在于CS8900A芯片的接收数据缓冲区内的数据帧全部丢弃:

If (length> *pLength) {

// if packet doesn’t fit in buffer, skip it

Data = ReadPacketPage(RX_CFG);

WritePacketPage(RX_CFG, data |RX_CFG_SKIP_1);

Length = 0;

} else{

}

5.启用与禁用CS8900A的中断功能的函数CS8900AEnableInts和CS8900ADisableInts。在CS8900A中,总线控制器BusCTL(PacketPage内偏移地址为0116H)的第15位(EnableIRQ)是否被置位即表示CS8900A是否会根据相应的事件产生中断。

6.CS8900A的配置地址过滤机制的函数。CS8900ACurrentPacketFilter和CS8900AMulticastList。

4 网络驱动的编译与加载

在WinCE下,所有的驱动程序都以用户态的DLL文件形式存在。当编写完驱动的模块化接口之后,我们就要将这个模块编译成*.DLL的动态库,然后在编译系统的时候将该DLL动态库加载到系统内核里去,这样操作系统就可以在运行时动态的加载需要的应用程序。

下面以移植CS89O0网卡驱动为实例,介绍如何将网络设备驱动模块加载到WinCE 的内核,编译器为Platform-Builder5.O(简称PB5.O)。其编译、加载过程主要分为六步:

(1)在硬件平台BSP的DRIVERS目录下创建新目录CS89OO。

(2)修改DRIVERS下的DIRS文件,DIR下定义了编译器需要编译的内容,所以需要在DIRS文件中将CS8900目录添加上。

(3)将编写好网络驱动源程序代码拷贝到CS89OO目录下。

(4)编写网络设备驱动的sources文件,告诉编译器和连接器如何编译及连接本驱动程序。这样的sources文件在每个WinCE的驱动下面都有一个,是为了给PB编译驱动的时候提供编译“向导”的。其关键内容为:TARGETTYPE定义编译该驱动成为哪种形式,有DLL和Lib两种形式;TARGETLIBS定义编译该程序的时候需要连接的其他库;SOURCES确定需要编译的文件。本驱动被编译成的形式为DLL,链接了ndis,ntcompat,coredll,ceddk 4个静态库。

(5)编写CS8900的注册表文件,可参考WinCE自带的驱动源码ne2000网卡驱动的注册表文件编写CS8900的注册表文件。注册表定义了网卡的基本参数信息提供给操作系统,其中:Parms项提供网卡驱动在系统中的逻辑中断号,读写基地址,总线类型;TcpIp项提供了网卡IP

地址信息等,如果要修改IP地址就在本注册表项中修改。特别注意网卡的中断的设置,在WinCE中,与外设对应的中断在0AL层被定义,所以这里的中断号必须与0AL层设置的一致,否则网络驱动将无法工作。

(6)将驱动编译进系统内核,修改系统平台初始化文件platform.bib。

经过上述步骤之后,重新编译内核,将内核下载到嵌入式主板上,就可以看到类似Windows操作系统的网络连接一样标志,说明网卡驱动已经被加载到内核。

本文在介绍嵌入式WinCE网络驱动架构的基础上,参照WinCE提供的网络驱动模型,详细介绍了嵌入式WinCE以太网驱动程序的设计原理,并已经成功的移植了驱动程序,在嵌入式WinCE下稳定运行。本网络接口已经用于脉冲发生器的远程控制,运行稳定。

{完}

NDIS与WinSock关系之自我扫盲相关推荐

  1. 微信支付横空出世,闲扯一番自我扫盲(转)

    首先是扫盲点: 1.  微信支付自2014年3月5号开始支付接口正式对外开放. 2.  申请者必须是认证服务号(简单来说吧,你必须有实体公司的营业执照) 3.  公司法新政策,大家可以去百度一下自我扫 ...

  2. OpenSSL BIO 自我扫盲

    参考文档 http://openssl.cs.utah.edu <OpenSSL 编程>赵春平 <OpenSSL与网络信息安全-基础.结构和指令> OpenSSL中文手册之BI ...

  3. 计算机老师的理想和信念,大学英语教师计算机焦虑,网络使用自我效能及计算机信念的关系研究...

    摘要: 计算机焦虑是一个心理现象,指在当个体使用计算机或者想到有关计算机使用技术时会有一种害怕,恐惧的体验.国外在这方面己有很多的研究,对计算机焦虑的生理表现,测量工具,治疗方法等都有较深入的研究.有 ...

  4. 中小民营企业劳动关系和谐浅议

    劳动关系是我国最基本.最普遍的社会关系,是连接劳动者和企业的纽带,中小民营企业与劳动者的和谐关系,不仅能提高企业的经济效益,同时也为社会的稳定发展奠定了一定的基础.但是随着我国经济的发展,中小民营企业 ...

  5. 100个人面试,70个倒在了自我介绍上

        有人说,相亲就像面试:也有人反驳,相亲和面试有着本质的不同,两者不可相提并论.在职场情感学上颇有研究的小编,最近发现了一些"规律".本篇文章将"学术性" ...

  6. WINCE6.0+S3C6410下的DM9000A驱动

    ********************************LoongEmbedded************************ 作者:LoongEmbedded(kandi) 时间:201 ...

  7. aspnetdb.mdb数据库介绍

    说明:该博文非原创,摘自:CSDN--->http://blog.csdn.net/pwalai/archive/2008/05/10/2431273.aspx asp.net 安全性验证中,觉 ...

  8. 情感识别难?图神经网络创新方法大幅提高性能

    作者 | Kevin Shen 译者 | Monanfei 出品 | AI科技大本营(ID: rgznai100) [导读]最近,深度学习在自然语言处理领域(NLP)取得了很大的进步.随着诸如 Att ...

  9. [学习整理]eclipe/MyEclipse:重要的快捷键

    一.查看大工程代码最重要的几个快捷键 其实有一些,直接在编辑器页面内右键也可查看相应的快捷键(比如F3,F4,Ctrl+O,Ctrl+T),但有些比较好用的快捷键,并不能能直接或方便地在eclipse ...

最新文章

  1. 中国超细旦丝现状调研及投资前景评估报告2022-2028年版
  2. python人工智能——深度学习——TensorFlow——图和会话
  3. mysql多表查询详解_MySQL多表查询详解上
  4. python 随机名言_如何用简易代码自动生成经典语录
  5. python 内置函数 builtins_python学习笔记(七)——内置函数
  6. lua 区间比较_TI-Lua 系列教程2.4.1: 条件分支
  7. matlab 数组范围内,MATLAB索引超出数组范围
  8. java scanner构造函数_Point类的构造函数(JAVA)
  9. im即时通讯源码+软件+app附详细封装视频搭建教程
  10. linux 内核 addr2line,內核調試 arm-none-linux-gnueabi-addr2line 工具使用
  11. 几款手机网站前端框架
  12. 坚持---明朝那些事儿
  13. 论文阅读 (四):MILIS: Multiple Instance Learning with Instance Selection.
  14. 排污单位生产设施及污染治理设施用电(能)监控系统原理、作用、组成及功能
  15. Windows去快捷方式角标
  16. 用人工智能设计超酷T恤,除了那专属感,还透露了这些时装设计大趋势 || 万有AI...
  17. 最大子矩阵(C语言)
  18. mysql 1亿条数据建索引时间_单表 13 亿记录创建索引需要多长时间?
  19. 利用pgzero做一个接球的小游戏
  20. Java程序员笨鸟前行之路(一) 开发环境搭建

热门文章

  1. 在js在页面中添加百度统计代码
  2. 删除指定下标的元素c语言,PHP删除数组中指定下标的元素方法
  3. linux中用户与组的概念,Linux用户和组的概念
  4. Redis 集群搭建和简单使用
  5. CSS对IE6、IE7、IE8支持详细的易用的参考
  6. linux如何编译wine,利用winelib编译一个可在linux下运行的程序
  7. ozf oracle,ORACLE EBS 简称大全
  8. java填空题_Java语言基础知识填空题
  9. 布尔运算_利用布尔运算拆分汉字
  10. 陕西专科学校王牌计算机专业,陕西省高职专科院校排名+王牌专业