首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

IBM AIX 设备驱动程序开发 -1

IBM AIX 设备驱动程序开发 -1

简介在传统的 UNIX® 中,术语 设备 是指硬件组件,如磁盘驱动器、磁带驱动器、打印机、键盘、伪设备(如控制台、错误特殊文件和空特殊文件),等等。在 AIX 中,这些设备被称为核心设备,它们有设备驱动程序,系统通过主编号和次编号来识别它们。
AIX 设备驱动程序是一种 AIX 内核扩展。内核扩展在一个受保护的内核域上运行。它们可以在系统启动或运行时被加载到内核中,也可以在运行时被删除。用户级的代码只能通过系统调用来访问注册的设备驱动程序代码。设备驱动程序为 AIX 添加了系统管理的可扩展性、可配置性和易用性。
如需了解基本的内核扩展开发,请参阅 IBM developerWorks 文章 。
设备驱动程序通过引用 /usr/lib/kernex.exp 使用由 AIX 内核 "/unix" 导出的核心内核服务。"kernex.exp" 包含一个由内核导出的符号列表。这些导出的符号本质上是内核函数和存储位置(内核全局数据结构)。链接器程序 (ld) 在链接编译的设备驱动程序代码时使用此信息。
设备类型
  • 字符
  • 网络
  • 多路复用字符设备
设备被表示为在 /dev 目录下面所列出的特殊类型的文件。
这些文件中没有任何可打印的内容。实际上,它们提供一个接口,供用户与相关设备进行交互。这些文件的 inode 包括主编号和次编号。使用 mknod() 系统调用可以创建这些文件。
Object Data Manager (ODM)ODM 维护以对象的类的形式所表示的数据。它是用于存储特定于设备的配置信息。它有预定义的数据库,用于存储所有设备的配置数据。它还具有当前在系统中运行的设备实例的自定义数据库。ODM 需要初始化之后才能使用。打算配置设备驱动程序的应用程序,必须首先初始化 ODM。
应用程序使用在 /usr/include/odmi.h 中定义的 odm_initialize() API 初始化 ODM。
内核扩展配置的基础知识struct cfg_load 的组件和使用 加载内核扩展的结构:
1
2
3
4
5
6
struct cfg_load
{
   caddr_t path; /* ptr to object module pathname */
   caddr_t libpath; /* ptr to a substitute libpath */
   mid_t   kmid;    /* kernel module id (returned) */
};




struct cfg_dd 的组件和使用用于调用设备驱动程序的配置(模块)入口点的结构:
1
2
3
4
5
6
7
8
struct cfg_dd
{
  mid_t   kmid;/* Module ID of device driver */
  dev_t   devno; /* Device major/minor number */
  int     cmd; /* Config command code for device driver*/
  caddr_t ddsptr; /* Pointer to device dependent structure*/
  int     ddslen; /* Length of device dependent structure */
};




Sysconfig() 系统调用Sysconfig() 需要三个参数。
1
2
3
4
5
int sysconfig(            
   int cmd, /* Command to be executed */
   void *parmp,/* Address of structure containing info for cmd */
   int parmlen /* Length of parmp information */
);




Sysconfig() 用于控制内核扩展的生命周期。如 /usr/include/sys/sysconfig.h 中所示,下面的命令被传递给 sysconfig() 作为 cmd 参数。
  • SYS_KLOAD: 在内核内存中加载一个内核扩展目标文件。
  • SYS_SINGLELOAD: 只有在尚未加载内核扩展目标文件时加载它。
  • SYS_QUERYLOAD: 确定是否加载一个指定的内核目标文件。
  • SYS_KULOAD: 卸载以前加载的内核目标文件。
  • SYS_CFGKMOD: 在模块入口点调用指定的模块,用于配置。
设备驱动程序基础知识主编号和次编号设备被视为 /dev 目录下的特殊文件。因此,每个设备都有一个名称,并且在其根文件系统下面有一个关联的 inode 或索引节点。每一个设备的文件系统入口点都包含主编号和次编号。
主编号用于在系统中惟一地找到该设备。这是设备交换表的索引。设备交换表包含设备特定的方法的指针,它们基本上是通用文件系统函数的实现。以这种方式,给定移动设备上由用户进程发布的文件系统调用被解析为对相应设备驱动程序函数的调用。驱动程序在内部使用次编号来区分多路复用设备的逻辑通道。
通过库调用 genmajor() 可以获得主编号。
genmajor() 的语法是:
1
int genmajor(char* name_of_device_driver)




通过库调用 genminor() 可以获得次编号。
它生成可供设备使用的最小的未使用次编号、首选的次编号码(如果可用),或为设备生成一组未使用的次编号。
genminor() 的语法是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int *genminor (
char * device_instance,
/*
Points to a character string containing the device instance name.*/
int major_no,
/*
  The major number of the device instance.*/
int preferred_minor,
/*
  Contains a single preferred minor number or a starting  
minor number for generating a set of numbers. */
int minors_in_grp,
/*
Indicates how many minor numbers are to be allocated.  */
int inc_within_grp,
/*
Indicates the interval between minor numbers.*/
int inc_btwn_grp
/*
Indicates the interval between groups of minor numbers.*/
);




makedev() API给定设备的主编号和次编号需要被打包成一个 32 位或 64 位整数,这取决于架构。该整数的数据类型是 dev_t。makedev() 是一个宏,它通过给定的主编号和次编号创建 dev_t。它是在 <sys/sysmacros.h> 下面定义的。makedev64() 用于为 64 位环境创建 dev_t。
makedev() 或 makedev64() 的语法是:
1
dev_t makedev64(int major, int minor);




mknod() 系统调用它是在 <sys/stat.h> 中定义的。它用于创建一个普通文件、先进先出 (FIFO),或一个特殊文件。它要求 root 特权,以使用 mknod() 来创建一个设备特殊文件。
mknod() 的语法是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int mknod (
char *Path,
/*
  Names the new device special file.
*/
int Mode,
/*
  Specifies the file type, attributes, and access
  permissions.
*/
dev_t Device
/*
  Device number generated by makedev() subroutine.
*/
);




设备交换表设备交换表是 struct devsw 结构的一个数组。它按主编号索引,并驻留在内存中(也就是说,它永远不会被换出 RAM)。块设备和字符设备使用此内核结构在根文件系统上注册自己。
设备交换表条目结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct devsw
{
int (*d_open)(); /* entry point for open routine */
int (*d_close)(); /* entry point for close routine */
int (*d_read)();/* entry point for read routine */
int (*d_write)(); /* entry point for write routine */
int (*d_ioctl)();/* entry point for ioctl routine */
int (*d_strategy)();/* entry point for strategy routine */
struct tty  *d_ttys;/* pointer to tty device structure */
int (*d_select)();  /* entry point for select routine */
int (*d_config)();  /* entry point for config routine */
int (*d_print)(); /* entry point for print routine */
int (*d_dump)(); /* entry point for dump routine */
int (*d_mpx)(); /* entry point for mpx routine */
int (*d_revoke)(); /* entry point for revoke routine */
caddr_t d_dsdptr; /* pointer to device specific data */
/*
  * The following entries are control fields managed
  * by the kernel and should not be modified by device
  * drivers or kernel extensions.  They may be set to
  * 0 in the devsw structure for devswadd(), since they
  * are not copied into the device switch table.
  */
caddr_t d_selptr;/* ptr to outstanding select cntl blks*/
ulong   d_opts;/* internal device switch control field */
};

返回列表