Linux 银河麒麟V10-SP1实现.ko驱动开机自动加载

此方法应该不止适用于银河麒麟,但是本人只实验了银河麒麟V10-SP1。

测试代码
hello_world.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h> // 用于 class_create() 和 device_create()

#define DEVICE_NAME "hello_world"
#define CLASS_NAME "hello_class"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World Linux driver with udev support");

static int major;
static char message[] = "Hello from kernel!\n";
static int message_len = sizeof(message);
static struct class* hello_class = NULL;
static struct device* hello_device = NULL;

// 设备文件 open
static int dev_open(struct inode *inodep, struct file *filep) {
    printk(KERN_INFO "Device opened\n");
    return 0;
}

// 设备文件 read
static ssize_t dev_read(struct file *filep, char __user *buffer, size_t len, loff_t *offset) {
    int bytes_read;

    if (*offset >= message_len)
        return 0;

    bytes_read = message_len - *offset;
    if (len < bytes_read)
        bytes_read = len;

    if (copy_to_user(buffer, message + *offset, bytes_read))
        return -EFAULT;

    *offset += bytes_read;
    return bytes_read;
}

// 设备文件 release
static int dev_release(struct inode *inodep, struct file *filep) {
    printk(KERN_INFO "Device closed\n");
    return 0;
}

// 定义 file_operations 结构体
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = dev_open,
    .read = dev_read,
    .release = dev_release,
};

// 模块初始化
static int __init hello_world_init(void) {
    major = register_chrdev(0, DEVICE_NAME, &fops);
    if (major < 0) {
        printk(KERN_ALERT "Failed to register a major number\n");
        return major;
    }
    printk(KERN_INFO "Hello, World! Device registered with major number %d\n", major);

    // 创建 class
    hello_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(hello_class)) {
        unregister_chrdev(major, DEVICE_NAME);
        printk(KERN_ALERT "Failed to register device class\n");
        return PTR_ERR(hello_class);
    }
    printk(KERN_INFO "Device class created successfully\n");

    // 创建 device
    hello_device = device_create(hello_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
    if (IS_ERR(hello_device)) {
        class_destroy(hello_class);
        unregister_chrdev(major, DEVICE_NAME);
        printk(KERN_ALERT "Failed to create the device\n");
        return PTR_ERR(hello_device);
    }
    printk(KERN_INFO "Device created successfully\n");

    return 0;
}

// 模块卸载
static void __exit hello_world_exit(void) {
    device_destroy(hello_class, MKDEV(major, 0));
    class_destroy(hello_class);
    unregister_chrdev(major, DEVICE_NAME);
    printk(KERN_INFO "Goodbye, World! Device unregistered\n");
}

module_init(hello_world_init);
module_exit(hello_world_exit);

Makefile

obj-m += hello_world.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

开机自动加载

  1. 将驱动模块复制到 /lib/modules/$(uname -r)/extra/
   sudo mkdir -p /lib/modules/$(uname -r)/extra/
   sudo cp hello_world.ko /lib/modules/$(uname -r)/extra/
  1. /etc/modules 添加驱动名
   echo "hello_world" | sudo tee -a /etc/modules
  1. 刷新模块依赖
   sudo depmod -a
  1. 重启测试
   sudo reboot
  1. 验证模块是否自动加载
   lsmod | grep hello_world

通过上诉步骤应该能够实现开机自动加载,亲测有效,但是此时还有一个问题就是默认情况下,udev 创建的设备节点的 user 和 group 都是 root,普通用户无法访问。
所以使用以下命令实现权限修改


解决方案:修改 udev 规则

我们可以在 udev 规则中指定设备的 用户 (OWNER)、用户组 (GROUP) 和权限 (MODE)

1. 找到当前用户的用户名

在终端运行:

whoami

假设返回:

yourusername

你的用户名是 yourusername


2. 编辑 udev 规则

创建或修改 /etc/udev/rules.d/99-hello_world.rules

sudo nano /etc/udev/rules.d/99-hello_world.rules

添加以下内容:

KERNEL=="hello_world", OWNER="yourusername", GROUP="yourusername", MODE="0666"

解释:

  • OWNER="yourusername" → 设备的所有者设置为 yourusername
  • GROUP="yourusername" → 设备的用户组设置为 yourusername
  • MODE="0666" → 允许所有用户(包括非 root 用户)读写设备。

在命令 sudo nano /etc/udev/rules.d/99-hello_world.rules 中,99-hello_world.rules 是一个 udev 规则文件的名称。以下是对这个文件及其命名的详细解析:

udev规则文件路径:
/etc/udev/rules.d/ —本机规则
/lib/udev/rules.d/ —系统规则

udev 规则文件

  • udev:是 Linux 系统中的设备管理器,负责动态管理设备节点。它在设备添加或移除时自动执行规则,以便配置设备的属性和行为。

文件路径

  • /etc/udev/rules.d/:这是存放 udev 规则的目录。所有以 .rules 结尾的文件都包含了设备管理的规则。

文件命名

  • 99-hello_world.rules
    • 数字前缀99):这个数字决定了规则的加载顺序。数字越小,规则越早加载。通常,99 表示这是一个优先级较低的规则,允许其他规则先执行。
    • 文件名hello_world):这个部分通常用来描述规则的用途或关联的设备。可以是任何有意义的名称,便于识别。

规则的作用

99-hello_world.rules 文件中,你可以定义针对特定设备的规则,例如:

  • 设置设备权限。
  • 创建符号链接。
  • 运行特定的脚本或命令。

示例内容

以下是一个简单的 99-hello_world.rules 文件示例:

SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"

这个规则的意思是:

  • 当连接的设备属于 USB 子系统(SUBSYSTEM=="usb")。
  • 设备的供应商 ID 为 1234,产品 ID 为 5678
  • 设置设备的权限为 0666(所有用户可读可写)。

如果你的 username 可能会变,可以改成 plugdev 组(Linux 里用于管理可插拔设备):

KERNEL=="hello_world", GROUP="plugdev", MODE="0660"

然后把你的用户加到 plugdev 组:

sudo usermod -aG plugdev yourusername

3. 重新加载 udev 规则

执行以下命令,使新的规则生效:

sudo udevadm control --reload-rules
sudo service udev restart
sudo udevadm trigger

4. 重新加载驱动

sudo rmmod hello_world
sudo modprobe hello_world

或者直接重启:

sudo reboot

5. 验证权限

启动后,运行:

ls -l /dev/hello_world

期望输出:

crw-rw-rw- 1 yourusername yourusername 240, 0 Feb 7 12:00 /dev/hello_world

或:

crw-rw---- 1 root plugdev 240, 0 Feb 7 12:00 /dev/hello_world

如果你使用了 plugdev 组,确保你的用户在 plugdev 组里:

groups yourusername

6. 运行应用程序(不需要 sudo

现在,你的应用可以直接访问 /dev/hello_world 了:

cat /dev/hello_world

不再需要 sudo 🎉🚀!


总结

  1. 修改 udev 规则/dev/hello_world 归属于当前用户或 plugdev 组。
  2. 重新加载 udev 规则重启驱动 使其生效。
  3. 验证权限,确保 /dev/hello_world 可由普通用户访问。
  4. 你的应用可以直接访问设备,无需 sudo 了!

这样,你的 Linux 驱动就真正 开机自动加载 + 用户无需 root 访问 了! 🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值