原文地址:https://blog.csdn.net/weixin_44048491/article/details/113701183
整理了一下排版,方便学习参考代码。
VxWorks的内核驱动层次:
所有类型(包括网络设备)的设备都必须向 IO 子系统进行注册方可被内核访问。
ioLib.c 文件称为上层接口子系统,上层接口子系统直接对用户层可见。
iosLib.c 文件称为 IO 子系统,而 IO 子系统则一般不可见,其作为上层接口子系统与下层驱动系统的中间层而存在。由于 IO 子系统在整个驱动层次中起着管理的功能,其维护着系统设备和驱动的关键的三张表:系统设备表、系统驱动表、文件描述符表。
1、系统设备表
Vxworks 内核对每个设备使用 DEV_HDR 数据结构进行表示,该结构定义如下。
/h/iosLib.h/
typedef struct // DEV_HDR - device header for all device structures
{
DL_NODE node; // device linked list node
short drvNum; // driver number for this device
char * name; // device name
} DEV_HDR;
底层驱动对其驱动的设备都有一个自定义数据结构表示,其中包含了被驱动设备寄存器基地址,中断号,可能的数据缓冲区,保存内核回调函数的指针,以及一些标志位。最为关键的一点是 DEV_HDR 内核结构必须是这个自定义数据结构的第一个成员变量,因为这个用户自定义结构最后需要添加到系统设备队列中,故必须能够在用户自定义结构与 DEV_HDR 结构之间进行转换,而将 DEV_HDR 结构设置为用户自定义结构的第一个成员变量就可以达到这个目的。
typedef struct xxDev
{
DEV_HDR devHdr; //内核提供的结构,必须是自定义结构的第一个成员变量。
UINT32 regBase; //设备寄存器基地址。
UINT32 buffPtr; //数据缓冲区基地址。
BOOL isOpen; //设备已打开标志位。
UINT8 intLvl; //设备中断号。
FUNCPTR putData; //内核回调函数指针,该指针指向的函数向内核提供数据。
FUNCPTR getData; //内核回调函数指针,该指针指向的函数从内核获取数据。
… //其他设备参数。
}
驱动程序必须将设备注册到 IO 子系统中,这个过程也被称为创建设备节点。
IO 子系统提供的 iosDevAdd 函数用以被驱动程序调用注册一个设备。该函数调用原型如下:
STATUS iosDevAdd(DEV_HDR pDevHdr, char name, int drvnum);// drvnum是iosDrvInstall()的返回值
参数 1 是一个 DEV_HDR 结构类型,一般我们将用户自定义结构作为第一个参数传入,这也是必须将 DEV_HDR 结构类型的成员变量作为用户自定义结构的第一个成员的原因所在;
参数 2 表示设备节点名,这个名称将被用户程序调用作为打开设备时的路径使用。
参数 3 是设备对应的驱动程序索引号。这个驱动号是 iosDrvInstall 函数的返回值。
在设备初始化函数中,我们首先调用 iosDrvInstall 注册驱动,然后使用 iosDrvInstall 函数返回的驱动号调用 iosDevAdd 添加设备到系统中,这两步完成之后,设备就可以被用户程序使用了。
iosDevAdd 函数将一个设备添加到由 IO 子系统维护的系统设备列表中,该列表是一个队列,队列中成员通过指针链接在一起,这是由 DEV_HDR 结构中 node 成员变量完成的。系统设备列表由 iosDvList 内核变量指向。
系统设备列表中第一个设备是内核本身添加的,这是一个 null 设备