国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)

這篇具有很好參考價(jià)值的文章主要介紹了字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1、字符設(shè)備驅(qū)動(dòng)簡(jiǎn)介

字符設(shè)備是 Linux 驅(qū)動(dòng)中最基本的一類(lèi)設(shè)備驅(qū)動(dòng),字符設(shè)備就是一個(gè)一個(gè)字節(jié),按照字節(jié) 流進(jìn)行讀寫(xiě)操作的設(shè)備,讀寫(xiě)數(shù)據(jù)是分先后順序的。比如我們最常見(jiàn)的點(diǎn)燈、按鍵、IIC、SPI, LCD 等等都是字符設(shè)備,這些設(shè)備的驅(qū)動(dòng)就叫做字符設(shè)備驅(qū)動(dòng)。

先來(lái)簡(jiǎn)單的了解一下 Linux 下的應(yīng)用程序是如 何調(diào)用驅(qū)動(dòng)程序的,Linux 應(yīng)用程序?qū)︱?qū)動(dòng)程序的調(diào)用

字符驅(qū)動(dòng),驅(qū)動(dòng)開(kāi)發(fā)

? ? ? ? 在 Linux 中一切皆為文件,驅(qū)動(dòng)加載成功以后會(huì)在“/dev”目錄下生成一個(gè)相應(yīng)的文件,應(yīng) 用程序通過(guò)對(duì)這個(gè)名為“/dev/xxx”(xxx 是具體的驅(qū)動(dòng)文件名字)的文件進(jìn)行相應(yīng)的操作即可實(shí) 現(xiàn)對(duì)硬件的操作。比如現(xiàn)在有個(gè)叫做/dev/led 的驅(qū)動(dòng)文件,此文件是 led 燈的驅(qū)動(dòng)文件。應(yīng)用程 序使用 open 函數(shù)來(lái)打開(kāi)文件/dev/led,使用完成以后使用 close 函數(shù)關(guān)閉/dev/led 這個(gè)文件。open 和 close 就是打開(kāi)和關(guān)閉 led 驅(qū)動(dòng)的函數(shù),如果要點(diǎn)亮或關(guān)閉 led,那么就使用 write 函數(shù)來(lái)操 作,也就是向此驅(qū)動(dòng)寫(xiě)入數(shù)據(jù),這個(gè)數(shù)據(jù)就是要關(guān)閉還是要打開(kāi) led 的控制參數(shù)。如果要獲取 led 燈的狀態(tài),就用 read 函數(shù)從驅(qū)動(dòng)中讀取相應(yīng)的狀態(tài)。

? ? ? ? ???應(yīng)用程序運(yùn)行在用戶(hù)空間,而 Linux 驅(qū)動(dòng)屬于內(nèi)核的一部分,因此驅(qū)動(dòng)運(yùn)行于內(nèi)核空間。 當(dāng)我們?cè)谟脩?hù)空間想要實(shí)現(xiàn)對(duì)內(nèi)核的操作,比如使用 open 函數(shù)打開(kāi)/dev/led 這個(gè)驅(qū)動(dòng),因?yàn)橛?戶(hù)空間不能直接對(duì)內(nèi)核進(jìn)行操作,因此必須使用一個(gè)叫做“系統(tǒng)調(diào)用”的方法來(lái)實(shí)現(xiàn)從用戶(hù)空 間“陷入”到內(nèi)核空間,這樣才能實(shí)現(xiàn)對(duì)底層驅(qū)動(dòng)的操作。open、close、write 和 read 等這些函 數(shù)是由 C 庫(kù)提供的,在 Linux 系統(tǒng)中,系統(tǒng)調(diào)用作為 C 庫(kù)的一部分。

字符驅(qū)動(dòng),驅(qū)動(dòng)開(kāi)發(fā)

?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-689100.html

2、每一 個(gè)系統(tǒng)調(diào)用,在驅(qū)動(dòng)中都有與之對(duì)應(yīng)的一個(gè)驅(qū)動(dòng)函數(shù),在 Linux 內(nèi)核文件include/linux/fs.h 中 有個(gè)叫做 file_operations 的結(jié)構(gòu)體,此結(jié)構(gòu)體就是 Linux 內(nèi)核驅(qū)動(dòng)操作函數(shù)集合

