ZBLOG

使用dma_alloc_coherent接口编写一个简单的读写内存的驱动接口范例

下面是一个使用 dma_alloc_coherent 接口的简单 Linux 驱动示例,该驱动实现了基本的读写功能,能够通过字符设备接口与用户空间进行交互。该示例展示了如何在驱动中分配 DMA 一致性内存,并提供给用户空间读写操作。

示例:DMA 读写内存的字符设备驱动

1. 驱动头文件和模块信息

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>

#define DEVICE_NAME "my_dma_device"
#define BUFFER_SIZE 1024

static int major_number;
static void *dma_buffer;
static dma_addr_t dma_handle;

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple DMA coherent memory example with read/write support");

2. 打开、关闭、读取和写入函数

static int my_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device opened\n");
    return 0;
}

static int my_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device closed\n");
    return 0;
}

ssize_t my_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_buffer + *offset, count))
        return -EFAULT;

    *offset += count;
    return count; // 返回实际读取的字节数
}

ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) {
    if (*offset >= BUFFER_SIZE)
        return -ENOSPC; // No space left on device
    
    if (*offset + count > BUFFER_SIZE)
        count = BUFFER_SIZE - *offset;

    if (copy_from_user(dma_buffer + *offset, buf, count))
        return -EFAULT;

    *offset += count;
    return count; // 返回实际写入的字节数
}

3. 文件操作结构体

static struct file_operations fops = {
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
};

4. 初始化和清理模块

static int __init my_init(void) {
    // 注册字符设备
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register device: %d\n", major_number);
        return major_number;
    }

    // 分配DMA一致性内存
    dma_buffer = dma_alloc_coherent(NULL, BUFFER_SIZE, &dma_handle, GFP_KERNEL);
    
   if (!dma_buffer) {
       unregister_chrdev(major_number, DEVICE_NAME);
       printk(KERN_ALERT "Failed to allocate DMA buffer\n");
       return -ENOMEM;
   }

   memset(dma_buffer, 0, BUFFER_SIZE); // 清空缓冲区
   
   printk(KERN_INFO "DMA buffer allocated at %p with handle %pad\n", dma_buffer, &dma_handle);

   return 0; 
}

static void __exit my_exit(void) {
   // 释放DMA一致性内存
   if (dma_buffer)
       dma_free_coherent(NULL, BUFFER_SIZE, dma_buffer, dma_handle);

   // 注销字符设备
   unregister_chrdev(major_number, DEVICE_NAME);
   
   printk(KERN_INFO "Device unregistered and DMA buffer freed\n");
}

5. 模块入口和出口函数

module_init(my_init);
module_exit(my_exit);

编译与加载模块

创建一个 Makefile 来编译这个模块:

obj-m += my_dma_device.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 my_dma_device.ko   # 加载模块
dmesg         # 查看内核日志以确认成功加载以及分配情况 
sudo rmmod my_dma_device     # 卸载模块 
make clean   # 清理生成文件 

测试驱动程序的读写功能

可以编写一个简单的用户空间程序来测试该驱动。下面是一个 C 程序示例,用于打开设备,向其写入数据,然后读取数据。

用户空间测试代码示例:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define DEVICE_PATH "/dev/my_dma_device"

int main() {
   int fd = open(DEVICE_PATH, O_RDWR);
   
   if (fd < 0) {
       perror("Failed to open the device");
       return -1;
   }

   const char* write_data = "Hello from user space!";
   
   write(fd , write_data , strlen(write_data)); // 写数据到设备
   
   char read_data[1024] = {0};
   
   lseek(fd , 0 , SEEK_SET);      // 移动到文件开始位置,准备读取数据
   
   read(fd , read_data , sizeof(read_data)); // 从设备读取数据
   
   printf("Read from device: %s\n", read_data); 

   close(fd);  
   
   return 0;
}

总结

上述代码演示了如何使用 dma_alloc_coherent 在 Linux 驱动程序中分配 DMA 一致性内存,并实现简单的读写功能。请根据具体需求进行必要的错误处理和调整。在实际应用中,还需要考虑线程安全、同步等问题。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=6287

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?