初學 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 驅動開發的基礎範式。