1588 struct file_operations {
1589     struct module *owner;
1590     loff_t (*llseek) (struct file *, loff_t, int);
1591     ssize_t (*read) (struct file *, char __user *, size_t, loff_t 
        *);
1592     ssize_t (*write) (struct file *, const char __user *, size_t,
            loff_t *);
1593     ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
1594     ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
1595     int (*iterate) (struct file *, struct dir_context *);
1596     unsigned int (*poll) (struct file *, struct poll_table_struct 
            *);
1597     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned
            long);
1598     long (*compat_ioctl) (struct file *, unsigned int, unsigned
            long);
1599     int (*mmap) (struct file *, struct vm_area_struct *);
1600     int (*mremap)(struct file *, struct vm_area_struct *);
1601     int (*open) (struct inode *, struct file *);
1602     int (*flush) (struct file *, fl_owner_t id);
1603     int (*release) (struct inode *, struct file *);
1604     int (*fsync) (struct file *, loff_t, loff_t, int datasync);
1605     int (*aio_fsync) (struct kiocb *, int datasync);
1606     int (*fasync) (int, struct file *, int);
1607     int (*lock) (struct file *, int, struct file_lock *);
1608     ssize_t (*sendpage) (struct file *, struct page *, int, size_t,
            loff_t *, int);
1609     unsigned long (*get_unmapped_area)(struct file *, unsigned long,
            unsigned long, unsigned long, unsigned long);
1610     int (*check_flags)(int);
1611     int (*flock) (struct file *, int, struct file_lock *);
1612     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
            loff_t *, size_t, unsigned int);
1613     ssize_t (*splice_read)(struct file *, loff_t *, struct
            pipe_inode_info *, size_t, unsigned int);
1614     int (*setlease)(struct file *, long, struct file_lock **, void
                **);
1615     long (*fallocate)(struct file *file, int mode, loff_t offset,
1616         loff_t len);
1617     void (*show_fdinfo)(struct seq_file *m, struct file *f);
1618     #ifndef CONFIG_MMU
1619     unsigned (*mmap_capabilities)(struct file *);
1620     #endif
1621 };

簡(jiǎn)單介紹一下 file_operation 結(jié)構(gòu)體中比較重要的、常用的函數(shù):

第 1589 行,owner 擁有該結(jié)構(gòu)體的模塊的指針,一般設(shè)置為 THIS_MODULE。

第 1590 行,llseek 函數(shù)用于修改文件當(dāng)前的讀寫(xiě)位置。

第 1591 行,read 函數(shù)用于讀取設(shè)備文件。

第 1592 行,write 函數(shù)用于向設(shè)備文件寫(xiě)入(發(fā)送)數(shù)據(jù)。

第 1596 行,poll 是個(gè)輪詢(xún)函數(shù),用于查詢(xún)?cè)O(shè)備是否可以進(jìn)行非阻塞的讀寫(xiě)。

第 1597 行,unlocked_ioctl 函數(shù)提供對(duì)于設(shè)備的控制功能,與應(yīng)用程序中的 ioctl 函數(shù)對(duì)應(yīng)。

第 1598 行,compat_ioctl 函數(shù)與 unlocked_ioctl 函數(shù)功能一樣,區(qū)別在于在 64 位系統(tǒng)上, 32 位的應(yīng)用程序調(diào)用將會(huì)使用此函數(shù)。在 32 位的系統(tǒng)上運(yùn)行 32 位的應(yīng)用程序調(diào)用的是 unlocked_ioctl。

第 1599 行,mmap 函數(shù)用于將設(shè)備的內(nèi)存映射到進(jìn)程空間中(也就是用戶(hù)空間),一般幀緩 沖設(shè)備會(huì)使用此函數(shù),比如 LCD 驅(qū)動(dòng)的顯存,將幀緩沖(LCD 顯存)映射到用戶(hù)空間中以后應(yīng)用 程序就可以直接操作顯存了,這樣就不用在用戶(hù)空間和內(nèi)核空間之間來(lái)回復(fù)制。

第 1601 行,open 函數(shù)用于打開(kāi)設(shè)備文件。

