编写设备驱动程序

可装入驱动程序接口

设备驱动程序必须是可动态装入的。驱动程序还应是可卸载的,以帮助节省内存资源。可卸载驱动程序还应易于测试、调试和修补。

每个设备驱动程序都需要实现 _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
};

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() 示例

以下示例给出了典型的 _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() 中分配特定于每台打印机实例的资源。


注 –

一旦 _init(9E) 调用了 mod_install(9F),驱动程序便不应更改连接至 modlinkage(9S) 结构的任何数据结构,因为系统可能会复制或更改这些数据结构。


_fini() 示例

以下示例给出了 _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() 中分配的所有资源。驱动程序必须将其自身从系统模块列表中删除。


注 –

将驱动程序连接至硬件实例时,可能会调用 _fini()。在本示例中,mod_remove(9F) 返回失败信息。因此,在 mod_remove() 返回成功信息之前,不应释放驱动程序资源。


_info() 示例

以下示例给出了 _info(9E) 例程。

int
_info(struct modinfo *modinfop)
{
    return (mod_info(&xxmodlinkage, modinfop));
}

调用该驱动程序是为了返回模块信息。应按如上所示实现入口点。