实现一个简单的Linux设备驱动demo可以帮助你理解设备驱动的基本结构和工作原理。下面是一个基本的字符设备驱动示例,展示了如何创建、注册和使用字符设备。
1. 环境准备
确保你已经安装了Linux内核开发包和必要的编译工具(如gcc
和make
)。
2. 创建驱动代码
创建一个新的文件,例如 simple_char_device.c
,并将以下代码复制到文件中:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h> // for copy_to_user and copy_from_user
#define DEVICE_NAME "simple_char_device"
#define BUFFER_SIZE 256
static char message[BUFFER_SIZE];
static int number_opens = 0;
static struct class* charClass = NULL;
static struct device* charDevice = NULL;
static ssize_t dev_read(struct file* file, char __user* buffer, size_t len, loff_t* offset) {
int error_count = 0;
if (*offset >= strlen(message)) {
return 0; // End of the file
}
error_count = copy_to_user(buffer, message + *offset, strlen(message) - *offset);
if (error_count == 0) {
*offset += strlen(message) - *offset; // Update offset
return strlen(message); // Return number of bytes read
} else {
return -EFAULT; // Failed to send data to the user
}
}
static ssize_t dev_write(struct file* file, const char __user* buffer, size_t len, loff_t* offset) {
snprintf(message, BUFFER_SIZE, "%s", buffer);
return len; // Return number of bytes written
}
static int dev_open(struct inode* inodep, struct file* filep) {
number_opens++;
printk(KERN_INFO "Device opened %d times\n", number_opens);
return 0;
}
static int dev_release(struct inode* inodep, struct file* filep) {
printk(KERN_INFO "Device closed\n");
return 0;
}
// Define the operations that can be performed on the device
static struct file_operations fops = {
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
static int __init simple_char_init(void) {
majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
if (majorNumber < 0) {
printk(KERN_ALERT "Failed to register a major number\n");
return majorNumber;
}
// Register the device class
charClass = class_create(THIS_MODULE, "char");
if (IS_ERR(charClass)) {
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(charClass);
}
// Register the device driver
charDevice = device_create(charClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(charDevice)){
class_destroy(charClass);
unregister_chrdev(majorNumber);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(charDevice);
}
printk(KERN_INFO "Simple Char Device initialized with major number %d\n", majorNumber);
return 0;
}
static void __exit simple_char_exit(void) {
device_destroy(charClass, MKDEV(majorNumber, 0));
class_unregister(charClass);
class_destroy(charClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_INFO "Simple Char Device unregistered\n");
}
module_init(simple_char_init);
module_exit(simple_char_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A Simple Character Device Driver");
MODULE_VERSION("1.0");
3. 编写Makefile
在相同目录下创建一个名为 Makefile
的文件,并添加以下内容:
obj-m += simple_char_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
4. 编译驱动程序
在终端中进入该目录并运行以下命令:
make
这将编译你的设备驱动,并生成一个模块文件 simple_char_device.ko
。
5. 加载模块
使用 insmod
命令加载模块:
sudo insmod simple_char_device.ko
检查内核日志,以确认设备已成功加载:
dmesg | tail
6. 测试设备驱动程序
你需要创建一个特殊文件来与设备进行交互。使用 mknod
命令创建设备节点(根据实际分配的主设备号进行调整):
sudo mknod /dev/simple_char_device c [主设备号] 0
然后,你可以通过 echo
和 cat
命令测试这个字符设备:
- 写入数据:
echo "Hello from user space!" > /dev/simple_char_device
- 从中读取数据:
cat /dev/simple_char_device
7. 卸载模块
完成测试后,可以卸载模块:
sudo rmmod simple_char_device.ko
再一次查看内核日志确认它已被卸载。
总结
这个简单示例演示了如何实现一个基础的字符设备驱动。在实际开发中,你可能会涉及更多复杂的功能,如中断处理、DMA等。学习和实践时,请参考Linux内核文档以及相关书籍以获得更深入的信息。如果您有任何问题或需要进一步的信息,请告诉我!
内容由零声教学AI助手提供,问题来源于学员提问