Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學

Linux 驅動開發:實現設備節點自動創建

編輯:Linux 系統常見問題解答

初學 Linux 驅動開發時,通常將驅動編譯為模組,再使用 mknod 手動建立 /dev/ 下的設備節點,方便應用層調用。但這種方式僅適合調試階段;若需在系統啟動時自動就緒驅動並提供設備節點,則必須實現自動創建機制,避免人工干預。

註冊設備類

為了讓 mdev 能在 /dev/ 目錄下自動生成設備節點,首先需要定義一個設備類。核心結構體 struct class 定義於 include/linux/device.h,包含類名、擁有者模組、子裝置列表、介面列表、信號量、虛擬目錄、屬性回調等欄位。

struct class {
    const char *name;
    struct module *owner;
    struct subsystem subsys;
    struct list_head children;
    struct list_head devices;
    struct list_head interfaces;
    struct semaphore sem;
    struct kobject *virtual_dir;
    struct class_attribute *class_attrs;
    struct class_device_attribute *class_dev_attrs;
    struct device_attribute *dev_attrs;
    int (*uevent)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
    int (*dev_uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
    void (*release)(struct class_device *dev);
    void (*class_release)(struct class *class);
    void (*dev_release)(struct device *dev);
    int (*suspend)(struct device *, pm_message_t state);
    int (*resume)(struct device *);
};

使用 class_create(THIS_MODULE, "device_name") 完成類的註冊。第一個參數通常為 THIS_MODULE,第二個參數為設備節點名稱。

示例代碼片段:

創建設備節點

核心提供 device_create() 函數用於創建設備節點,其原型如下:

struct device *device_create(struct class *class, struct device *parent, dev_t devt, const char *fmt, ...);

四個關鍵參數依次為:所屬類指標、父設備指標(無則為 NULL)、設備號(dev_t)、設備名稱格式字串(支援可變參數)。函數內部會分配 struct device、設定屬性並註冊到核心。

銷毀類與設備節點

模組卸載時必須成對釋放資源:

  • 銷毀類: void class_destroy(struct class *cls),先檢查指標有效性,再呼叫 class_unregister()。
  • 銷毀設備節點: void device_destroy(struct class *class, dev_t devt),遍歷類的設備鏈表匹配設備號,找到後呼叫 device_unregister()。

完整範例:延時驅動

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>

#define NAME "ralink_drive_delay"
#define DEV_NAME "my_delay"
#define DELAY_US 0
#define DELAY_MS 1
static int delay_major = 109;
MODULE_LICENSE("Dual BSD/GPL");

static long delay_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    switch (cmd) {
        case DELAY_US: udelay(10 * arg); return 0;
        case DELAY_MS: udelay(1000); return 0;
        default: return -1;
    }
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = delay_ioctl,
};

static struct class *delay_class;

static int __init delay_init(void) {
    int ret = register_chrdev(delay_major, DEV_NAME, &fops);
    if (ret < 0) {
        printk("無法註冊字元設備\n");
        return ret;
    }
    if (delay_major == 0) delay_major = ret;

    delay_class = class_create(THIS_MODULE, DEV_NAME);
    if (IS_ERR(delay_class)) {
        printk("類創建失敗\n");
        return -1;
    }

    device_create(delay_class, NULL, MKDEV(delay_major, 0), DEV_NAME);
    printk("delay driver initialized\n");
    return 0;
}

static void __exit delay_exit(void) {
    unregister_chrdev(delay_major, DEV_NAME);
    device_destroy(delay_class, MKDEV(delay_major, 0));
    class_destroy(delay_class);
    printk("delay driver exited\n");
}

module_init(delay_init);
module_exit(delay_exit);

此範例展示了從字元設備註冊、類創建、設備節點自動生成到模組卸載清理的完整流程,是嵌入式 Linux 驅動開發的基礎範式。

Copyright © Windows教程網 All Rights Reserved