【Linux-驅動開發】

Linux-驅動開發

  • ■ Linux-應用程序對驅動程序的調用流程
  • ■ Linux-file_operations 結構體
  • ■ Linux-驅動模塊的加載和卸載
    • ■ 1. 驅動編譯進 Linux 內核中
    • ■ 2. 驅動編譯成模塊(Linux 下模塊擴展名為.ko)
  • ■ Linux-
  • ■ Linux-
  • ■ Linux-設備號
    • ■ Linux-設備號-分配
      • ■ 靜態分配設備號
      • ■ 動態分配設備號
  • ■ Linux-驅動分類
    • ■ 字符設備:
      • ■ 字符設備-注冊與注銷函數
      • ■ 字符設備-具體操作函數
      • ■ 字符設備-LICENSE 和作者信息
      • ■ 示例一:

■ Linux-應用程序對驅動程序的調用流程

在這里插入圖片描述
在這里插入圖片描述

■ Linux-file_operations 結構體

在 Linux 內核文件 include/linux/fs.h 中有個叫做 file_operations 的結構體,此結構體就是 Linux 內核驅動操作函數集合,

1588 struct file_operations {
1589 struct module *owner;        // 擁有該結構體的模塊的指針,一般設置為 THIS_MODULE
1590 loff_t (*llseek) (struct file *, loff_t, int);  //llseek 函數用于修改文件當前的讀寫位置。
1591 ssize_t (*read) (struct file *, char __user *, size_t, loff_t*);  // read 函數用于讀取設備文件。
1592 ssize_t (*write) (struct file *, const char __user *, size_t,loff_t *); //write 函數用于向設備文件寫入(發送)數據。
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); //unlocked_ioctl 函數提供對于設備的控制功能,與應用程序中的 ioctl 函數對應。
1598 long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //compat_ioctl 函數與 unlocked_ioctl 函數功能一樣,區別在于在 64 位系統上,
32 位的應用程序調用將會使用此函數。在 32 位的系統上運行 32 位的應用程序調用的是
unlocked_ioctl。
1599 int (*mmap) (struct file *, struct vm_area_struct *); //mmap 函數用于將設備的內存映射到進程空間中(也就是用戶空間),一般幀緩
沖設備會使用此函數,比如 LCD 驅動的顯存,將幀緩沖(LCD 顯存)映射到用戶空間中以后應用
程序就可以直接操作顯存了,這樣就不用在用戶空間和內核空間之間來回復制。
1600 int (*mremap)(struct file *, struct vm_area_struct *);
1601 int (*open) (struct inode *, struct file *); //open 函數用于打開設備文件。
1602 int (*flush) (struct file *, fl_owner_t id);
1603 int (*release) (struct inode *, struct file *); //release 函數用于釋放(關閉)設備文件,與應用程序中的 close 函數對應。
1604 int (*fsync) (struct file *, loff_t, loff_t, int datasync); //fasync 函數用于刷新待處理的數據,用于將緩沖區中的數據刷新到磁盤中
1605 int (*aio_fsync) (struct kiocb *, int datasync); //aio_fsync 函數與 fasync 函數的功能類似,只是 aio_fsync 是異步刷新待處理的
數據。
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 *, structpipe_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, 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 };
序號描述
1驅動加載成功以后會在“/dev”目錄下生成一個相應的文件
2比如現在有個叫做/dev/led 的驅動文件,此文件是 led 燈的驅動文件。應用程序使用 open 函數來打開文件/dev/led,使用完成以后使用close 函數關閉/dev/led 這 個文件。 open和 close 就是打開和關閉 led 驅動的函數,如果要點亮或關閉 led
3應用程序運行在用戶空間,而 Linux 驅動屬于內核的一部分,因此驅動運行于內核空間
4
5
6
7
8

■ Linux-驅動模塊的加載和卸載

■ 1. 驅動編譯進 Linux 內核中

這樣當 Linux 內核啟動的時候就會自動運行驅動程序。

■ 2. 驅動編譯成模塊(Linux 下模塊擴展名為.ko)

在Linux 內核啟動以后使用“insmod”命令加載驅動模塊。在調試驅動的時候一般都選擇將其編譯為模塊,這樣我們修改驅動以后只需要編譯一下驅動代碼即可,不需要編譯整個 Linux 代碼。

module_init(xxx_init); //注冊模塊加載函數 當使用“insmod”命令加載驅動的時候, xxx_init 這個函數就會被調用
module_exit(xxx_exit); //注冊模塊卸載函數 當使用“rmmod”命令卸載具體驅動的時候, xxx_exit 函數就會被調用。

示例一:
在這里插入圖片描述
第15行,調用函數module_init 來聲明 xxx_init 為驅動入口函數,當加載驅動的時候 xxx_init函數就會被調用。
第16行,調用函數module_exit來聲明xxx_exit為驅動出口函數,當卸載驅動的時候xxx_exit函數就會被調用。

