dma_buf_export

/**
 * DOC: dma buf device access
 *
 * For device DMA access to a shared DMA buffer the usual sequence of operations
 * is fairly simple:
 *
 * 1. The exporter defines his exporter instance using
 *    DEFINE_DMA_BUF_EXPORT_INFO() and calls dma_buf_export() to wrap a private
 *    buffer object into a &dma_buf. It then exports that &dma_buf to userspace
 *    as a file descriptor by calling dma_buf_fd().
 *
 * 2. Userspace passes this file-descriptors to all drivers it wants this buffer
 *    to share with: First the filedescriptor is converted to a &dma_buf using
 *    dma_buf_get(). Then the buffer is attached to the device using
 *    dma_buf_attach().
 *
 *    Up to this stage the exporter is still free to migrate or reallocate the
 *    backing storage.
 *
 * 3. Once the buffer is attached to all devices userspace can initiate DMA
 *    access to the shared buffer. In the kernel this is done by calling
 *    dma_buf_map_attachment() and dma_buf_unmap_attachment().
 *
 * 4. Once a driver is done with a shared buffer it needs to call
 *    dma_buf_detach() (after cleaning up any mappings) and then release the
 *    reference acquired with dma_buf_get by calling dma_buf_put().
 *
 * For the detailed semantics exporters are expected to implement see
 * &dma_buf_ops.
 */

/**
 * dma_buf_export - Creates a new dma_buf, and associates an anon file
 * with this buffer, so it can be exported.
 * Also connect the allocator specific data and ops to the buffer.
 * Additionally, provide a name string for exporter; useful in debugging.
 *
 * @exp_info:    [in]    holds all the export related information provided
 *            by the exporter. see &struct dma_buf_export_info
 *            for further details.
 *
 * Returns, on success, a newly created dma_buf object, which wraps the
 * supplied private data and operations for dma_buf_ops. On either missing
 * ops, or error in allocating struct dma_buf, will return negative error.
 *
 * For most cases the easiest way to create @exp_info is through the
 * %DEFINE_DMA_BUF_EXPORT_INFO macro.
 */
struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
{
    struct dma_buf *dmabuf;
    struct dma_resv *resv = exp_info->resv;
    struct file *file;
    size_t alloc_size = sizeof(struct dma_buf);
    int ret;

    if (!exp_info->resv)
        alloc_size += sizeof(struct dma_resv);
    else
        /* prevent &dma_buf[1] == dma_buf->resv */
        alloc_size += 1;

    if (WARN_ON(!exp_info->priv
              || !exp_info->ops
              || !exp_info->ops->map_dma_buf
              || !exp_info->ops->unmap_dma_buf
              || !exp_info->ops->release)) {
        return ERR_PTR(-EINVAL);
    }

    if (!try_module_get(exp_info->owner))
        return ERR_PTR(-ENOENT);

    dmabuf = kzalloc(alloc_size, GFP_KERNEL);
    if (!dmabuf) {
        ret = -ENOMEM;
        goto err_module;
    }

    dmabuf->priv = exp_info->priv;
    dmabuf->ops = exp_info->ops;
    dmabuf->size = exp_info->size;
    dmabuf->exp_name = exp_info->exp_name;
    dmabuf->owner = exp_info->owner;
    spin_lock_init(&dmabuf->name_lock);
    init_waitqueue_head(&dmabuf->poll);
    dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll;
    dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;

    if (!resv) {
        resv = (struct dma_resv *)&dmabuf[1];
        dma_resv_init(resv);
    }
    dmabuf->resv = resv;

    file = dma_buf_getfile(dmabuf, exp_info->flags);
    if (IS_ERR(file)) {
        ret = PTR_ERR(file);
        goto err_dmabuf;
    }

    file->f_mode |= FMODE_LSEEK;
    dmabuf->file = file;

    mutex_init(&dmabuf->lock);
    INIT_LIST_HEAD(&dmabuf->attachments);

    mutex_lock(&db_list.lock);
    list_add(&dmabuf->list_node, &db_list.head);
    mutex_unlock(&db_list.lock);

    return dmabuf;

err_dmabuf:
    kfree(dmabuf);
err_module:
    module_put(exp_info->owner);
    return ERR_PTR(ret);

static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
{
    struct file *file;
    struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb);

    if (IS_ERR(inode))
        return ERR_CAST(inode);

    inode->i_size = dmabuf->size;
    inode_set_bytes(inode, dmabuf->size);

    file = alloc_file_pseudo(inode, dma_buf_mnt, "dmabuf",
                 flags, &dma_buf_fops);
    if (IS_ERR(file))
        goto err_alloc_file;
    file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
    file->private_data = dmabuf;
    file->f_path.dentry->d_fsdata = dmabuf;

    return file;

err_alloc_file:
    iput(inode);
    return file;
}

static const struct file_operations dma_buf_fops = {
    .release    = dma_buf_file_release,
    .mmap        = dma_buf_mmap_internal,
    .llseek        = dma_buf_llseek,
    .poll        = dma_buf_poll,
    .unlocked_ioctl    = dma_buf_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl    = dma_buf_ioctl,
#endif
    .show_fdinfo    = dma_buf_show_fdinfo,
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值