參考資訊:
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