实验 27 VxWorks 网络驱动程序编写实验
一 实验原理
1 MUX 网络设备驱动程序简介
VxWorks 的网络协议栈有个特征,就是在数据链接和网络协议层之间使用公共接口
(API)来进行数据交互,这种接口被称为 MUX 网络接口。在 BSD4.3 模型下,VxWorks 网络
骆动程序和协议紧密结合,它们彼此紧密依赖于对方的数据结构。而在基于 MUX 的模式下,
网络驱动程序与协议之间没有内部交换数据,它们只通过 MUX 间接相互作用。例如,接收到
数据包后,网络接口驱动程序并不直接访问协议中的任何结构。而当驱动程序准备给协议传
递数据时,驱动程序会调用 MUX 辅助程序,然后此程序用于处理给协议传递数据时的具体细
节。MUX 接口的目的是分解协议和网络驱动程序,从而使它们几乎独立于彼此。这种独立使
添加新的驱动程序和协议变得简单。例如,若想添加一新的 END,所有现有基于 MUX 的协议
均可使用新的驱动程序。同样地,若想添加一新的基于 MUX 的协议,任何现有的 END 均可
MUX 来访问新的协议。
图 1 VxWorks 网络协议栈
IP+ICMP Stream 用户协议
MUX接口
以太网 SLIP 其他
图 2 VxWorks 网络协议与 MUX 接口
图 3 VxWorks MUX 驱动与网络协议
图 1、2、3 显示了协议栈、MUX 和一个网络接口驱动程序之间的 API 接口调用关系。可
以看出协议层会执行以下接口:
stackShutdownRm()
stackError()
stackRcvRm()
stackTxRestartRm()
stackShutdownRtn()
stackRcvRtm()
stackError()
stackTxRestartRtn()
muxBind()
muxUnbind()
muxDevLoad()
muxDevUnload()
muxReceive()
muxError()
muxSend()
muxTxRestartRtn()
muxMCastAddrGet()
muxMCastAddrDel()
muxMCastAddrAdd()
muxPollSend()
muxPollReceive()
muxIoctl()
endLoad()
endUnload()
endSend()
endTxRestartRtn()
endMCastAddrGet()
endMCastAddrDel()
endMCastAddrAdd()
endPollSend()
endPollReceive()
endIoctl()
endStart()
endStop()
图 4 VxWorks MUX 驱动调用关系
MUX 会执行入口点 muxBind()、muxUnbind()、muxDevLoad()等。MUX 使用这些入口点与
网络接口驱动程序相互作用,如图 4。当编写或加载网络接口驱动程序以使用 MUX 时,用户
必须实现上面的所有接口点。
当启动系统时,VxWorks 执行任务 tUsrRoot 来完成驱动程序的安装,步骤如下:
网络任务的工作队列初始化;
产生 tNetTask 来处理网络任务工作队列中的条目;
调用 muxDevLoad()加载网络驱动程序;
调用 muxDevStart()启动驱动程序。
使用 tUsrRoot 调用 muxDevLoad()加载用户网络驱动程序。作为调用的输入,tUsrRoot
规定了用户驱动程序 endLoad()的入口点。这个 endLoad()入口点类似于 xxattach()入口点。
endLoad()程序用于处理任何特殊设备的初始化并且返回一个 END_OBJ 结构。用户的网络设
备描述结构必须包含该结构,而且还包括一个指向 NET_FUNCS 结构的指针。
在从 endLoad()返回控制值到 muxDevLoad()之后,MUX 完成了 END_OBJ 结构的填写(通
过给程序赋予一指针,用户的驱动程序可以传递数据包到 MUX 中)。MUX 然后把返回的 END_OBJ
添加到 END_OBJ 结构的链表中,此链表列出了当前系统所运行的所有网络设备的信息。在
muxDevLoad()返回控制信息后,用户的驱动程序装载完毕以备用。
当网络设备产生中断时,VxWorks 调用用户驱动程序先前注册的中断服务程序,中断服
务程序应做尽可能少的工作以完成将信息包从本地硬件送出/取出。中断服务程序应尽量减
小中断阻塞时间,中断服务程序只应该处理那些只需要最小执行时间的任务,如差错和状态
变换,而不应包含所有任务级的耗时处理工作。
为了将一些数据包的处理工作放置在任务级别,用户中断服务程序必须调用
netJobAdd()将相应的处理程序作为输入来生成一个任务级的数据处理任务,netJobAdd()
接收一个程序指针和最多 5 个附加参数,这些参数将由添加的程序引用。下面是 netJobAdd()
的函数原型:
程序清单 1 netJobAdd 函数原型
STATUS netJobAdd
{
FUNCPTR rountine, /* 处理函数的指针 */
int paraml, /* 可选参数 1 */
int param2, /* 可选参数 2 */
int param3, /* 可选参数 3 */
int param4, /* 可选参数 4 */
int param5 /* 可选参数 5 */
}
在用户调用 netJobAdd ()时,应把驱动程序用来处理数据包的入口点规定为任务级别。
然后 netJobAdd ()程序把程序调用(和自变量)放入 tNetTask 的工作队列。VxWorks 使用
tNetTask 来处理任务级别的网络处理。使用 netJobAdd()有两个事情要明确:
用户可以使用 netJobAdd ()来生成任务而不处理接收到的数据包;
netJobAdd ()为一个同时被网络堆栈所使用的有限资源。若其溢出将会造成通用网络堆
栈的瘫痪。
2 RTL8019 网络芯片简介
在进行驱动程序编写之前,首先看看 JX2410 教学系统中的网络芯片的操作方法。
JX2410 使用的网络芯片是由台湾 Realtek 公司生产的 RTL8019AS,它是一个高集成的以太网
控制器芯片,不仅集成了介质访问控制子层(MAC)和物理层的性能,而且还可以方便地设
计基于 ISA 总线的系统,简单的与通用处理器进行接口。另外,它还具有与 NE2000 兼容、
软件移植性好,以及低廉的价格等优点,在市场上的 10Mbps 网卡中占有相当的比例。
(1) 主要性能
适应于 Ethernet II 、IEEE802.3 协议、10Base5、10Base2、10BaseT;
支持 8 位、16 位数据总线,8 个中断申请线以及 16 个 I/O 基地址选择;
全双工,收发可同时达到 10Mbps 的速率,具有休眠模式,以降低功耗;
内置 16KB 的 SRAM,用于收发缓冲,降低对主处理器的速度要求;
可连接同轴电缆和双绞线,并可自动检测所连接的媒介类型;
支持闪存读写;
允许四个诊断 LED 引脚可编程输出;
100 脚的 TQFP 封装,缩小主机板尺寸。
(2) 工作原理
按数据链路的不同,可以将以太网络控制器内部划分为远程DMA(remote DMA)信道和本
地DMA(local DMA)信道两个部分。本地DMA完成控制器与网络线的数据交换,处理器(Host)
收发数据只需对远程DMA操作。当主处理器要向以太网络发送数据时,先将一帧(frame)数
据经过远程DMA信道,送到以太网络控制器中的发送缓存内存(Ring Buffer),然后发出传
送命令。以太网络控制器在送出前一帧的数据后,继而完成此帧的发送。以太网络控制器接
收到的数据通过MAC比较、CRC校验后,由FIFO存到接收缓冲区,收满一帧后,以中断或缓存
器标志的方式通知处理器。
接收逻辑在接收时脉的控制下,将串行数据组成字节送到 FIFO 和 CRC;发送逻辑将 FIFO
送来的字节在发送时脉的控制下逐步按位移出,并送到 CRC;CRC 逻辑在接收时对输入的数
据进行 CRC 校验,将结果与帧尾的 CRC 比较,如不同,该帧数据将被拒收,在发送时 CRC
对帧数据产生 CRC,并附加在数据尾传送;地址识别逻辑对接收帧的目的地址与预先设置的
本地实体地址进行比较,如不同且不满足广播地址(broadcast address)的设定要求,该
帧数据将被拒收;FIFO 逻辑对收发的数据作 16 个字节的缓冲,以减少对本地 DMA 请求的频
率。
RTL8019 是针对 PC 总线设计的,将其应用在嵌入式设备中,需要考虑其硬件和软件设
计上的特殊性。嵌入式设备的主处理器可利用内存映像方法,将以太网络控制器内 16 个 I/O
地址上的缓存器映像到嵌入式操作系统来,这样就可以用程序来操控以太网络控制器。
RTL8019 的缓存器地址如下图所列。
图 5 RTL8019 芯片寄存器映射图
(3) 软件设计
对于 8019AS的软件设计,包括芯片初始化、发送、接收三部分。
芯片初始化
首先要对网卡进行复位:18H-1FH 共 8 个地址,为复位端口。对该端口地址的读或者
写入任何数,都会引起网卡的复位,代码如下:。
程序清单 2 RTL8019 复位操作
void rtl8019_Reset(void)
{
unsigned int i;
unsigned char temp;
for(i=0;i<250;i++); /* 简单的延时 */
temp=inportb(RTL8019_BASE +0x1f); /* 读网卡的复位端口 */
outportbb(RTL8019_BASE +0x1f,temp); /* 写网卡的复位端口 */
}
说明:RTL8019_BASE 是 RTL8019 的基地址,其全部的寄存器地址都是由它得出来的,
在初始化时必须赋予它正确的基准地址值。我们在此所使用的值为 0x18000300。网卡复位
完成之后,要对网卡的工作参数进行设置,使网卡开始工作。对网卡的参数设置主要是对命
令寄存器 CR 进行设置,CR 主要是用于选择寄存器页、启动或停止远程 DMA 操作以及执行命
令。网卡初始化的软件编程如下
:
程序清单 3 RTL8019 初始化
void rtl8019_init()
{
outportb(RTL8019_BASE+0x00,0x21); /*选择页 0 寄存器,网卡停止运行*/
outportb(RTL8019_BASE+0x01,0x4c); /*接收缓冲区范围*/
outportb(RTL8019_BASE+0x02,0x80); /*PSTOP,构造缓冲环:0x4c-0x80*/
outportb(RTL8019_BASE+0x03,0x4c); /*BNRY,设置指针*/
outportb(RTL8019_BASE+0x04,0x40); /*发送缓冲区范围*/
outportb(RTL8019_BASE+0x0d,0x4c);
outportb(RTL8019_BASE+0x0e,0xc8); /*设置数据配置寄存器使用 FIFO 缓存
*/
/*普通模式,8 位数据 DMA*/
outportb(RTL8019_BASE+0x0f,0xff); /*清除所有中断标志位*/
outportb(RTL8019_BASE+0x0f,0x00); /*设置中断屏蔽寄存器屏蔽所有中断*/
/* page(1); 选择页 1 寄存器;*/
outportb(RTL8019_BASE+0x07,0x4d); /*初始化当前页寄存器,*/
/*指向当前正在写的页的下一页;*/
评论0