在 Linux 幀緩衝驅動 (fbmem.c) 中,透過 register_chrdev(FB_MAJOR, "fb", &fb_fops) 註冊字符設備,所有 framebuffer 設備共用同一主設備號 FB_MAJOR。隨後在 register_framebuffer 中調用 device_create(fb_class, ..., MKDEV(FB_MAJOR, i), NULL, "fb%d", i) 建立 /dev/fb0、/dev/fb1 等設備節點。問題在於:用戶空間打開 /dev/fb0 時,核心如何知道要調用 fb_fops 中的操作函數?
register_chrdev 將主設備號 FB_MAJOR 與 file_operations 結構體 fb_fops 綁定,存放在核心的字符設備註冊表 (chrdevs) 中。這建立了「主設備號 → 預設操作集」的映射。
device_create 內部會:
struct cdev 並初始化 cdev->ops = &fb_fops(繼承自類別的 devnode 回調或預設值)。cdev_add 將 cdev 掛入核心的 cdev 映射表,鍵值為 MKDEV(FB_MAJOR, i)(主次設備號組合)。/sys/class/graphics/fb/dev,內容為 29:0 等主次號文本。用戶調用 open("/dev/fb0") → VFS 解析 inode → 取得 i_rdev = MKDEV(29,0) → chrdev_open 根據主次號在 cdev 映射表查找對應 cdev → 將 file->f_op = cdev->ops(即 fb_fops)。
file_operations(透過 register_chrdev)。fb0、fb1...)。device_create 會自動建立並綁定 cdev->ops。/dev/fb* 共用同一組 fb_fops,驅動內部透過 file->private_data 或 iminor(inode) 區分具體實例。詳細源碼追蹤可參考:Linux 字符設備同一主設備號註冊機制分析