网页设计作业主题,大连seo关键词排名,网站 一级域名 二级域名,网站的设计风格起来真是雷人#xff0c;最近几天纠结与一个最基本的概念#xff0c;就是NDIS与WinSock关系#xff0c;想来想去都没有想明白#xff0c;真实汗Ing#xff0c;赶紧找了篇精美的文章来扫盲一下。
原文如下#xff1a; 文章转自http://www.cnblogs.com/sankye/articles/16… 起来真是雷人最近几天纠结与一个最基本的概念就是NDIS与WinSock关系想来想去都没有想明白真实汗Ing赶紧找了篇精美的文章来扫盲一下。
原文如下 文章转自http://www.cnblogs.com/sankye/articles/1651280.html 1.WinCE的网络通信架构
WinCE的网络通信架构如图1所示WinCE的网络通信架构中一个重要的角色是网络结构规范(NetworkDriver Interface SpecificationNDIS)它支持多种网络媒体以及提供包括TCPIP等多种网络协议。 图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接口函数。下面结合利用WinCE50内核在脉冲发生器嵌入式主板上移植编写嵌入式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 又会调用CS8900InitializeCS8900Initialize函数会相继调用findCS查找网络设备resetCS重启网络控制器并设置工作模式为16bit的I0模式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 CS8900AInitUINT *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的实际数值36,它把发送命令端口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 CS8900AGetFrameUINT8 *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中断必须满足两个条件接收事件寄存器RxEventPacketPage内偏移地址为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-Builder5O(简称PB5O)。其编译、加载过程主要分为六步 (1)在硬件平台BSP的DRIVERS目录下创建新目录CS89OO。 (2)修改DRIVERS下的DIRS文件DIR下定义了编译器需要编译的内容所以需要在DIRS文件中将CS8900目录添加上。 (3)将编写好网络驱动源程序代码拷贝到CS89OO目录下。 (4)编写网络设备驱动的sources文件告诉编译器和连接器如何编译及连接本驱动程序。这样的sources文件在每个WinCE的驱动下面都有一个是为了给PB编译驱动的时候提供编译“向导”的。其关键内容为TARGETTYPE定义编译该驱动成为哪种形式有DLL和Lib两种形式TARGETLIBS定义编译该程序的时候需要连接的其他库SOURCES确定需要编译的文件。本驱动被编译成的形式为DLL链接了ndisntcompatcoredllceddk 4个静态库。 (5)编写CS8900的注册表文件可参考WinCE自带的驱动源码ne2000网卡驱动的注册表文件编写CS8900的注册表文件。注册表定义了网卡的基本参数信息提供给操作系统其中Parms项提供网卡驱动在系统中的逻辑中断号读写基地址总线类型TcpIp项提供了网卡IP 地址信息等如果要修改IP地址就在本注册表项中修改。特别注意网卡的中断的设置在WinCE中与外设对应的中断在0AL层被定义所以这里的中断号必须与0AL层设置的一致否则网络驱动将无法工作。 (6)将驱动编译进系统内核修改系统平台初始化文件platformbib。 经过上述步骤之后重新编译内核将内核下载到嵌入式主板上就可以看到类似Windows操作系统的网络连接一样标志说明网卡驱动已经被加载到内核。 本文在介绍嵌入式WinCE网络驱动架构的基础上参照WinCE提供的网络驱动模型详细介绍了嵌入式WinCE以太网驱动程序的设计原理并已经成功的移植了驱动程序在嵌入式WinCE下稳定运行。本网络接口已经用于脉冲发生器的远程控制运行稳定。{完}