编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

将设备内存与用户映射相关联

通过驱动程序的 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);

其中:

handle

系统用来标识映射的不透明的设备映射句柄。

dip

指向设备的 dev_info 结构的指针。

callbackops

指向 devmap_callback_ctl(9S) 结构的指针,此指针可在映射时向驱动程序通知用户事件。

rnumber

寄存器地址空间集的索引号。

roff

在设备内存中的偏移。

len

导出的长度(字节)。

maxprot

允许驱动程序为导出的设备内存中的不同区域指定不同的保护。

flags

必须设置为 DEVMAP_DEFAULTS

accattrp

指向 ddi_device_acc_attr(9S) 结构的指针。

rofflen 参数描述了寄存器集 rnumber 指定的设备内存中的一个范围。reg 属性用于描述 rnumber 所引用的寄存器规格。对于只有一个寄存器集的设备,将 rnumber 设置为 0 即可。范围通过 rofflen 定义。如果用户的应用程序映射位于通过 devmap(9E) 入口点传入的 offset 位置上,则可对此范围进行访问。驱动程序通常将 devmap(9E) 偏移直接传递给 devmap_devmem_setup(9F)。然后,mmap(2) 的返回地址将映射到寄存器集的起始地址。

通过 maxprot 参数,驱动程序可为导出的设备内存中的不同区域指定不同保护。例如,要禁止对某个区域进行写访问,可以只为该区域设置 PROT_READPROT_USER

以下示例说明如何将设备内存导出到应用程序。驱动程序首先确定请求的映射是否位于设备内存区域之内。设备内存的大小通过使用 ddi_dev_regsize(9F) 来确定。使用 ptob(9F)btopr(9F) 可将映射的长度向上舍入为页面大小的倍数。然后调用 devmap_devmem_setup(9F) 可将设备内存导出到应用程序。

示例 10-3  使用 devmap_devmem_setup() 例程
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, &regsize) != 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);
}