/drivers/media/video/videobuf2-dma-contig.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2 · C · 185 lines · 136 code · 38 blank · 11 comment · 9 complexity · 2f16fc4af2606fb66315fc850a6238b8 MD5 · raw file

  1. /*
  2. * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2
  3. *
  4. * Copyright (C) 2010 Samsung Electronics
  5. *
  6. * Author: Pawel Osciak <pawel@osciak.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/slab.h>
  14. #include <linux/dma-mapping.h>
  15. #include <media/videobuf2-core.h>
  16. #include <media/videobuf2-memops.h>
  17. struct vb2_dc_conf {
  18. struct device *dev;
  19. };
  20. struct vb2_dc_buf {
  21. struct vb2_dc_conf *conf;
  22. void *vaddr;
  23. dma_addr_t paddr;
  24. unsigned long size;
  25. struct vm_area_struct *vma;
  26. atomic_t refcount;
  27. struct vb2_vmarea_handler handler;
  28. };
  29. static void vb2_dma_contig_put(void *buf_priv);
  30. static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
  31. {
  32. struct vb2_dc_conf *conf = alloc_ctx;
  33. struct vb2_dc_buf *buf;
  34. buf = kzalloc(sizeof *buf, GFP_KERNEL);
  35. if (!buf)
  36. return ERR_PTR(-ENOMEM);
  37. buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr,
  38. GFP_KERNEL);
  39. if (!buf->vaddr) {
  40. dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
  41. size);
  42. kfree(buf);
  43. return ERR_PTR(-ENOMEM);
  44. }
  45. buf->conf = conf;
  46. buf->size = size;
  47. buf->handler.refcount = &buf->refcount;
  48. buf->handler.put = vb2_dma_contig_put;
  49. buf->handler.arg = buf;
  50. atomic_inc(&buf->refcount);
  51. return buf;
  52. }
  53. static void vb2_dma_contig_put(void *buf_priv)
  54. {
  55. struct vb2_dc_buf *buf = buf_priv;
  56. if (atomic_dec_and_test(&buf->refcount)) {
  57. dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr,
  58. buf->paddr);
  59. kfree(buf);
  60. }
  61. }
  62. static void *vb2_dma_contig_cookie(void *buf_priv)
  63. {
  64. struct vb2_dc_buf *buf = buf_priv;
  65. return &buf->paddr;
  66. }
  67. static void *vb2_dma_contig_vaddr(void *buf_priv)
  68. {
  69. struct vb2_dc_buf *buf = buf_priv;
  70. if (!buf)
  71. return 0;
  72. return buf->vaddr;
  73. }
  74. static unsigned int vb2_dma_contig_num_users(void *buf_priv)
  75. {
  76. struct vb2_dc_buf *buf = buf_priv;
  77. return atomic_read(&buf->refcount);
  78. }
  79. static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
  80. {
  81. struct vb2_dc_buf *buf = buf_priv;
  82. if (!buf) {
  83. printk(KERN_ERR "No buffer to map\n");
  84. return -EINVAL;
  85. }
  86. return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
  87. &vb2_common_vm_ops, &buf->handler);
  88. }
  89. static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
  90. unsigned long size, int write)
  91. {
  92. struct vb2_dc_buf *buf;
  93. struct vm_area_struct *vma;
  94. dma_addr_t paddr = 0;
  95. int ret;
  96. buf = kzalloc(sizeof *buf, GFP_KERNEL);
  97. if (!buf)
  98. return ERR_PTR(-ENOMEM);
  99. ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
  100. if (ret) {
  101. printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
  102. vaddr);
  103. kfree(buf);
  104. return ERR_PTR(ret);
  105. }
  106. buf->size = size;
  107. buf->paddr = paddr;
  108. buf->vma = vma;
  109. return buf;
  110. }
  111. static void vb2_dma_contig_put_userptr(void *mem_priv)
  112. {
  113. struct vb2_dc_buf *buf = mem_priv;
  114. if (!buf)
  115. return;
  116. vb2_put_vma(buf->vma);
  117. kfree(buf);
  118. }
  119. const struct vb2_mem_ops vb2_dma_contig_memops = {
  120. .alloc = vb2_dma_contig_alloc,
  121. .put = vb2_dma_contig_put,
  122. .cookie = vb2_dma_contig_cookie,
  123. .vaddr = vb2_dma_contig_vaddr,
  124. .mmap = vb2_dma_contig_mmap,
  125. .get_userptr = vb2_dma_contig_get_userptr,
  126. .put_userptr = vb2_dma_contig_put_userptr,
  127. .num_users = vb2_dma_contig_num_users,
  128. };
  129. EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
  130. void *vb2_dma_contig_init_ctx(struct device *dev)
  131. {
  132. struct vb2_dc_conf *conf;
  133. conf = kzalloc(sizeof *conf, GFP_KERNEL);
  134. if (!conf)
  135. return ERR_PTR(-ENOMEM);
  136. conf->dev = dev;
  137. return conf;
  138. }
  139. EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx);
  140. void vb2_dma_contig_cleanup_ctx(void *alloc_ctx)
  141. {
  142. kfree(alloc_ctx);
  143. }
  144. EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
  145. MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2");
  146. MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
  147. MODULE_LICENSE("GPL");