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