下面是一个简易的 Linux 驱动程序示例,使用 dma_alloc_coherent()
分配 DMA 一致性内存,并不依赖于 platform 总线。这种情况下,我们可以使用字符设备驱动来实现。
示例代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/dma-mapping.h>
#define DEVICE_NAME "simple_dma_char"
#define BUFFER_SIZE 1024
struct simple_dma_device {
char *cpu_addr; // CPU可访问的内存地址
dma_addr_t dma_handle; // 设备可访问的DMA地址
struct cdev cdev; // 字符设备结构体
};
static struct simple_dma_device *dma_dev;
static int major_number;
// 打开设备
static int simple_dma_open(struct inode *inode, struct file *file) {
return 0;
}
// 释放设备
static int simple_dma_release(struct inode *inode, struct file *file) {
return 0;
}
// 从设备读取数据
static ssize_t simple_dma_read(struct file *file, char __user *buf, size_t count, loff_t *offset) {
if (*offset >= BUFFER_SIZE) {
return 0; // EOF
}
if (*offset + count > BUFFER_SIZE) {
count = BUFFER_SIZE - *offset;
}
if (copy_to_user(buf, dma_dev->cpu_addr + *offset, count)) {
return -EFAULT;
}
*offset += count;
return count;
}
// 向设备写入数据
static ssize_t simple_dma_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) {
if (*offset >= BUFFER_SIZE) {
return 0; // EOF
}
if (*offset + count > BUFFER_SIZE) {
count = BUFFER_SIZE - *offset;
}
if (copy_from_user(dma_dev->cpu_addr + *offset, buf, count)) {
return -EFAULT;
}
*offset += count;
return count;
}
// 文件操作结构体
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = simple_dma_open,
.release = simple_dma_release,
.read = simple_dma_read,
.write = simple_dma_write,
};
// 模块初始化函数
static int __init simple_dma_init(void) {
major_number = register_chrdev(0, DEVICE_NAME, &fops);
if (major_number < 0) {
printk(KERN_ALERT "Failed to register character device\n");
return major_number;
}
dma_dev = kmalloc(sizeof(struct simple_dma_device), GFP_KERNEL);
if (!dma_dev) {
unregister_chrdev(major_number, DEVICE_NAME);
printk(KERN_ALERT "Failed to allocate memory for device\n");
return -ENOMEM;
}
// 分配一致性DMA内存
dma_dev->cpu_addr = dma_alloc_coherent(NULL, BUFFER_SIZE, &dma_dev->dma_handle, GFP_KERNEL);
if (!dma_dev->cpu_addr) {
kfree(dma_dev);
unregister_chrdev(major_number, DEVICE_NAME);
printk(KERN_ALERT "Failed to allocate coherent DMA memory\n");
return -ENOMEM;
}
memset(dma_dev->cpu_addr, 0, BUFFER_SIZE); // 初始化为零
printk(KERN_INFO "Simple DMA driver initialized with major number %d\n", major_number);
return 0;
}
// 模块退出函数
static void __exit simple_dma_exit(void) {
if (dma_dev && dma_dev->cpu_addr) {
dma_free_coherent(NULL, BUFFER_SIZE, dma_dev->cpu_addr, dma_dev->dma_handle);
kfree(dma_dev);
}
unregister_chrdev(major_number, DEVICE_NAME);
}
module_init(simple_dma_init);
module_exit(simple_dma_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A Simple Character Device Driver using DMA Alloc Coherent");
编译与加载
- 将上述代码保存到文件
simple_dma_char.c
中。 - 创建一个
Makefile
:
obj-m += simple_dma_char.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
- 编译模块:
make
- 加载模块:
sudo insmod simple_dma_char.ko
- 查看日志以确认输出:
dmesg | tail -n 20
- 创建设备节点:
sudo mknod /dev/simple_dma_char c [major_number] 0 # 将 [major_number] 替换为实际的主设备号,如 'cat /proc/devices'
- 使用
echo
和cat
命令进行读写测试:
# 写入数据(例如:hello)
echo "hello" > /dev/simple_dma_char
# 从设备读取数据并打印出来
cat /dev/simple_dma_char
- 卸载模块:
sudo rmmod simple_dmа_char
注意事项
- 上述驱动是一个基本示例,演示了如何创建字符设备并使用
dma_alloc_coherent()
。 - 请根据需要扩展和修改该驱动,以满足您的具体要求和硬件环境。
- 确保处理好错误情况以及多线程环境下的数据安全。
内容由零声教学AI助手提供,问题来源于学员提问