怎样在内核中编写一个简单的字符设备驱动?

超级礼物 2025-04-17 10:33:23

怎样在内核中编写一个简单的字符设备驱动?

...全文
225 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

在Linux内核中编写一个简单的字符设备驱动,通常需要以下几个步骤:

1. 分配设备号

字符设备驱动需要有一个设备号来标识,设备号分为主设备号和次设备号。主设备号用于标识驱动程序,次设备号用于标识该驱动管理的不同设备。

2. 定义文件操作结构体

文件操作结构体定义了用户空间对设备进行读写等操作时内核需要调用的函数。

3. 注册字符设备驱动

将定义好的文件操作结构体和设备号注册到内核中。

4. 实现文件操作函数

实现文件操作结构体中定义的函数,如 openreadwrite 等。

5. 卸载驱动

在驱动卸载时,需要释放分配的资源,如注销字符设备驱动、释放设备号等。

以下是一个简单的字符设备驱动示例代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "simple_char_driver"
#define BUFFER_SIZE 1024

static int major_number;
static char buffer[BUFFER_SIZE];
static int buffer_length = 0;

// 定义文件操作结构体
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = device_read,
    .write = device_write,
    .open = device_open,
    .release = device_release,
};

// 打开设备
static int device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device opened\n");
    return 0;
}

// 读取设备
static ssize_t device_read(struct file *filp, char __user *buffer_user, size_t count, loff_t *offset) {
    int bytes_to_copy = min(buffer_length, (int)count);
    if (copy_to_user(buffer_user, buffer, bytes_to_copy)) {
        return -EFAULT;
    }
    buffer_length = 0;
    return bytes_to_copy;
}

// 写入设备
static ssize_t device_write(struct file *filp, const char __user *buffer_user, size_t count, loff_t *offset) {
    int bytes_to_copy = min(BUFFER_SIZE - buffer_length, (int)count);
    if (copy_from_user(buffer + buffer_length, buffer_user, bytes_to_copy)) {
        return -EFAULT;
    }
    buffer_length += bytes_to_copy;
    return bytes_to_copy;
}

// 关闭设备
static int device_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device closed\n");
    return 0;
}

// 模块初始化函数
static int __init simple_char_driver_init(void) {
    // 动态分配主设备号
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register device\n");
        return major_number;
    }
    printk(KERN_INFO "Device registered with major number %d\n", major_number);
    return 0;
}

// 模块退出函数
static void __exit simple_char_driver_exit(void) {
    // 注销字符设备驱动
    unregister_chrdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "Device unregistered\n");
}

module_init(simple_char_driver_init);
module_exit(simple_char_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device driver");

代码解释

  1. 设备号分配:使用 register_chrdev 函数动态分配主设备号。
  2. 文件操作结构体:定义了 fops 结构体,包含了 openreadwriterelease 函数。
  3. 文件操作函数:实现了 device_opendevice_readdevice_writedevice_release 函数,分别处理设备的打开、读取、写入和关闭操作。
  4. 模块初始化和退出simple_char_driver_init 函数在模块加载时被调用,注册字符设备驱动;simple_char_driver_exit 函数在模块卸载时被调用,注销字符设备驱动。

编译和加载驱动

  1. 创建一个 Makefile 文件:
    ```makefile
    obj-m += simple_char_driver.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

2. 编译驱动:
```bash
make
  1. 加载驱动:

    sudo insmod simple_char_driver.ko
    
  2. 创建设备节点:

    sudo mknod /dev/simple_char_driver c <major_number> 0
    

    其中 <major_number> 是驱动加载时分配的主设备号。

  3. 卸载驱动:

    sudo rmmod simple_char_driver
    

通过以上步骤,你就可以在内核中编写并加载一个简单的字符设备驱动。

2,856

社区成员

发帖
与我相关
我的任务
社区描述
本论坛以AI、WoS 、XR、IoT、Auto、生成式AI等核心板块组成,为开发者提供便捷及高效的学习和交流平台。 高通开发者专区主页:https://qualcomm.csdn.net/
人工智能物联网机器学习 技术论坛(原bbs) 北京·东城区
社区管理员
  • csdnsqst0050
  • chipseeker
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