问题:linux模块加载和模块卸载时出现的问题
在编写驱动程序的时候有时候会出现这种情况,模块加载之后不能卸载或卸载之后不能在加载,cat/proc/devices后发现设备还占用着设备号,这种情况下,再次加载驱动模块肯定不会成功,必须重新启动才可以解决。最近仔细看书后发现自己在驱动程序的卸载函数中少写了两个函数调用,以至于在加载模块的时候申请或添加的设备没有被释放或删除。
解决:抛弃老版本register_chrdev()注册方式,使用register_chrdev_region( )方式实现注册
删除 /dev/
中的设备文件:rm -f /dev/your_device_name
检查设备文件是否创建:sudo mknod /dev/traffic_light c MAJOR_NUMBER 0
其中,MAJOR_NUMBER
是通过 cat /proc/devices
命令查看的设备的主设备号。
实现代码:
// virtual_traffic_light.c
#include
#include
#include
#include
#include
#define DEVICE_NAME "traffic_light"
static int major_number;
static struct cdev cdev;
static int light_status = 0; // 0: 红灯亮,1: 绿灯亮
static int device_open(struct inode *inode, struct file *file) {
return 0;
}
static int device_release(struct inode *inode, struct file *file) {
return 0;
}
static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) {
// 读取灯的状态并传递到用户空间
if (copy_to_user(buffer, &light_status, sizeof(light_status)) != 0) {
return -EFAULT; // 复制失败
}
return sizeof(light_status);
}
static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) {
// 从用户空间获取灯的状态
if (copy_from_user(&light_status, buffer, sizeof(light_status)) != 0) {
return -EFAULT; // 复制失败
}
return sizeof(light_status);
}
static struct file_operations fops = {
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write,
};
static int __init traffic_light_init(void) {
// 分配设备号
if (alloc_chrdev_region(&major_number, 0, 1, DEVICE_NAME) < 0) {
printk(KERN_ALERT "Failed to register device number.\n");
return -1;
}
// 初始化字符设备
cdev_init(&cdev, &fops);
// 添加字符设备到内核
if (cdev_add(&cdev, major_number, 1) < 0) {
unregister_chrdev_region(major_number, 1);
printk(KERN_ALERT "Failed to register the device.\n");
return -1;
}
printk(KERN_INFO "Traffic Light module loaded. Major number: %d\n", major_number);
return 0;
}
static void __exit traffic_light_exit(void) {
// 移除字符设备
cdev_del(&cdev);
// 释放设备号
unregister_chrdev_region(major_number, 1);
printk(KERN_INFO "Traffic Light module unloaded.\n");
}
module_init(traffic_light_init);
module_exit(traffic_light_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Linux device driver for controlling a virtual traffic light.");
问题:
内核文件virtual_traffic_light.c:
// virtual_traffic_light.c
#include
#include
#include
#include
#define DEVICE_NAME "traffic_light"
static int light_status = 0; // 0: 红灯亮,1: 绿灯亮
static int device_open(struct inode *inode, struct file *file) {
return 0;
}
static int device_release(struct inode *inode, struct file *file) {
return 0;
}
static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) {
// 读取灯的状态并传递到用户空间
if (copy_to_user(buffer, &light_status, sizeof(light_status)) != 0) {
return -EFAULT; // 复制失败
}
return sizeof(light_status);
}
static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) {
// 从用户空间获取灯的状态
if (copy_from_user(&light_status, buffer, sizeof(light_status)) != 0) {
return -EFAULT; // 复制失败
}
return sizeof(light_status);
}
static struct file_operations fops = {
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write,
};
static int __init traffic_light_init(void) {
// 注册字符设备驱动程序
register_chrdev(0, DEVICE_NAME, &fops);
printk(KERN_INFO "Traffic Light module loaded.\n");
return 0;
}
static void __exit traffic_light_exit(void) {
// 注销字符设备驱动程序
unregister_chrdev(0, DEVICE_NAME);
printk(KERN_INFO "Traffic Light module unloaded.\n");
}
module_init(traffic_light_init);
module_exit(traffic_light_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Linux device driver for controlling a virtual traffic light.");
qt文件:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 打开设备文件
fd = ::open("/dev/traffic_light",O_RDWR);
if(fd < 0)
{
QMessageBox::critical(this, "Error", "Unable to open device file.");
qDebug()<<"open /dev/traffic_light failed";
qApp->exit(-1);
}
}
MainWindow::~MainWindow()
{
delete ui;
// 关闭设备文件
::close(fd);
}
void MainWindow::on_pushButton_clicked()
{
// 控制红灯亮
int lightStatus = 0;
}
void MainWindow::on_pushButton_2_clicked()
{
// 控制绿灯亮
int lightStatus = 1;
}
首先make后加载内核:insmod traffic_light.ko;添加设备:sudo mknod /dev/traffic_light c 240 0
问题描述都加载成功:
但qt运行时无法打开设备:
解决办法:把设备节点权限改成777
crw-r--r-- 1 root root 240, 0 1月 24 11:00 /dev/traffic_light
root@szdjg-virtual-machine:~# chmod 777 /dev//traffic_light