第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
14. 分层驱动程序接口 (Layered Driver Interface, LDI)
使用 Oracle Solaris DDI 接口,驱动程序可以提供设备 ID,即设备的永久唯一标识符。设备 ID 可用于识别或查找设备。设备 ID 独立于 /devices 名称或设备编号 (dev_t)。应用程序可以使用 libdevid(3LIB) 中定义的函数来读取和处理由驱动程序注册的设备 ID。
在驱动程序可以导出设备 ID 之前,驱动程序需要检验设备是否可以提供唯一 ID 或者将主机生成的唯一 ID 存储在正常情况下不可访问的区域中。例如,通用编号 (world-wide number, WWN) 是设备提供的唯一 ID。例如,设备 NVRAM 和保留扇区是不可访问区域,主机生成的唯一 ID 可以安全地存储在此区域中。
通常,驱动程序在其 attach(9E) 处理程序中初始化和注册设备 ID。如上所述,驱动程序负责注册永久设备 ID。同时,驱动程序可能需要处理可直接提供唯一 ID (WWN) 的设备和向稳定存储器写入及从稳定存储器读取虚构 ID 的设备。
如果设备可以为驱动程序提供唯一的标识符,则驱动程序可以直接使用此标识符初始化设备 ID 并使用 Oracle 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 并将其写入保留区中。
/* * 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);
通常,驱动程序会注销并释放处理 detach(9E) 时分配的所有设备 ID。驱动程序首先调用 ddi_devid_unregister(9F) 来注销设备实例的设备 ID。然后,驱动程序必须通过调用 ddi_devid_free(9F) 并传送已由 ddi_devid_init(9F) 返回的句柄来释放设备 ID 句柄自身。驱动程序负责管理为 WWN 或序列号数据分配的任何空间。