AIX 下写驱动模块没有象 linux/solairs 那样固定的入口,入口是在编译连接时可以随意指
定的,(这点比较灵活)只要包含特定的规范即可,如 int cmd 和一个 struct uio* 结构。
关于如何装载驱动,在你那份文档里已经有介绍了。应用层与驱动通讯也有一套固定的规范,见
uiomove() 等 kernel api。这点做的比较像 Windows 驱动。记得我在 IBM 网站上曾经
看到过一篇介绍如何编写驱动模块的框架,还是中文的。你可以到 http://publib.boulder.ibm.com/
再去搜索看看。我也是再编写了几个驱动后才看到这篇文章的。
关于你提到的类 linux 下的设备结构,在 AIX 下不论是伪设备驱动还是真实的设备驱动,都需要
向系统注册一个 struct devsw (设备交换表),使用 devswadd() 来添加,将这个结构中的
open/read/write/close 区域指向你的回调函数即可。
最后在 AIX 下处理还需要考虑 64 BIT 的兼容情况。
void
loadipf(int major, int minor, dev_t devno, char *path)
{
struct cfg_dd ipfcfg;
struct cfg_load cfg;
char *buffer[1024];
char *ipfpath;
int i;
bzero(buffer, sizeof(buffer));
if (path != NULL)
ipfpath = path;
else
ipfpath = "/usr/lib/drivers/ipf";
#if 0
bzero((char *)&cfg, sizeof(cfg));
cfg.path = ipfpath;
cfg.libpath = "/usr/lib/drivers/";
sysconfig(SYS_SINGLELOAD, &cfg, sizeof(cfg));
ipfcfg.kmid = cfg.kmid;
#else
ipfcfg.kmid = (mid_t)loadext(ipfpath, TRUE, TRUE);
#endif
if (ipfcfg.kmid == (mid_t)NULL)
{
perror("loadext");
buffer[0] = "execerror";
buffer[1] = "ipf";
loadquery(1, &buffer[2], sizeof(buffer) - sizeof(*buffer)*2);
execvp("/usr/sbin/execerror", buffer);
exit(errno);
}
ipfcfg.devno = devno;
ipfcfg.cmd = CFG_INIT;
ipfcfg.ddsptr = (caddr_t)NULL;
ipfcfg.ddslen = 0;
if (sysconfig(SYS_CFGDD, &ipfcfg, sizeof(ipfcfg)) == -1) {
perror("sysconifg(SYS_CFGDD)");
exit(errno);
}
for (i = 0; ipf_devfiles
!= NULL; i++) {
unlink(ipf_devfiles);
if (mknod(ipf_devfiles, 0600 | _S_IFCHR, devno) == -1) {
perror("mknod(devfile)");
exit(errno);
}
}
}
这个 loadipf 函数是在main里调用的,我猜应该是在命令行下敲入命令根据参数调用这个函数。
这个 loadipf 函数应该是装载模块进内核的
int ipfconfig(devno, cmd, uiop)
dev_t devno;
int cmd;
struct uio *uiop;
{
int error = EINVAL;
printf("ipfconfig(%u,%x,%p)\n", devno,cmd,uiop);
switch (cmd)
{
case CFG_INIT :
error = devswadd(devno, &ipfdevsw);
if (error == 0)
error = ipfattach();
break;
case CFG_TERM :
error = devswdel(devno);
break;
case CFG_QVPD :
error = 0;
break;
default :
return EINVAL;
}
return 0;
}
这个 ipfconfig 应该是一个配置函数,即利用 devsw 将自己写的函数挂载上去。但是没有找到这个函数的调用点
我觉得只有上面这两个配合使用:ipfconfig利用 devsw 将自己的驱动对应到某个主设备号上去
然后用loadipf将这个主设备号装载到内核里。。。。
不知自己的理解对不对。
那个 loadipf() 是应用层代码, sysconfig() 这个 syscall 就是负责装载驱动的。从代码来 看那个 ipfconfig() 应该是配置入口,但是代码不全,也没有对 struct devsw ipfdevsw 进行 设置。在调用 devswadd() 之前应该先用 devswqry() 查询下设备。
ifdevsw已经设置了,完整的代码在这里: http://www.google.com/codesearch?hl=en&q=+lang:c+ipfconfig+show:IWIo1eXS5e4:v4l8bOL-OYQ:ibQrDqBvLK0&sa=N&cd=1&ct=rc&cs_p=ftp://coombs.anu.edu.au/pub/net/ip-filter/ip_fil4.1.10.tar.gz&cs_f=ip_fil4.1.10/ip_fil_aix.c#a0 那个loadipf也在这个连接左边的 AIX 目录下的 aix_cfg_ipf.c 文件里,具体的连接地址是: http://www.google.com/codesearch?hl=en&q=show:ukJJHIWWKLc:JGNERWZWZ4k:PBaLLLhyBBM&sa=N&ct=rd&cs_p=ftp://coombs.anu.edu.au/pub/net/ip-filter/ip_fil4.1.10.tar.gz&cs_f=ip_fil4.1.10/AIX/aix_cfg_ipf.c
现在我的疑问是:这个 devsw 到底 怎么加进去的? 是不是先将ipfconfig这个函数所在的文件等编译成一个库,然后应用层调用了 loadipf 从而调用 sysconfig,然后 sysconfig 根据 PATH 将这个库加载进去? ipfconfig 编译出来就是一个驱动。在这里它使用的是 loadext() 先安装驱动,然后 sysconfig() 发送控制字,这个 devsw 就加进去了。
|