【linux-IMX6ULL-字符設備驅動簡單框架實驗】

目錄

  • 1. 字符設備驅動簡介
    • 1.1 重要函數
    • 1.2 簡單框架代碼流程
    • 1.3 linux中關于驅動的重要命令
  • 2. 字符設備驅動簡單框架編寫
    • 2.1 添加LICENSE信息
    • 2.2 驅動模塊的入口與出口
    • 2.3 入口和出口函數的編寫
    • 2.4 設備操作結構體定義
      • 2.4.1 結構體函數內容填充
  • 3. 應用程序簡介:
  • 4. 應用程序的編寫思路

1. 字符設備驅動簡介

??目前的驅動開發一般是分為三類,第一類就是字符設備驅動、塊設備驅動、和網絡驅動三類,其中字符設備驅動是最多最雜的,現在對字符設備驅動進行一個簡要的介紹:
??字符設備驅動,是指那些以字節流進行數據傳輸的設備、IIC、SPI、LCD、按鍵、例如鍵盤、鼠標、打印機等,其中包含以下幾個關鍵的部分:

  1. 設備注冊和注銷:通過設備注冊使設備能被系統識別;注銷則相反;
  2. 數據操作函數:通常包含open,read,write,realse等;
  3. 中斷處理:處理設備產生的中斷,以響應特定事件;

?? 通過字符型設備驅動,可以使系統方便統一管理不同的設備,這樣就可以給上層應用提供相應的接口函數,方便應用程序與設備之間進行數據交換和通信;



?? 本次的實驗是通過簡單的實驗建立一個設備驅動開發的基本框架,為后續的學習打下基礎,其中會列出重要的函數以及重要的掛載指令,當然其中有一些函數是比較老的,例如要手動分配設備號,但是為了便于學習目前就以簡單的為主,因為越是抽象的越簡單,但是越抽象就越難以理解;

1.1 重要函數

??這里只是把本實驗相關的重要函數給羅列出來了,主要的作用就是對本次實驗的一個總結,如果沒有做個這個實驗,那么看著沒啥感覺的;例如我下面羅列函數的順序就是我們在編寫驅動實驗時整個流程的順序,首先就是注冊入口和出口函數,其次就是編寫入口和出口函數,再次就是編寫文件結構體的對應相關的函數內容;

  • MODULE-LICENSE("GPL"): 表示該內核模塊遵循的許可協議是通用公共許可(GPL)。指定許可協議非常重要,它明確了該模塊在使用、分發等方面的權利和限制。如果不寫這個的話就會導致在裝載設備驅動時出現警告;
  • module_init(*****_init):模塊的入口函數,進行初始化,也就是加載模塊時第一個就是運行這個函數注冊的函數*******;對模塊進行初始化設置;
  • module_exit(*****_exit):模塊的出口函數,對模塊進行卸載時就會執行這個函數注冊的函數*******;
  • static int __init *****_init(void):設備加載函數,進行模塊的初始化和加載的設置;這個函數要被入口函數進行注冊后起作用
  • register_chrdev(unsigned int major, const char *name, const struct file_operations *fops):對設備進行注冊;
  • static int __exit *****_exit(void):設備卸載函數、進行模塊的卸載時這個函數內部的程序就會執行,不過要被出口函數進行注冊
  • unregister_chrdev(unsigned int major, const char *name):對模塊進行卸載;
  • static const struct file_operations **_fops : struct file_operations是一個很重要的結構體,其中定義了很多與文件操作有關的函數指針,例如read,write,realse,open等等,這些函數可以按需進行填充,這樣就方便與設備之間進行文件的操作;下面進行實驗時會進行一個詳細的說明;

1.2 簡單框架代碼流程

??代碼實驗編寫流程:


在這里插入圖片描述


1.3 linux中關于驅動的重要命令

  • lsmod:顯示有哪些模塊被加載了,也就是顯示所有的加載模塊
  • lsmod:顯示有哪些模塊被加載了,也就是顯示所有的加載模塊
  • depmod:更新模塊的依賴關系,也就是新加載一個模塊時,要先運行一下這個命令,不然有錯誤
  • modprob ***.ko:這個命令的作用就是加載模塊***.ko
  • mknod /dev/*** c 200 0:mknod:手動創建節點的命令。/dev/*** :創建設備的名稱。c:字符型設備。200:主設備號,自己指定。0:次設備號,自己指定。
  • cat /proc/devices:這個命令的作用是查看所有加載的模塊,顯示所有設備號等;
  • rmmod ***.ko:卸載模塊***.ko;
  • cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq:這個命令是顯示當成CPU的頻率;

2. 字符設備驅動簡單框架編寫

??上面已經介紹了驅動編寫的則整體流程,以及介紹了重要的加載驅動的一些linux的命令,因此下面的代碼就不做過多的介紹:

2.1 添加LICENSE信息

??我們需要在代碼中添加LICENSE信息,否則編譯會出錯,不過我們還可以添加一些其他的信息,例如作者,郵箱等等;

MODULE_LICENSE("GPL");

2.2 驅動模塊的入口與出口

??linux的驅動有兩種加載形式,一就是編譯進linux內核中,當內核啟動,驅動也啟動,另一種方法就是把啟動編譯成模塊也就***.ko文件,通過insmode或者modprob的命令進行加載模塊,這樣做的好處就是便于調試,而且不用重啟linux內核;代碼如下,下面兩個函數的作用就是對模塊進行加載和卸載,并在加載和卸載函數中對字符設備進行注冊,如我們裸機編程中系統中斷函數對中斷服務函數的注冊一樣;

/* * 模塊入口和出口函數注冊*/ 
module_init(chrdevbase_init);/*入口,加載模塊*/
module_exit(chrdevbase_exit);/*出口,卸載模塊*/

