在Linux内核中,dma_alloc_contiguous
是用于分配连续的DMA物理内存的一种接口。不过,实际使用中,我们通常会看到的是 dma_alloc_coherent
函数,它提供了更高层次的抽象,并适用于大多数场景。
以下是一个使用 dma_alloc_coherent
的示例代码,这个代码展示了如何在Linux设备驱动中分配和释放DMA缓冲区:
示例代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
struct my_device {
void *virt_addr; // 虚拟地址
dma_addr_t phys_addr; // 物理地址
size_t size; // 分配大小
};
static struct my_device *my_dev;
static int __init my_driver_init(void) {
// 分配设备结构体
my_dev = kmalloc(sizeof(struct my_device), GFP_KERNEL);
if (!my_dev) {
pr_err("Failed to allocate memory for device structure\n");
return -ENOMEM;
}
// 设置要分配的DMA缓冲区大小(例如:1MB)
my_dev->size = 1024 * 1024;
// 分配连续DMA内存
my_dev->virt_addr = dma_alloc_coherent(NULL, my_dev->size,
&my_dev->phys_addr,
GFP_KERNEL);
if (!my_dev->virt_addr) {
pr_err("Failed to allocate DMA coherent memory\n");
kfree(my_dev);
return -ENOMEM;
}
pr_info("Allocated %zu bytes of DMA memory at virtual address: %p, physical address: %pad\n",
my_dev->size, my_dev->virt_addr, &my_dev->phys_addr);
return 0;
}
static void __exit my_driver_exit(void) {
if (my_dev && my_dev->virt_addr) {
// 释放DMA内存
dma_free_coherent(NULL, my_dev->size,
my_dev->virt_addr,
my_dev->phys_addr);
pr_info("Freed DMA memory\n");
}
kfree(my_dev);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple example of using dma_alloc_coherent");
MODULE_AUTHOR("Your Name");
代码说明
头文件包含:
- 包含必要的头文件,如
module.h
、kernel.h
、dma-mapping.h
和slab.h
。
- 包含必要的头文件,如
定义设备结构体:
struct my_device
定义了一个简单的设备结构体,包含虚拟地址、物理地址和分配大小。
初始化函数 (
my_driver_init
):- 使用
kmalloc()
分配设备结构体。 - 设置想要分配的DMA缓冲区大小(如1MB)。
- 使用
dma_alloc_coherent()
函数申请连续的DMA内存,并获取其虚拟地址和物理地址。如果失败,则释放已分配资源并返回错误。
- 使用
退出函数 (
my_driver_exit
):- 在模块卸载时,如果已经分配了DMA内存,则调用
dma_free_coherent()
释放它,并打印日志信息。 - 最后释放设备结构体。
- 在模块卸载时,如果已经分配了DMA内存,则调用
模块宏:
- 使用
module_init()
和module_exit()
来指定驱动程序加载和卸载时的函数。
- 使用
注意事项
- 确保在你的开发环境中,相关驱动框架正确安装,并且这个模块与目标硬件兼容。
- 在实际情况中,你应该根据需要传入合适的参数来替代这里示例中的 NULL 指针(例如,与硬件相关的信息)。
- 请遵循 Linux 内核编程的最佳实践,在不同上下文中使用这些API时注意可能发生的问题。
内容由零声教学AI助手提供,问题来源于学员提问