這兩個函數是字符設備初始化相關的內核函數。nice編輯器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;">一、字符設備架構
下面我們以兩個設備:LED、MPU6050為例來講解字符設備的架構
由上圖所示:
1、硬件
外設有MPU6050、LED兩個設備,他們通過外設電路連接到SOC的對應的引腳上。程序要操作外設,就要通過設置soc中對應的SFR來與外設交互。
2、驅動層
- 每一個字符設備都必須首先定義一個結構體變量struct cdev,并注冊到內核中
- 所有的該變量在內核中會通過鏈表進程管理,其中成員list用于將所有鏈表串接起來
- 用于操作外設的功能函數全部被封裝在struct file_operations中,包括read、write等
- 每一個字符設備都必須要有一個設備號,保存在成員dev中,
- 主、次設備號只能被分配一次
- 所有的字符設備號,都由數組chrdevs統(tǒng)一管理
- chrdevs是一個指針數組,成員類型為**struct char_device_struct ***,下標與字符設備號有一定的對應關系,
- **struct char_device_struct **中有成員:
unsigned?int?major;
struct?cdev?*cdev;?
major : 是主設備號 cdev ?: 指向該字符設備號對應的cdev結構體
3、應用層、VFS層
- 用戶如果想操作硬件,必須調用內核中的struct file_operations中的操作函數,
- 那么如何才能找到該結構體呢?必須要依賴文件節(jié)點來查找,可以通過以下命令來創(chuàng)建
mknod??/dev/led?c?250?0
?mknod?創(chuàng)建設備文件,可以使字符設備,也可以是塊設備
?/dev/led?設備文件名
?c??字符設備
?250??主設備號
?0????次設備號
字符設備文件屬性中最重要的屬性就是字符設備號,該設備號和chedevs的下標有一定對應關系
- 通過mknod創(chuàng)建的文件,VFS層會分配一個結構體變量來維護該文件,類型為struct inode
- 每新建1個文件內核都會創(chuàng)建不同的結構體變量與之對應
- 應用程序要操作某個字符設備,那么必須先通過系統(tǒng)調用open()來打開該字符設備
- 該函數會返回一個唯一的整型文件描述符,同時內核中會分配結構體變量,類型為struct file,并與文件描述符一一對應,該結構體維護在struct task_struct中
- 每次打開某個文件,都會分配不同的文件描述符,所以需要用不同的變量來保存文件描述符
二、字符設備創(chuàng)建的流程
了解了架構之后,那么我們來看一下內核中完整的創(chuàng)建字符設備的流程及對應的函數調用關系:如下圖所示,字符設備的創(chuàng)建主要包括以下三個步驟:
- 申請設備號
- 初始化cdev
- 注冊cdev 調用的函數見右側
下面是一個最簡單的額字符設備創(chuàng)建的實例
/*??
?*一口Linux
?*2021.6.21
?*version:?1.0.0
*/
#include?
#include?
#include?
#include?
#include?
static?int?major?=?237;
static?int?minor?=?0;
static?dev_t?devno;
static?struct?cdev?cdev;
static?int?hello_open?(struct?inode?*inode,?struct?file?*filep)
{
?printk("hello_open()\n");
?return?0;
}
static?struct?file_operations?hello_ops?=?
{
?.open?=?hello_open,
};
static?int?hello_init(void)
{
?int?result;
?int?error;?
?printk("hello_init?\n");
?devno?=?MKDEV(major,minor);?
?result?=?register_chrdev_region(devno,?1,?"test");
?if(result<0)
?{
??printk("register_chrdev_region?fail?\n");
??return?result;
?}
?cdev_init(