cma.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #include <linux/miscdevice.h>
  2. #include <linux/module.h>
  3. #include <linux/dma-map-ops.h>
  4. #define CMA_ALLOC _IOWR('Z', 0, u32)
  5. static unsigned long cma_size = 0;
  6. static struct page *cma_page = NULL;
  7. static struct page **cma_pages = NULL;
  8. static void cma_free(void)
  9. {
  10. if(cma_pages)
  11. {
  12. kfree(cma_pages);
  13. cma_pages = NULL;
  14. }
  15. if(cma_page)
  16. {
  17. dma_release_from_contiguous(NULL, cma_page, cma_size);
  18. cma_page = NULL;
  19. }
  20. }
  21. static long cma_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  22. {
  23. int i;
  24. long rc;
  25. u32 buffer;
  26. if(cmd != CMA_ALLOC) return -ENOTTY;
  27. rc = copy_from_user(&buffer, (void __user *)arg, sizeof(buffer));
  28. if(rc) return rc;
  29. cma_free();
  30. cma_size = PAGE_ALIGN(buffer) >> PAGE_SHIFT;
  31. cma_pages = kmalloc_array(cma_size, sizeof(struct page *), GFP_KERNEL);
  32. if(!cma_pages) return -ENOMEM;
  33. cma_page = dma_alloc_from_contiguous(NULL, cma_size, 0, false);
  34. if(!cma_page)
  35. {
  36. cma_free();
  37. return -ENOMEM;
  38. }
  39. for(i = 0; i < cma_size; ++i) cma_pages[i] = &cma_page[i];
  40. buffer = page_to_phys(cma_page);
  41. return copy_to_user((void __user *)arg, &buffer, sizeof(buffer));
  42. }
  43. static int cma_mmap(struct file *file, struct vm_area_struct *vma)
  44. {
  45. if(!cma_pages) return -ENXIO;
  46. vm_flags_set(vma, VM_MIXEDMAP);
  47. return vm_map_pages(vma, cma_pages, cma_size);
  48. }
  49. static int cma_release(struct inode *inode, struct file *file)
  50. {
  51. cma_free();
  52. return 0;
  53. }
  54. static struct file_operations cma_fops =
  55. {
  56. .unlocked_ioctl = cma_ioctl,
  57. .mmap = cma_mmap,
  58. .release = cma_release
  59. };
  60. struct miscdevice cma_device =
  61. {
  62. .minor = MISC_DYNAMIC_MINOR,
  63. .name = "cma",
  64. .fops = &cma_fops
  65. };
  66. static int __init cma_init(void)
  67. {
  68. return misc_register(&cma_device);
  69. }
  70. static void __exit cma_exit(void)
  71. {
  72. cma_free();
  73. misc_deregister(&cma_device);
  74. }
  75. module_init(cma_init);
  76. module_exit(cma_exit);
  77. MODULE_LICENSE("MIT");