驅動程式 - Linux Device Driver (LDD) - 使用範例 - C/C++ (PocketBeagle) - Char Device - Device Node



參考資訊:
https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html

User Application可以透過檔案操作方式跟驅動程式溝通,在Linux Kernel中,將檔案分成字元驅動程式(Char)和區塊驅動程式(Block)兩大類,主要區別在於傳輸方式,可以把字元驅動程式想像成每次傳輸都是以1個Byte為單位,而區塊驅動程式則是多個Bytes為單位,如:512 Bytes,User Application可以透過open()、read()、write()、ioctl()、close()跟字元驅動程式溝通,那User Application怎麼知道路徑在哪呢?答案是Symbolic Link(/dev/xxx),那Symbolic Link又如何連結到字元驅動程式呢?答案是Major、Minor號碼,Major、Minor號碼是驅動程式的裝置索引,字元驅動程式在被系統載入時,會註冊Major和Minor號碼,使用者可以透過mknod工具,去建立一個Symbolic Link(名稱可以由使用者隨意取)並且綁定到字元驅動程式的這個Major、Minor號碼,完成連接的管道

字元驅動程式建立步驟:

1. alloc_chrdev_region()
2. cdev_init()
3. cdev_add()
4. cdev_del()
5. unregister_chrdev_region()

alloc_chrdev_region()可以取得空閒的裝置號碼,如果想要自訂Major號碼,可以使用register_chrdev_region()

main.c

#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steward Fu");
MODULE_DESCRIPTION("Linux Driver");

static int base = 0;
static struct cdev mycdev;

static int myopen(struct inode *inode, struct file *file)
{
    printk("%s\n", __func__);
    return 0;
}

static int myclose(struct inode *inode, struct file *file)
{
    printk("%s\n", __func__);
    return 0;
}

static const struct file_operations myfops = {
    .owner = THIS_MODULE,
    .open = myopen,
    .release = myclose,
};

int ldd_init(void)
{
    alloc_chrdev_region(&base, 0, 1, "myfile");
    cdev_init(&mycdev, &myfops);
    cdev_add(&mycdev, base, 1);
    printk("major:%d, minor:%d\n", MAJOR(base), MINOR(base));
    return 0;
}
 
void ldd_exit(void)
{
    cdev_del(&mycdev);
    unregister_chrdev_region(base, 1);
}
 
module_init(ldd_init);
module_exit(ldd_exit);

ldd_init: 建立字元驅動程式
myopen: 對應User Application的open()
myclose: 對應User Application的close()
ldd_exit: 刪除字元驅動程式

安裝驅動

# insmod /boot/main.ko 
    major:243, minor:0

P.S. Linux驅動程式使用Major、Minor號碼當作裝置索引

make node

# mknod /dev/myfile c 243 0

# ls -al /dev/myfile
    crw-r--r--    1 root     root      243,   0 Jan  1 00:00 /dev/myfile

P.S. 建立Symbolic符號,供User Application開啟使用

開啟裝置

# echo "" > /dev/myfile
    myopen
    sh: write error: Invalid argument myclose