第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
使用 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 或序列号数据分配的任何空间。