關鍵字功能作用說明
加載驅動insmodinsmod 是最簡單的模塊加載命令 例如 insmod drv.ko ,
insmod 命令不能解決模塊的依賴關系,
比如 drv.ko 依賴 first.ko 這個模塊,就必須先使用insmod 命令加載 first.ko 這個模塊,然后再加載 drv.ko 這個模塊。
加載驅動modprobemodprobe 會分析模塊的依賴關系,然后會將所有的依賴模塊都加載到內核中,
因此modprobe 命令相比 insmod 要智能一些。
推薦使用 modprobe 命令來加載驅動。
modprobe 命令默認會去/lib/modules/目錄中查找模塊,
卸載驅動modprobe -r例如 modprobe -r drv.ko
使用 modprobe 命令可以卸載掉驅動模塊所依賴的其他模塊,前提是這些依賴模塊已經沒有被其他模塊所使用,否則就不能使用 modprobe 來卸載驅動模塊。
卸載驅動rmmod例如 rmmod drv.ko
推薦使用 rmmod 命令。

■ Linux-

■ Linux-

■ Linux-設備號

Linux 中每個設備都有一個設備號,設備號由主設備號和次設備號兩部分組成,
主設備號表示某一個具體的驅動,
次設備號表示使用這個驅動的各個設備。
dev_t 其實就是 unsigned int 類型,是一個 32 位的數據類型。高 12 位為主設備號, 低 20 位為次設備號。

typedef unsigned int __u32;      
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t dev_t;   dev_t 其實就是 unsigned int 類型,是一個 32 位的數據類型。高 12 位為主設備號, 低 20 位為次設備號。

在include/linux/kdev_t.h 中提供了幾個關于設備號的操作函數(本質是宏),如下所示:

#define MINORBITS 20       宏 MINORBITS 表示次設備號位數,一共是 20 位。
#define MINORMASK ((1U << MINORBITS) - 1)         宏 MINORMASK 表示次設備號掩碼。
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))  宏 MAJOR 用于從 dev_t 中獲取主設備號,將 dev_t 右移 20 位即可。
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))  宏 MINOR 用于從 dev_t 中獲取次設備號,取 dev_t 的低 20 位的值即可。
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))   宏 MKDEV 用于將給定的主設備號和次設備號的值組合成 dev_t 類型的設備號。

■ Linux-設備號-分配

■ 靜態分配設備號

具體分配的內容可以查看文檔 Documentation/devices.txt。
看硬件平臺運行過程中有沒有使用這個主設備號,使用“cat /proc/devices” 命令即可查看當前系統中所有已經使用了的設備號。

■ 動態分配設備號

靜態分配設備號很容易帶來沖突問題, Linux 社區推薦使用動態分配設備號,在注冊字符設備之前先申請一個設備號,系統會自動給你一個沒有被使用的設備號,這樣就避免了沖突。

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)  //用于申請設備號,dev:保存申請到的設備號。baseminor: 次設備號起始地址, alloc_chrdev_region 可以申請一段連續的多個設備號,這些設備號的主設備號一樣,但是次設備號不同,次設備號以 baseminor 為起始地址地址開始遞增。一般 baseminor 為 0,也就是說次設備號從 0 開始。count: 要申請的設備號數量。name:設備名字。void unregister_chrdev_region(dev_t from, unsigned count)     //設備號釋放函數from:要釋放的設備號。count: 表示從 from 開始,要釋放的設備號數量。

■ Linux-驅動分類

■ 字符設備:

字符設備就是一個一個字節,按照字節流進行讀寫操作的設備,讀寫數據是分先后順序的。比如我們最常見的點燈、按鍵、 IIC、 SPI,LCD 等等都是字符設備,這些設備的驅動就叫做字符設備驅動。

■ 字符設備-注冊與注銷函數

static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)major: 主設備號,
name:設備名字,指向一串字符串。
fops: 結構體 file_operations 類型指針,指向設備的操作函數集合變量。

■ 字符設備-具體操作函數

打開
關閉

寫 操作

■ 字符設備-LICENSE 和作者信息

MODULE_LICENSE() //添加模塊 LICENSE 信息
MODULE_AUTHOR() //添加模塊作者信息

