@@ -124,6 +124,92 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
return base + offset;
}
+static ssize_t dma_buf_read(struct file *file,
+ char __user *ubuf, size_t remain,
+ loff_t *offset)
+{
+ struct dma_buf *dmabuf = file->private_data;
+ unsigned long idx;
+ unsigned int start;
+ size_t written;
+
+ if (!is_dma_buf_file(file))
+ return -EBADF;
+
+ written = 0;
+ idx = *offset >> PAGE_SHIFT;
+ start = offset_in_page(*offset);
+ while (remain) {
+ unsigned int len = min_t(size_t, remain, PAGE_SIZE - start);
+ unsigned int copied;
+ void *vaddr;
+
+ vaddr = dma_buf_kmap(dmabuf, idx);
+ if (!vaddr)
+ return written ?: -EIO;
+
+ copied = copy_to_user(vaddr, ubuf, len);
+ dma_buf_kunmap(dmabuf, idx, vaddr);
+
+ written += copied ?: len;
+ if (copied) {
+ *offset += copied;
+ return written ?: -EFAULT;
+ }
+
+ remain -= len;
+ *offset += len;
+ ubuf += len;
+ start = 0;
+ idx++;
+ }
+
+ return written;
+}
+
+static ssize_t dma_buf_write(struct file *file,
+ const char __user *ubuf, size_t remain,
+ loff_t *offset)
+{
+ struct dma_buf *dmabuf = file->private_data;
+ unsigned long idx;
+ unsigned int start;
+ size_t written;
+
+ if (!is_dma_buf_file(file))
+ return -EBADF;
+
+ written = 0;
+ idx = *offset >> PAGE_SHIFT;
+ start = offset_in_page(*offset);
+ while (remain) {
+ unsigned int len = min_t(size_t, remain, PAGE_SIZE - start);
+ unsigned int copied;
+ void *vaddr;
+
+ vaddr = dma_buf_kmap(dmabuf, idx);
+ if (!vaddr)
+ return written ?: -EIO;
+
+ copied = copy_from_user(vaddr, ubuf, len);
+ dma_buf_kunmap(dmabuf, idx, vaddr);
+
+ written += copied ?: len;
+ if (copied) {
+ *offset += copied;
+ return written ?: -EFAULT;
+ }
+
+ remain -= len;
+ *offset += len;
+ ubuf += len;
+ start = 0;
+ idx++;
+ }
+
+ return written;
+}
+
/**
* DOC: fence polling
*
@@ -318,6 +404,8 @@ static const struct file_operations dma_buf_fops = {
.release = dma_buf_release,
.mmap = dma_buf_mmap_internal,
.llseek = dma_buf_llseek,
+ .read = dma_buf_read,
+ .write = dma_buf_write,
.poll = dma_buf_poll,
.unlocked_ioctl = dma_buf_ioctl,
#ifdef CONFIG_COMPAT
It is expected that processes will pass dma-buf fd between drivers, and only using the fd themselves for mmaping and synchronisation ioctls. However, it may be convenient for an application to read/write into the dma-buf, for instance a test case to check the internal dma_buf->ops->kmap interface. There may also be a small advantage to avoiding the mmap() for very simple/small operations. Note in particular, synchronisation with the device is left to the caller with an explicit DMA_BUF_IOCTL_SYNC, rather than done implicitly inside the read/write, so that the user can avoid synchronisation if they so choose. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Laura Abbott <labbott@redhat.com> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Sean Paul <seanpaul@chromium.org> --- drivers/dma-buf/dma-buf.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)