编写设备驱动程序

使用设备 ID

使用 Solaris DDI 接口,驱动程序可以提供设备 ID,即设备的永久唯一标识符。设备 ID 可用于识别或查找设备。设备 ID 独立于 /devices 名称或设备编号 (dev_t)。应用程序可以使用 libdevid(3LIB) 中定义的函数来读取和处理由驱动程序注册的设备 ID。

在驱动程序可以导出设备 ID 之前,驱动程序需要检验设备是否可以提供唯一 ID 或者将主机生成的唯一 ID 存储在正常情况下不可访问的区域中。例如,通用编号 (world-wide number, WWN) 是设备提供的唯一 ID。例如,设备 NVRAM 和保留扇区是不可访问区域,主机生成的唯一 ID 可以安全地存储在此区域中。

注册设备 ID

通常,驱动程序在其 attach(9E) 处理程序中初始化和注册设备 ID。如上所述,驱动程序负责注册永久设备 ID。同时,驱动程序可能需要处理可直接提供唯一 ID (WWN) 的设备和向稳定存储器写入及从稳定存储器读取虚构 ID 的设备。

注册设备提供的 ID

如果设备可以为驱动程序提供唯一的标识符,则驱动程序可以直接使用此标识符初始化设备 ID 并使用 Solaris DDI 注册此 ID。

/*
 * The device provides a guaranteed unique identifier,
 * in this case a SCSI3-WWN.  The WWN for the device has been
 * stored in the device's soft state.
 */
if (ddi_devid_init(dip, DEVID_SCSI3_WWN, un->un_wwn_len, un->un_wwn,
    &un->un_devid) != DDI_SUCCESS)
    return (DDI_FAILURE);

(void) ddi_devid_register(dip, un->un_devid);

注册虚构 ID

驱动程序还可能为不直接提供唯一 ID 的设备注册设备 ID。注册这些 ID 需要设备能够存储并检索保留区中的少量数据。随后,驱动程序可创建虚构设备 ID 并将其写入保留区中。

/*
 * the device doesn't supply a unique ID, attempt to read
 * a fabricated ID from the device's reserved data.
 */

if (xxx_read_deviceid(un, &devid_buf) == XXX_OK) {
    if (ddi_devid_valid(devid_buf) == DDI_SUCCESS) {
        devid_sz = ddi_devi_sizeof(devid_buf);
        un->un_devid = kmem_alloc(devid_sz, KM_SLEEP);
        bcopy(devid_buf, un->un_devid, devid_sz);
        ddi_devid_register(dip, un->un_devid);
        return (XXX_OK);
    }
}

/*
 * we failed to read a valid device ID from the device
 * fabricate an ID, store it on the device, and register
 * it with the DDI
 */

if (ddi_devid_init(dip, DEVID_FAB, 0, NULL, &un->un_devid)
    == DDI_FAILURE) {
    return (XXX_FAILURE);
}

if (xxx_write_deviceid(un) != XXX_OK) {
    ddi_devid_free(un->un_devid);
    un->un_devid = NULL;
    return (XXX_FAILURE);
}

ddi_devid_register(dip, un->un_devid);
return (XXX_OK);

注销设备 ID

通常,驱动程序会注销并释放处理 detach(9E) 时分配的所有设备 ID。驱动程序首先调用 ddi_devid_unregister(9F) 来注销设备实例的设备 ID。然后,驱动程序必须通过调用 ddi_devid_free(9F) 并传送已由 ddi_devid_init(9F) 返回的句柄来释放设备 ID 句柄自身。驱动程序负责管理为 WWN 或序列号数据分配的任何空间。