■ 示例一:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>#define CHRDEVBASE_MAJOR      200           //主設備號
#define CHRDEVBASE_NAME     "chrdevbase"    //名字static char readbuf[100]; /*讀緩沖 */
static char writebuf[100];  /* 寫緩沖 */
static char kerneldata[] = {"kernel data!"};static int chrdevbase_open(struct inode *inode, struct file *filp)
{// printk("chrdevbase_open\r\n");return 0;
}static int chrdevbase_release(struct inode *inode, struct file *filp)
{// printk("chrdevbase_release\r\n");return 0;   
}static ssize_t chrdevbase_read(struct file *filp, __user char *buf, size_t count,loff_t *ppos)
{ int ret  = 0;//printk("chrdevbase_read\r\n");memcpy(readbuf, kerneldata, sizeof(kerneldata));ret = copy_to_user(buf, readbuf, count);if(ret == 0) {} else {}return 0;  
}static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{int ret = 0;//printk("chrdevbase_write\r\n");ret = copy_from_user(writebuf, buf, count);if(ret == 0) {printk("kernel recevdata:%s\r\n", writebuf);} else {}return 0; 
}/** 字符設備 操作集合*/
static struct file_operations chrdevbase_fops={.owner = THIS_MODULE,.open = chrdevbase_open,.release = chrdevbase_release,.read = chrdevbase_read,.write = chrdevbase_write,
};static int __init chrdevbase_init(void)
{int ret = 0;printk("chrdevbase_init\r\n");/* 注冊字符設備 */ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(ret < 0) {printk("chrdevbase init failed!\r\n");}return 0;
}static void __exit chrdevbase_exit(void)
{printk("chrdevbase_exit\r\n");	/* 注銷字符設備 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
}/*模塊入口與出口
*/
module_init(chrdevbase_init);  /* 入口 */
module_exit(chrdevbase_exit);  /* 出口 */MODULE_LICENSE("GPL");      
MODULE_AUTHOR("zuozhongkai");

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

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

相關文章

React Native 之 主題偏好(十一)

如果你的 React Native 版本較新&#xff0c;它提供一個主題API useColorScheme&#xff0c;你可以直接使用它。如果不是&#xff0c;需安裝額外的庫&#xff0c;如react-native-appearance。 下面是一個使用 react-native-appearance&#xff08;或 useColorScheme&#xff0…

家電維修上門維修小程序怎么搭建制作?

?在家庭生活中&#xff0c;家電的維修問題一直是人們關注的焦點。隨著微信小程序的普及&#xff0c;家電維修服務行業也迎來了線上轉型的機遇。一款便捷、高效的家電維修上門維修小程序&#xff0c;不僅能為維修服務商帶來新的客戶&#xff0c;也能為用戶帶來更便捷的服務體驗…

[Algorithm][動態規劃][路徑問題][下降路徑最小和][最小路徑和][地下城游戲]詳細講解

目錄 1.下降路徑最小和1.題目鏈接2.算法原理詳解3.代碼實現 2.最小路徑和1.題目鏈接2.算法原理詳解3.代碼實現 3.地下城游戲1.題目鏈接2.算法原理詳解3.代碼實現 1.下降路徑最小和 1.題目鏈接 下降路徑最小和 2.算法原理詳解 思路&#xff1a; 確定狀態表示 -> dp[i][j]的…

用WPS將多張圖片生成一個pdf文檔,注意參數設置

目錄 1 新建一個docx格式的文檔 2 向文檔中插入圖片 3 設置頁邊距 4 設置圖片大小 5 導出為pdf格式 需要把十幾張圖片合并為一個pdf文件&#xff0c;本以為很簡單&#xff0c;迅速從網上找到兩個號稱免費的在線工具&#xff0c;結果浪費了好幾分鐘時間&#xff0c;發現需要…

面試-軟件工程與設計模式相關,Spring簡介

面試-軟件工程與設計模式相關&#xff0c;Spring簡介 1.編程思想1.1 面向過程編程1.2 面向對象編程1.2.1 面向對象編程三大特征 1.3 面向切面編程1.3.1 原理1.3.2 大白話&#xff1f;1.3.3 名詞解釋1.3.4 實現 2. 耦合與內聚2.1 耦合性2.2 內聚性 3. 設計模式3.1 設計模型七大原…

【Nodejs-多進程之Cluster】

cluster 模塊是 Node.js 提供的一個用于多進程的模塊&#xff0c;它可以輕松地創建一組共享同一個服務器端口的子進程&#xff08;worker進程&#xff09;。通過使用 cluster 模塊&#xff0c;可以充分利用多核系統&#xff0c;提高應用程序的性能和可靠性。 基本原理 cluste…

#php把pdf文件轉成圖片#

本地環境 系統&#xff1a;win11 64位 環境&#xff1a;phpStudy PHP版本&#xff1a;8.0.2 礦建&#xff1a;laravel 配置擴展 一、安裝imageMagick 下載地址&#xff1a;https://imagemagick.org/script/download.php 安裝版本&#xff1a;ImageMagick-最新版本-Q16-HDRI-x64…

Docker: exec命令淺析

簡介 Docker exec命令是Docker提供的一個強大工具&#xff0c;用于在正在運行的容器中執行命令。在此將介紹Docker exec命令的用法和示例&#xff0c;幫助大家更好地理解和使用這個命令。 Docker是一種流行的容器化平臺&#xff0c;允許用戶在容器中運行應用程序。有時候&#…

React開發環境配置詳細講解-04

React環境 前端隨著規范化&#xff0c;可以說規范和環境插件配置滿天飛&#xff0c;筆者最早接觸的是jquery&#xff0c;那個開發非常簡單&#xff0c;只要引入jquery就可以了&#xff0c;當時還寫了一套UI框架&#xff0c;至今在做小型項目中還在使用&#xff0c;show一張效果…

一款顏值頗高的虛擬列表!差點就被埋沒了,終于還是被我挖出來了

大家好&#xff0c;我是曉衡&#xff01; 今天&#xff0c;推薦一款頗有顏值的虛擬列表組件&#xff0c;不然真的被埋沒就可惜了&#xff01; 我們先來看下效果&#xff1a; 感覺怎么樣&#xff1f;還不錯吧&#xff01; 為什么說這個資源差點被埋沒呢&#xff1f;因為個朋友找…

用數據,簡單點!奇點云2024 StartDT Day數智科技大會,直播見

在充滿挑戰的2024&#xff0c;企業如何以最小化的資源投入和試錯成本&#xff0c;挖掘新的增長機會&#xff0c;實現確定性發展&#xff1f; “簡單點”是當前商業環境的應對策略&#xff0c;也是奇點云2024 StartDT Day的核心理念。 5月28日&#xff0c;由奇點云主辦的2024 S…

Linux —— 信號量

Linux —— 信號量 什么是信號量P操作&#xff08;Wait操作&#xff09;V操作&#xff08;Signal操作&#xff09;信號量的類型 一些接口POSIX 信號量接口&#xff1a;其他相關命令&#xff1a; 基于循環隊列的生產者和消費者模型同步關系 多生產多消費 我們今天接著來學習信號…

【譯】組復制和 Percona XtraDB 集群: 常見操作概述

原文地址&#xff1a;Group Replication and Percona XtraDB Cluster: Overview of Common Operations 在這篇博文中&#xff0c;我將概述使用 MySQL Group Replication 8.0.19&#xff08;又稱 GR&#xff09;和 Percona XtraDB Cluster 8 (PXC)&#xff08;基于 Galera&…

Jetbrains插件AI Assistant,終于用上了

ai assistant激活成功后&#xff0c;如圖 ai assistant獲取&#xff1a;https://web.52shizhan.cn/activity/ai-assistant 主要功能如下

Spring Boot 配置使用 PEM 格式SSL/TLS證書和私鑰

傳統的為 Spring Boot 配置SSL/TLS證書一般都會把證書打包成 JKS(Java KeyStore) 或 PKCS12 (Public Key Cryptographic Standards) 格式&#xff0c;然后為Spring Boot 增加以下類似配置&#xff1a; # The format used for the keystore. It could be set to JKS in case it…

SpringBoot(六)之內嵌容器

SpringBoot&#xff08;六&#xff09;之內嵌容器 文章目錄 SpringBoot&#xff08;六&#xff09;之內嵌容器內嵌容器的特點如何替換默認容器1.pom形式2.主動配置 如何通過配置切換serlvet容器 Spring Boot 提供了一種便捷的方式來創建獨立運行的 Spring 應用程序&#xff0c;…

計算機畢業設計hadoop+spark微博輿情大數據分析 微博爬蟲可視化 微博數據分析 微博采集分析平臺 機器學習(大屏+LSTM情感分析+爬蟲)

電商數據建模 一、分析背景與目的 1.1 背景介紹 電商平臺數據分析是最為典型的一個數據分析賽道&#xff0c;且電商數據分析有著比較成熟的數據分析模型&#xff0c;比如&#xff1a;人貨場模型。此文中我將通過分析國內最大的電商平臺——淘寶的用戶行為&#xff0c;來鞏固數…

算法打卡 Day13(棧與隊列)-滑動窗口最大值 + 前 K 個高頻元素 + 總結

文章目錄 Leetcode 239-滑動窗口最大值題目描述解題思路 Leetcode 347-前 K 個高頻元素題目描述解題思路 棧與隊列總結 Leetcode 239-滑動窗口最大值 題目描述 https://leetcode.cn/problems/sliding-window-maximum/description/ 解題思路 在本題中我們使用自定義的單調隊列…

C語言指針指針和數組筆試題(必看)

前言&#xff1a; 前面介紹了指針的大體內容&#xff0c;如果接下來能夠把這些代碼的含義搞得清清楚楚&#xff0c;那么你就是代碼king&#xff01; 一維數組&#xff1a; int a[] {1,2,3,4}; printf("%d\n",sizeof(a)); printf("%d\n",sizeof(a0)); pr…