编写设备驱动程序

驱动程序必需的数据结构

为了支持自动配置,驱动程序需要静态初始化以下数据结构:

驱动程序依赖于图 5-1 中的数据结构。必须提供并正确初始化这些数据结构。没有这些数据结构,可能无法正确装入驱动程序。结果导致可能无法装入必需的例程。如果驱动程序不支持某个操作,则 nodev(9F) 例程的地址可以用作占位符。在某些情况下,驱动程序支持入口点,并且仅需要返回成功信息或失败信息。在这种情况下,可以使用例程 nulldev(9F) 的地址。


注 –

应该在编译时对这些结构进行初始化。在任何其他时间,驱动程序都不应访问或更改这些结构。


modlinkage 结构

static struct modlinkage xxmodlinkage = {
    MODREV_1,       /* ml_rev */
    &xxmodldrv,     /* ml_linkage[] */
    NULL            /* NULL termination */
};

第一个字段是装入子系统的模块的版本号。该字段应为 MODREV_1。第二个字段指向接下来定义的驱动程序的 modldrv 结构。该结构的最后一个元素应始终为 NULL

modldrv 结构

static struct modldrv xxmodldrv = {
    &mod_driverops,           /* drv_modops */
    "generic driver v1.1",    /* drv_linkinfo */
    &xx_dev_ops               /* drv_dev_ops */
};

该结构更加详细地描述模块。第一个字段提供有关模块安装的信息。对于驱动程序模块,该字段应设置为 &mod_driverops。第二个字段是将由 modinfo(1M) 显示的字符串。第二个字段应包含足够的信息,以便确定生成驱动程序二进制文件的源代码版本。最后一个字段指向下节所定义的驱动程序的 dev_ops 结构。

dev_ops 结构

static struct dev_ops xx_dev_ops = {
    DEVO_REV,       /* devo_rev */
    0,              /* devo_refcnt  */
    xxgetinfo,      /* devo_getinfo: getinfo(9E) */
    nulldev,        /* devo_identify: identify(9E) */
    xxprobe,        /* devo_probe: probe(9E) */
    xxattach,       /* devo_attach: attach(9E) */
    xxdetach,       /* devo_detach: detach(9E) */
    nodev,          /* devo_reset */
    &xx_cb_ops,     /* devo_cb_ops */
    NULL,           /* devo_bus_ops */
    &xxpower        /* devo_power: power(9E) */
};

使用 dev_ops(9S) 结构,内核可以找到设备驱动程序的自动配置入口点。devo_rev 字段标识结构的修订号。该字段必须设置为 DEVO_REVdevo_refcnt 字段必须初始化为零。应使用相应驱动程序的入口点地址填充函数地址字段,但以下情况除外:

devo_cb_ops 成员应包含 cb_ops(9S) 结构的地址。devo_bus_ops 字段必须设置为 NULL

cb_ops 结构

static struct cb_ops xx_cb_ops = {
    xxopen,         /* open(9E) */
    xxclose,        /* close(9E) */
    xxstrategy,     /* strategy(9E) */
    xxprint,        /* print(9E) */
    xxdump,         /* dump(9E) */
    xxread,         /* read(9E) */
    xxwrite,        /* write(9E) */
    xxioctl,        /* ioctl(9E) */
    xxdevmap,       /* devmap(9E) */
    nodev,          /* mmap(9E) */
    xxsegmap,       /* segmap(9E) */
    xxchpoll,       /* chpoll(9E) */
    xxprop_op,      /* prop_op(9E) */
    NULL,           /* streamtab(9S) */
    D_MP | D_64BIT, /* cb_flag */
    CB_REV,         /* cb_rev */
    xxaread,        /* aread(9E) */
    xxawrite        /* awrite(9E) */
};

cb_ops(9S) 结构包含设备驱动程序的字符操作和块操作的入口点。驱动程序不支持的所有入口点应初始化为 nodev(9F)。例如,字符设备驱动程序应该将所有块字段(例如 cb_stategy)设置为 nodev(9F)。请注意,保留 mmap(9E) 入口点是为了兼容早期发行版。驱动程序应使用 devmap(9E) 入口点来进行设备内存映射。如果支持 devmap(9E),应将 mmap(9E) 设置为 nodev(9F)

streamtab 字段表明驱动程序是否基于 STREAMS。只有第 19 章中讨论的网络设备驱动程序基于 STREAMS。所有不基于 STREAMS 的驱动程序必须streamtab 字段设置为 NULL

cb_flag 成员包含以下标志:

cb_revcb_ops 结构修订号。该字段必须设置为 CB_REV