第 1603 行,release 函數(shù)用于釋放(關(guān)閉)設(shè)備文件,與應(yīng)用程序中的 close 函數(shù)對(duì)應(yīng)。 第 1604 行,fasync 函數(shù)用于刷新待處理的數(shù)據(jù),用于將緩沖區(qū)中的數(shù)據(jù)刷新到磁盤(pán)中。 第 1605 行,aio_fsync 函數(shù)與 fasync 函數(shù)的功能類(lèi)似,只是 aio_fsync 是異步刷新待處理的 數(shù)據(jù)。

在字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)中最常用的就是上面這些函數(shù),關(guān)于其他的函數(shù)大家可以查閱相關(guān)文 檔。我們?cè)谧址O(shè)備驅(qū)動(dòng)開(kāi)發(fā)中最主要的工作就是實(shí)現(xiàn)上面這些函數(shù),不一定全部都要實(shí)現(xiàn), 但是像 open、release、write、read 等都是需要實(shí)現(xiàn)的,當(dāng)然了,具體需要實(shí)現(xiàn)哪些函數(shù)還是要 看具體的驅(qū)動(dòng)要求。

3、字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)步驟

在 Linux 驅(qū) 動(dòng)開(kāi)發(fā)中肯定也是要初始化相應(yīng)的外設(shè)寄存器,這個(gè)是毫無(wú)疑問(wèn)的。只是在 Linux 驅(qū)動(dòng)開(kāi)發(fā)中 我們需要按照其規(guī)定的框架來(lái)編寫(xiě)驅(qū)動(dòng),所以說(shuō)學(xué) Linux 驅(qū)動(dòng)開(kāi)發(fā)重點(diǎn)是學(xué)習(xí)其驅(qū)動(dòng)框架。

4、驅(qū)動(dòng)模塊的加載和卸載

Linux 驅(qū)動(dòng)有兩種運(yùn)行方式,第一種就是將驅(qū)動(dòng)編譯進(jìn) Linux 內(nèi)核中,這樣當(dāng) Linux 內(nèi)核啟 動(dòng)的時(shí)候就會(huì)自動(dòng)運(yùn)行驅(qū)動(dòng)程序。第二種就是將驅(qū)動(dòng)編譯成模塊(Linux 下模塊擴(kuò)展名為.ko),在 Linux 內(nèi)核啟動(dòng)以后使用“insmod”命令加載驅(qū)動(dòng)模塊。在調(diào)試驅(qū)動(dòng)的時(shí)候一般都選擇將其編譯 為模塊,這樣我們修改驅(qū)動(dòng)以后只需要編譯一下驅(qū)動(dòng)代碼即可,不需要編譯整個(gè) Linux 代碼。 而且在調(diào)試的時(shí)候只需要加載或者卸載驅(qū)動(dòng)模塊即可,不需要重啟整個(gè)系統(tǒng)??傊瑢Ⅱ?qū)動(dòng)編 譯為模塊最大的好處就是方便開(kāi)發(fā),當(dāng)驅(qū)動(dòng)開(kāi)發(fā)完成,確定沒(méi)有問(wèn)題以后就可以將驅(qū)動(dòng)編譯進(jìn) Linux 內(nèi)核中,當(dāng)然也可以不編譯進(jìn) Linux 內(nèi)核中,具體看自己的需求。

模塊有加載和卸載兩種操作,我們?cè)诰帉?xiě)驅(qū)動(dòng)的時(shí)候需要注冊(cè)這兩種操作函數(shù),模塊的加載和 卸載注冊(cè)函數(shù)如下:

module_init(xxx_init); //注冊(cè)模塊加載函數(shù)
module_exit(xxx_exit); //注冊(cè)模塊卸載函數(shù)

module_init()?函數(shù)用來(lái)向 Linux 內(nèi)核注冊(cè)一個(gè)模塊加載函數(shù),參數(shù) xxx_init 就是需要注冊(cè)的 具體函數(shù),當(dāng)使用“insmod”命令加載驅(qū)動(dòng)的時(shí)候,xxx_init 這個(gè)函數(shù)就會(huì)被調(diào)用。module_exit() 函數(shù)用來(lái)向 Linux 內(nèi)核注冊(cè)一個(gè)模塊卸載函數(shù),參數(shù) xxx_exit 就是需要注冊(cè)的具體函數(shù),當(dāng)使 用rmmod”命令卸載具體驅(qū)動(dòng)的時(shí)候 xxx_exit 函數(shù)就會(huì)被調(diào)用。

