通过驱动程序的 devmap(9E) 入口点调用 devmap_devmem_setup(9F) 可将设备内存导出到用户应用程序。
devmap_devmem_setup(9F) 函数的语法如下所示:
int devmap_devmem_setup(devmap_cookie_t handle, dev_info_t *dip, struct devmap_callback_ctl *callbackops, uint_t rnumber, offset_t roff, size_t len, uint_t maxprot, uint_t flags, ddi_device_acc_attr_t *accattrp);
其中:
系统用来标识映射的不透明的设备映射句柄。
指向设备的 dev_info 结构的指针。
指向 devmap_callback_ctl(9S) 结构的指针,此指针可在映射时向驱动程序通知用户事件。
寄存器地址空间集的索引号。
在设备内存中的偏移。
导出的长度(以字节为单位)。
允许驱动程序为导出的设备内存中的不同区域指定不同的保护。
必须设置为 DEVMAP_DEFAULTS。
指向 ddi_device_acc_attr(9S) 结构的指针。
roff 和 len 参数描述了寄存器集 rnumber 指定的设备内存中的一个范围。reg 属性用于描述 rnumber 所引用的寄存器规格。对于只有一个寄存器集的设备,将 rnumber 设置为 0 即可。范围通过 roff 和 len 定义。如果用户的应用程序映射位于通过 devmap(9E) 入口点传入的 offset 位置上,则可对此范围进行访问。驱动程序通常将 devmap(9E) 偏移直接传递给 devmap_devmem_setup(9F)。然后,mmap(2) 的返回地址将映射到寄存器集的起始地址。
通过 maxprot 参数,驱动程序可为导出的设备内存中的不同区域指定不同保护。例如,要禁止对某个区域进行写访问,可以只为该区域设置 PROT_READ 和 PROT_USER。
以下示例说明如何将设备内存导出到应用程序。驱动程序首先确定请求的映射是否位于设备内存区域之内。设备内存的大小通过使用 ddi_dev_regsize(9F) 来确定。使用 ptob(9F) 和 btopr(9F) 可将映射的长度向上舍入为页面大小的倍数。然后调用 devmap_devmem_setup(9F) 可将设备内存导出到应用程序。
static int xxdevmap(dev_t dev, devmap_cookie_t handle, offset_t off, size_t len, size_t *maplen, uint_t model) { struct xxstate *xsp; int error, rnumber; off_t regsize; /* Set up data access attribute structure */ struct ddi_device_acc_attr xx_acc_attr = { DDI_DEVICE_ATTR_V0, DDI_NEVERSWAP_ACC, DDI_STRICTORDER_ACC }; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (-1); /* use register set 0 */ rnumber = 0; /* get size of register set */ if (ddi_dev_regsize(xsp->dip, rnumber, ®size) != DDI_SUCCESS) return (-1); /* round up len to a multiple of a page size */ len = ptob(btopr(len)); if (off + len > regsize) return (-1); /* Set up the device mapping */ error = devmap_devmem_setup(handle, xsp->dip, NULL, rnumber, off, len, PROT_ALL, DEVMAP_DEFAULTS, &xx_acc_attr); /* acknowledge the entire range */ *maplen = len; return (error); }