attach(9E) 会为每个设备实例执行常见初始化任务:
分配每个实例的状态结构
映射设备寄存器
注册设备中断
初始化互斥变量和条件变量
创建可进行电源管理的组件
创建次要节点
块设备驱动程序创建类型为 S_IFBLK 的次要节点。因此,代表节点的块特殊文件会出现在 /devices 分层结构中。
块设备的逻辑设备名称位于 /dev/dsk 目录中,该名称由控制器编号、总线地址编号、磁盘编号和片编号组成。如果节点类型设置为 DDI_NT_BLOCK 或 DDI_NT_BLOCK_CHAN,则这些名称由 devfsadm(1M) 程序创建。如果设备通过通道(即有附加寻址能力级别的总线)进行通信,则应该指定 DDI_NT_BLOCK_CHAN。SCSI 磁盘就是一个典型示例。DDI_NT_BLOCK_CHAN 可使总线地址字段 (tN) 出现在逻辑名称中。其他大多数设备则应该使用 DDI_NT_BLOCK。
次要设备指磁盘上的分区。对于每个次要设备,驱动程序必须创建 nblocks 或 Nblocks 属性。此整数属性给出了次要设备所支持的块数,以 DEV_BSIZE(即 512 字节)为单位。文件系统使用 nblocks 和 Nblocks 属性来确定设备限制。Nblocks 是 64 位版本的 nblocks。应该将 Nblocks 用于每个磁盘的存储容量超过 1 TB 的存储设备。有关更多信息,请参见设备属性。
示例 16–1 说明了一个典型的 attach(9E) 入口点,重点说明如何创建设备的次要节点和 Nblocks 属性。请注意,由于此示例使用 Nblocks 而非 nblocks,因此将调用 ddi_prop_update_int64(9F) 而非 ddi_prop_update_int(9F)。
作为附带说明,本示例还说明了如何使用 makedevice(9F) 为 ddi_prop_update_int64() 创建设备编号。makedevice 函数利用 ddi_driver_major(9F),后者基于指向 dev_info_t 结构的指针生成主设备号。使用 ddi_driver_major() 与使用 getmajor(9F) 类似,后者用于获取 dev_t 结构指针。
static int xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int instance = ddi_get_instance(dip); switch (cmd) { case DDI_ATTACH: /* * allocate a state structure and initialize it * map the devices registers * add the device driver's interrupt handler(s) * initialize any mutexes and condition variables * read label information if the device is a disk * create power manageable components * * Create the device minor node. Note that the node_type * argument is set to DDI_NT_BLOCK. */ if (ddi_create_minor_node(dip, "minor_name", S_IFBLK, instance, DDI_NT_BLOCK, 0) == DDI_FAILURE) { /* free resources allocated so far */ /* Remove any previously allocated minor nodes */ ddi_remove_minor_node(dip, NULL); return (DDI_FAILURE); } /* * Create driver properties like "Nblocks". If the device * is a disk, the Nblocks property is usually calculated from * information in the disk label. Use "Nblocks" instead of * "nblocks" to ensure the property works for large disks. */ xsp->Nblocks = size; /* size is the size of the device in 512 byte blocks */ maj_number = ddi_driver_major(dip); if (ddi_prop_update_int64(makedevice(maj_number, instance), dip, "Nblocks", xsp->Nblocks) != DDI_PROP_SUCCESS) { cmn_err(CE_CONT, "%s: cannot create Nblocks property\n", ddi_get_name(dip)); /* free resources allocated so far */ return (DDI_FAILURE); } xsp->open = 0; xsp->nlayered = 0; /* ... */ return (DDI_SUCCESS); case DDI_RESUME: /* For information, see Chapter 12, "Power Management," in this book. */ default: return (DDI_FAILURE); } }