字符設(shè)備驅(qū)動(dòng)模塊加載和卸 載模板如下所示:

/* 驅(qū)動(dòng)入口函數(shù) */
static int __init xxx_init(void)
 {
 /* 入口函數(shù)具體內(nèi)容 */
  return 0;
 }
 
 /* 驅(qū)動(dòng)出口函數(shù) */
static void __exit xxx_exit(void)
 {
 /* 出口函數(shù)具體內(nèi)容 */
 }

 /* 將上面兩個(gè)函數(shù)指定為驅(qū)動(dòng)的入口和出口函數(shù) */
module_init(xxx_init);
module_exit(xxx_exit);

第 2 行,定義了個(gè)名為 xxx_init 的驅(qū)動(dòng)入口函數(shù),并且使用了“__init”來(lái)修飾。

第 9 行,定義了個(gè)名為 xxx_exit 的驅(qū)動(dòng)出口函數(shù),并且使用了“__exit”來(lái)修飾。

第 15 行,調(diào)用函數(shù) module_init 來(lái)聲明 xxx_init 為驅(qū)動(dòng)入口函數(shù),當(dāng)加載驅(qū)動(dòng)的時(shí)候 xxx_init 函數(shù)就會(huì)被調(diào)用。

第16行,調(diào)用函數(shù)module_exit來(lái)聲明xxx_exit為驅(qū)動(dòng)出口函數(shù),當(dāng)卸載驅(qū)動(dòng)的時(shí)候xxx_exit 函數(shù)就會(huì)被調(diào)用

驅(qū)動(dòng)編譯完成以后擴(kuò)展名為.ko,有兩種命令可以加載驅(qū)動(dòng)模塊insmod和modprobe,insmod 是最簡(jiǎn)單的模塊加載命令,此命令用于加載指定的.ko 模塊,比如加載 drv.ko 這個(gè)驅(qū)動(dòng)模塊,命 令如下:

insmod drv.ko

insmod 命令不能解決模塊的依賴(lài)關(guān)系,比如 drv.ko 依賴(lài) first.ko 這個(gè)模塊,就必須先使用 insmod 命令加載 first.ko 這個(gè)模塊,然后再加載 drv.ko 這個(gè)模塊。但是 modprobe 就不會(huì)存在這 個(gè)問(wèn)題,modprobe 會(huì)分析模塊的依賴(lài)關(guān)系,然后會(huì)將所有的依賴(lài)模塊都加載到內(nèi)核中,因此 modprobe 命令相比 insmod 要智能一些。modprobe 命令主要智能在提供了模塊的依賴(lài)性分析、 錯(cuò)誤檢查、錯(cuò)誤報(bào)告等功能,推薦使用 modprobe 命令來(lái)加載驅(qū)動(dòng)。modprobe 命令默認(rèn)會(huì)去 /lib/modules/目錄中查找模塊,比如使用的 Linux kernel 的版本號(hào)為 4.1.15, 因此 modprobe 命令默認(rèn)會(huì)到/lib/modules/4.1.15 這個(gè)目錄中查找相應(yīng)的驅(qū)動(dòng)模塊,一般自己制 作的根文件系統(tǒng)中是不會(huì)有這個(gè)目錄的,所以需要自己手動(dòng)創(chuàng)建。

驅(qū)動(dòng)模塊的卸載使用命令“rmmod”即可,比如要卸載 drv.ko,使用如下命令即可:

rmmod drv.ko

也可以使用“modprobe -r”命令卸載驅(qū)動(dòng),比如要卸載 drv.ko,命令如下:

modprobe -r drv.ko

使用 modprobe 命令可以卸載掉驅(qū)動(dòng)模塊所依賴(lài)的其他模塊,前提是這些依賴(lài)模塊已經(jīng)沒(méi) 有被其他模塊所使用,否則就不能使用 modprobe 來(lái)卸載驅(qū)動(dòng)模塊。所以對(duì)于模塊的卸載,還是 推薦使用 rmmod 命令。

字符驅(qū)動(dòng),驅(qū)動(dòng)開(kāi)發(fā)

?

到了這里,關(guān)于字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包