2.3 入口和出口函數的編寫

??注意,入口函數是通過__init來修飾(注意是兩個杠),而對于出口函數通過__exit進行修飾,在出入口函數中對設備進行注冊,CHRDEVBASE_MAJOR是設備號,CHREEVBAScE_NAME是設備名,chrdevbase_fops是文件操作結構體;出口函數是類似的;

#define CHRDEVBASE_MAJOR 200  
#define CHREEVBASE_NAME "chrdevbase"static int __init chrdevbase_init(void)
{printk("chrdevbase_init3\r\n");/*注冊字符設備*/register_chrdev(CHRDEVBASE_MAJOR, CHREEVBASE_NAME,&chrdevbase_fops);return 0;
}
static void __exit chrdevbase_exit(void)
{printk("chrdevbase_exit\r\n");unregister_chrdev(CHRDEVBASE_MAJOR,CHREEVBASE_NAME);
}

2.4 設備操作結構體定義

??對于設備的操作file_operations結構體,也稱為文件操作結構體,這也是為什么linux下一切皆文件,我們的操作大部分都是通過文件來進行管理,我們可能用不到那么多的功能,因此我們要用到什么功能就進行對應的添加和書寫就行,代碼如下,注意這里使用的是=:

static const struct file_operations chrdevbase_fops={.owner	= THIS_MODULE,.open	= chrdevbase_open,.release	= chrdevbase_release,.read	= chrdevbase_read,.write	=	chrdevbase_write,
};

2.4.1 結構體函數內容填充

??可以看到,我們對上面的文件操作結構體中定義了四個函數指針,分別是:chrdevbase_open、chrdevbase_release、chrdevbase_read、chrdevbase_write,接下來就是對這四個函數進行內容填充:

static char readbuf[100];/*讀緩沖*/
static char writebuf[100];
static char kerneldata[]={"kernel data!"};/************/
static ssize_t chrdevbase_read(struct file * file, char * buf, size_t count, loff_t *off)
{int ret=0;memcpy(readbuf,kerneldata,sizeof(kerneldata));ret = copy_to_user(buf,readbuf,count);if(ret<0){printk("Error!");}else{}return 0;
}
/************/
static ssize_t chrdevbase_write(struct file * file, const char * buf, size_t count,loff_t *off)
{int ret =0;ret = copy_from_user(writebuf,buf,count);printk("Kernel recevdata:%s\r\n",writebuf);if(ret = 0){printk("Kernel recevdata:%s\r\n",writebuf);}return 0;
}
static int chrdevbase_release(struct inode * inode, struct file * file)
{printk("chrdevbase_ralease\r\n");return 0;
}
static int chrdevbase_open(struct inode * inode, struct file * file)
{printk("chrdevbase_open\n");return 0;
}

3. 應用程序簡介:

??當驅動程序編寫完畢后,要通過應用程序進行調用驅動函數的一些接口函數,這些功能的實現是在應用程序中實現的,這樣就實現了應用程序與驅動程序的分離可以這樣類比,我們寫應用程序就相當于我們在windows系統上寫C程序,我們寫C程序時也沒有關注下層,這就是一種分離,不過這兩者是可以相互進行數據交換的,不過要用特定的方法;注意驅動程序和應用程序的編譯是不一樣的:對于應用程序的編譯是下面的指令:

  • arm-linux-gnueabihf-gcc ***APP.c -o ***APP:應用程序的編譯指令
  • $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules:驅動程序的編譯:Make部分核心指令

?? 從上面的編譯指令中就可以看出區別,對于驅動的編譯要用到一系列的庫,這些庫包含板子的信息,以及一些arm中的一些庫等等,最終生成一個驅動模塊,屬于下層的驅動文件;
??而對于應用程序的編譯則是用到了一個.c文件以及基礎庫,就像我們編譯C語言一樣,只不過我們寫一個hello.c文件用的是gcc編譯器,生成的是x86架構的可執行文件,同理,我們使用arm-linux-gnueabihf-gcc交叉編譯器生成的是arm架構的可執行文件,這明顯是上層的應用程序,不過我們寫上層應用程序時通過傳參命令的形式就可以與下層的驅動進行數據文件交換;

