第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
14. 分层驱动程序接口 (Layered Driver Interface, LDI)
设备驱动程序必须是可动态装入的。驱动程序还应是可卸载的,以帮助节省内存资源。可卸载驱动程序还应易于测试、调试和修补。
每个设备驱动程序都需要实现 _init(9E)、_fini(9E) 和 _info(9E) 入口点以支持驱动程序的装入和卸载。以下示例显示了可装入驱动程序接口的典型实现。
示例 6-1 可装入接口部分
static void *statep; /* for soft state routines */
static struct cb_ops xx_cb_ops; /* forward reference */
static struct dev_ops xx_ops = {
DEVO_REV,
0,
xxgetinfo,
nulldev,
xxprobe,
xxattach,
xxdetach,
xxreset,
nodev,
&xx_cb_ops,
NULL,
xxpower,
ddi_quiesce_not_needed,
};
static struct modldrv modldrv = {
&mod_driverops,
"xx driver v1.0",
&xx_ops
};
static struct modlinkage modlinkage = {
MODREV_1,
&modldrv,
NULL
};
int
_init(void)
{
int error;
ddi_soft_state_init(&statep, sizeof (struct xxstate),
estimated_number_of_instances);
/* further per-module initialization if necessary */
error = mod_install(&modlinkage);
if (error != 0) {
/* undo any per-module initialization done earlier */
ddi_soft_state_fini(&statep);
}
return (error);
}
int
_fini(void)
{
int error;
error = mod_remove(&modlinkage);
if (error == 0) {
/* release per-module resources if any were allocated */
ddi_soft_state_fini(&statep);
}
return (error);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
以下示例显示了典型的 _init(9E) 接口。
示例 6-2 _init() 函数
static void *xxstatep;
int
_init(void)
{
int error;
const int max_instance = 20; /* estimated max device instances */
ddi_soft_state_init(&xxstatep, sizeof (struct xxstate), max_instance);
error = mod_install(&xxmodlinkage);
if (error != 0) {
/*
* Cleanup after a failure
*/
ddi_soft_state_fini(&xxstatep);
}
return (error);
}
在 _init() 中装入驱动程序期间,驱动程序应执行所有一次性资源分配或数据初始化。例如,在该例程中驱动程序应初始化所有对于该驱动程序为全局互斥锁的互斥锁。但是,驱动程序不应使用 _init(9E) 来分配或初始化与设备特定实例有关的任何内容。必须在 attach(9E) 中完成每个实例的初始化。例如,如果打印机的驱动程序可以同时处理多台打印机,则该驱动程序应在 attach() 中分配特定于每台打印机实例的资源。
以下示例显示了 _fini() 例程。
int
_fini(void)
{
int error;
error = mod_remove(&modlinkage);
if (error != 0) {
return (error);
}
/*
* Cleanup resources allocated in _init()
*/
ddi_soft_state_fini(&xxstatep);
return (0);
}
同样,在 _fini() 中,驱动程序应该释放在 _init() 中分配的所有资源。驱动程序必须将其自身从系统模块列表中删除。
以下示例显示了 _info(9E) 例程。
int
_info(struct modinfo *modinfop)
{
return (mod_info(&xxmodlinkage, modinfop));
}