dma-buf: add release callback support
authorMark Yao <mark.yao@rock-chips.com>
Mon, 20 Mar 2017 01:46:47 +0000 (09:46 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Thu, 23 Mar 2017 10:19:48 +0000 (18:19 +0800)
Change-Id: Ibfb4ffe3d97fae0a27f20032fdfbc3cc561aa375
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/dma-buf/dma-buf.c
include/linux/dma-buf.h

index 155c1464948e7ad02f885302754353725775b3be..15c0fbc817a54540d944f44e434d3699e22ff599 100644 (file)
 
 static inline int is_dma_buf_file(struct file *);
 
+struct dma_buf_callback {
+       struct list_head list;
+       void (*callback)(void *);
+       void *data;
+};
+
 struct dma_buf_list {
        struct list_head head;
        struct mutex lock;
@@ -46,6 +52,7 @@ static struct dma_buf_list db_list;
 static int dma_buf_release(struct inode *inode, struct file *file)
 {
        struct dma_buf *dmabuf;
+       struct dma_buf_callback *cb, *tmp;
 
        if (!is_dma_buf_file(file))
                return -EINVAL;
@@ -64,6 +71,13 @@ static int dma_buf_release(struct inode *inode, struct file *file)
         */
        BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active);
 
+       list_for_each_entry_safe(cb, tmp, &dmabuf->release_callbacks, list) {
+               if (cb->callback)
+                       cb->callback(cb->data);
+               list_del(&cb->list);
+               kfree(cb);
+       }
+
        dmabuf->ops->release(dmabuf);
 
        mutex_lock(&db_list.lock);
@@ -266,6 +280,37 @@ static inline int is_dma_buf_file(struct file *file)
        return file->f_op == &dma_buf_fops;
 }
 
+int dma_buf_set_release_callback(struct dma_buf *dmabuf,
+                                void (*callback)(void *), void *data)
+{
+       struct dma_buf_callback *cb;
+
+       if (WARN_ON(dma_buf_get_release_callback_data(dmabuf, callback)))
+               return -EINVAL;
+
+       cb = kzalloc(sizeof(*cb), GFP_KERNEL);
+       if (!cb)
+               return -ENOMEM;
+       cb->callback = callback;
+       cb->data = data;
+       list_add_tail(&cb->list, &dmabuf->release_callbacks);
+
+       return 0;
+}
+
+void *dma_buf_get_release_callback_data(struct dma_buf *dmabuf,
+                                       void (*callback)(void *))
+{
+       struct dma_buf_callback *cb, *tmp;
+
+       list_for_each_entry_safe(cb, tmp, &dmabuf->release_callbacks, list) {
+               if (cb->callback == callback)
+                       return cb->data;
+       }
+
+       return NULL;
+}
+
 /**
  * dma_buf_export - Creates a new dma_buf, and associates an anon file
  * with this buffer, so it can be exported.
@@ -341,6 +386,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
 
        mutex_init(&dmabuf->lock);
        INIT_LIST_HEAD(&dmabuf->attachments);
+       INIT_LIST_HEAD(&dmabuf->release_callbacks);
 
        mutex_lock(&db_list.lock);
        list_add(&dmabuf->list_node, &db_list.head);
index f98bd7068d55a3f4ddfdb50dc01d95909ab30f45..d58bd33d643576ae7347ae6ac58b5ff8685762fe 100644 (file)
@@ -90,6 +90,9 @@ struct dma_buf_ops {
         * if the call would block.
         */
 
+       int (*set_release_callback)(void (*release_callback)(void *data),
+                                   void *data);
+       void *(*get_release_callback_data)(void *callback);
        /* after final dma_buf_put() */
        void (*release)(struct dma_buf *);
 
@@ -125,6 +128,7 @@ struct dma_buf {
        size_t size;
        struct file *file;
        struct list_head attachments;
+       struct list_head release_callbacks;
        const struct dma_buf_ops *ops;
        /* mutex to serialize list manipulation, attach/detach and vmap/unmap */
        struct mutex lock;
@@ -209,6 +213,12 @@ static inline void get_dma_buf(struct dma_buf *dmabuf)
        get_file(dmabuf->file);
 }
 
+int dma_buf_set_release_callback(struct dma_buf *dmabuf,
+                                void (*callback)(void *), void *data);
+
+void *dma_buf_get_release_callback_data(struct dma_buf *dmabuf,
+                                       void (*callback)(void *));
+
 struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
                                                        struct device *dev);
 void dma_buf_detach(struct dma_buf *dmabuf,