4. 應用程序的編寫思路

??編寫測試APP就是編寫Linux應用程序,需要用到C庫和文件操作相關的一些函數,open、read、write 和 close 這四個函數;這些函數可以根據下面的命令進行找詳細幫助:“man 1”通常是用戶命令的手冊頁;“man 2”一般是系統調用的手冊頁;“man 3”可能是 C 庫函數的手冊頁;

wyj@BK:~$ man 2 read
wyj@BK:~$ man 2 write
wyj@BK:~$ man 2 close
wyj@BK:~$ man 2 open

??因此在應用程序中編寫程序就是如何對驅動程序進行調用和使用,不過要注意的是對于驅動的編寫屬于內核態,而對于應用程序的編寫屬于應用態,應用態不能直接操作內核態,要通過一定的程序從而間接操作內核態

int mian(int argc,char *argv[])
{int ret = 0;int fd = 0;char *filename;char readbuf[100];char writebuf[100];static char usrdata[]={"Usr data!Usr data!Usr data!"};filename=argv[1];fd = open(filename, O_RDWR);if(fd<0){printf("Can't open file %s\r\n",filename);}/*read*/if(atoi(argv[2])==1){ret=read(fd, readbuf, 50); printf("\r\nAPP read data:%s\r\n",readbuf);}/*write*/if(atoi(argv[2])==2){memcpy(writebuf,usrdata,sizeof(usrdata));ret = write(fd, writebuf,50);}/*close*/ret = close(fd);if(ret<0){printf("Can't close %s\r\n",filename);}return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/14890.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/14890.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/14890.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Design to code(2)

【碎碎念】從七點到十一點&#xff0c;累計用時4個小時完成的代碼翻譯Σ(&#xffe3;。&#xffe3;ノ)ノ DCDS圖 順序圖&#xff08;支付過程&#xff09; 交互圖&#xff08;訂單&#xff09; 我的代碼 Payment public class Payment { //定義支付訂單金額 private…

static的了解

【關鍵字】static 使用總結_c static關鍵字-CSDN博客 本文來自上面的文章&#xff0c;這里用于學習&#xff0c;謝謝大佬的分享&#xff01;&#xff01;&#xff01; 非原創&#xff01;&#xff01;&#xff01; 1.一個項目中創建main.cpp和demo.cpp &#xff08;1&#…

FL Studio2025中文最新版本專業編曲軟件有哪些新功能?

FL Studio 21&#xff0c;也被音樂制作愛好者親切地稱為“水果編曲軟件”&#xff0c;是比利時的Image-Line公司研發的一款完整的音樂制作環境或數字音頻工作站&#xff08;DAW&#xff09;。自從1990年代推出以來&#xff0c;FL Studio 以其直觀的用戶界面、豐富的插件支持和強…

Rust分割字符串的常見操作方法

在Rust編程語言中&#xff0c;分割字符串是一個常見的操作&#xff0c;可以通過多種方式實現。以下是一些常用的方法&#xff1a; 使用split方法&#xff1a; split方法可以按照指定的字符或字符序列來分割字符串。它返回一個迭代器&#xff0c;可以迭代分割后的字符串片段。 l…

玩機社區 - 2024年最美社區源碼開源

玩機社區 - 2024年最美社區源碼開源 教程源碼文檔都內置到壓縮包了 https://pan.baidu.com/s/1xwcscTne-JMbmKEntiuAuA?pwd78oi

邏輯分析儀 - 采樣率/采樣深度

采樣深度&#xff08;Sampling Depth&#xff09; 采樣深度指的是邏輯分析儀在一次捕獲過程中可以記錄的最大樣本數量。簡單來說&#xff0c;采樣深度越大&#xff0c;邏輯分析儀可以記錄的數據量就越多。這對于分析長時間的信號變化或復雜的信號序列非常重要。 采樣率&#…

2024年5月23日 (周四) 葉子游戲新聞

《Unclogged》Steam頁面上線 馬桶主題恐怖逃脫解謎Brody制作并發行&#xff0c;一款奇葩創意馬桶主題恐怖逃脫解謎新游《Unclogged》Steam頁面上線&#xff0c;本作暫不支持中文。 Meta人工智能主管楊立昆 大語言模型不會達到人類智能水平IT之家今日&#xff08;5月23日&#x…

QEMU啟動Linux內核

在QEMU環境下啟動linux內核命令如下&#xff1a; QEMU_AUDIO_DRVnone qemu-system-arm -m 256M -nographic -M versatilepb -kernel /home/yukeyang/myfile/linux-6.6.30/arch/arm/boot/zImage -append "consolettyAMA0 rdinit/bin/sh" -dtb arch/arm/boot/dts/arm/…

數據防泄漏系統哪個好用,給文件加密的軟件

數據防泄露&#xff08;Data Leakage Prevention&#xff0c;DLP&#xff09;是指通過一定的技術手段&#xff0c;防止組織指定&#xff08;重要或敏感的&#xff09;數據或信息資產以違反安全策略規定的形式流出組織的一種策略。 信息防泄露以文檔加密技術為核心&#xff0c;…

順序表及其應用

掌握順序表的初始化&#xff0c;初始化、查找、插入、刪除、遍歷、查看實際長度等操作 內容 從鍵盤輸入n個整數&#xff0c;創建順序表。【創建長度為n的順序表】從鍵盤輸入1個整數x&#xff0c;在順序表中查找x所在的位置。若找到&#xff0c;輸出該元素所在的位置(即數組下標…

SQL開窗函數

文章目錄 概念&#xff1a;語法&#xff1a;常用的窗口函數及示例&#xff1a;求平均值&#xff1a;AVG() &#xff1a;求和&#xff1a;SUM():求排名&#xff1a;移動平均計數COUNT():求最大MXA()/小MIN()值求分區內的最大/最小值求當前行的前/后一個值 概念&#xff1a; 開窗…

同旺科技 FLUKE ADPT 隔離版發布 ---- 說明書

所需設備&#xff1a; 1、FLUKE ADPT 隔離版 內附鏈接&#xff1b; 應用于&#xff1a;福祿克Fluke 12E / 15BMax / 17B Max / 101 / 106 / 107 應用于&#xff1a;福祿克Fluke 15B / 17B / 18B

利用文本圖像對比模型進行虛假信息檢測

Harnessing the Power of Text-image Contrastive Models for Automatic Detection of Online Misinformation 論文地址: CVPR 2023 Open Access Repositoryhttps://openaccess.thecvf.com/content/CVPR2023W/WMF/html/Chen_Harnessing_the_Power_of_Text-Image_Contrastive_…

51單片機學習(4)3-1 獨立按鍵控制LED亮滅

#include<REGX52.H> void main() { //P20xFE; P2_01; while(1) { if(P3_10) { P2_00&#xff1b; } else { P2_01&#xff1b; } } }

力扣周賽398題解

特殊數組Ⅰ 如果數組的每一對相鄰元素都是兩個奇偶性不同的數字&#xff0c;則該數組被認為是一個 特殊數組 。 Aging 有一個整數數組 nums。如果 nums 是一個 特殊數組 &#xff0c;返回 true&#xff0c;否則返回 false。 示例 1&#xff1a; 輸入&#xff1a;nums [1] …

SEO:屏蔽流氓蜘蛛抓取

解決屏蔽流氓蜘蛛抓取&#xff0c;如MJ12bot 、DotBot 、BLEXBot 、PetalBot 、DataForSeoBot 1、robots文件屏蔽 User-agent: MJ12bot Disallow: / User-agent:DotBot Disallow: / User-agent:BLEXBot Disallow: / User-agent:PetalBot Disallow: / User-agent:DataForSeoBot…

【C++】<知識點> 標準和文件的輸入輸出

目錄 一、輸入輸出操作 1. 相關的類 2. 標準流對象 3. istream類的成員函數 二、流操縱算子 1. 整數流的基數 2. 浮點數精度的流操縱算子 3. 域寬的流操縱算子 4. 其他的流操縱算子 5. 用戶自定義流操縱算子 三、文件讀寫 1. 文本文件的讀寫 2. 二進制文件的讀寫 3. 文件讀寫…

vue 點擊復制文本到剪貼板

一、首先在vue文件的template中定義復制按鈕 <div size"small" v-if"item.prop jadeCode" class"cell-container"><span>{{ scope.row.jadeCode }}</span> <button click"handleCopy(scope.row.jadeCode)" clas…

一周開發一個客服工單系統

開發一個客服工單系統在一周內完成&#xff0c;需要詳細的計劃和高效的執行。以下是一個詳細的開發計劃&#xff0c;涵蓋每天的主要任務和技術棧選擇&#xff1a; 演示效果&#xff1a;gofly.v1kf.com 技術棧選擇 前端&#xff1a;React.js 或 Vue.js后端&#xff1a;Go (Gin)數…

K8s是如何Watch的?

1. 概述 進入 K8s 的世界&#xff0c;會發現幾乎所有對象都被抽象為了資源(Resource)&#xff0c;包括 K8s Core Resources(Pod, Service, Namespace 等)、CRD、APIService 擴展的資源類型。同時 K8s 底層將這些資源統一抽象為了 RESTful 的存儲(Storage)&#xff0c;一方面服…