2,856
社区成员




在Linux内核中编写一个简单的字符设备驱动,通常需要以下几个步骤:
字符设备驱动需要有一个设备号来标识,设备号分为主设备号和次设备号。主设备号用于标识驱动程序,次设备号用于标识该驱动管理的不同设备。
文件操作结构体定义了用户空间对设备进行读写等操作时内核需要调用的函数。
将定义好的文件操作结构体和设备号注册到内核中。
实现文件操作结构体中定义的函数,如 open
、read
、write
等。
在驱动卸载时,需要释放分配的资源,如注销字符设备驱动、释放设备号等。
以下是一个简单的字符设备驱动示例代码:
#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");
register_chrdev
函数动态分配主设备号。fops
结构体,包含了 open
、read
、write
和 release
函数。device_open
、device_read
、device_write
和 device_release
函数,分别处理设备的打开、读取、写入和关闭操作。simple_char_driver_init
函数在模块加载时被调用,注册字符设备驱动;simple_char_driver_exit
函数在模块卸载时被调用,注销字符设备驱动。Makefile
文件: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
加载驱动:
sudo insmod simple_char_driver.ko
创建设备节点:
sudo mknod /dev/simple_char_driver c <major_number> 0
其中 <major_number>
是驱动加载时分配的主设备号。
卸载驱动:
sudo rmmod simple_char_driver
通过以上步骤,你就可以在内核中编写并加载一个简单的字符设备驱动。