【linux-IMX6ULL-LED字符驅動框架完善】

目錄

  • 1.簡介
  • 2.前置知識
    • 2.1 重要函數及結構體
    • 2.2 程序框架流程
  • 3. 代碼詳解:

1.簡介

??在上節,我對linux-IMX6ULL-字符設備驅動簡單框架實驗進行了說明和構建,但是也存在幾個問題;

  • 需要手動指定設備號,不能自動申請;
  • 需要在linux端手動創造設備節點,也就是要用maknod命令;
  • 沒有引入實際設備;
    ??因此這節內容就根據上節的驅動框架,然后結合LED,實現設備號的自動分配和設備節點的自動創建;

2.前置知識

??由于本篇博客不屬于教程類博客,只是作為學習總結和復盤,因此先把相關的重點知識給提前說明,也能起到一個便于快速回顧的目的;

2.1 重要函數及結構體

?下面的函數均進行了實參帶入,具體原定義可以參考源碼;

  • static void __iomem *IMX6U_CCM_CCGR1;
  • IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);
  • register_chrdev_region(newchrled.devid,NEWCHRLED_COUNT,NEWCHRLED_NAME);
  • alloc_chrdev_region(&newchrled.devid,0,NEWCHRLED_COUNT,NEWCHRLED_NAME);
  • struct cdev cdev;
  • struct class *class;
  • struct device *device;
  • cdev_init(&newchrled.cdev, &newchrled_fops);
  • cdev_add(&newchrled.cdev, newchrled.devid,1);
  • class_create(THIS_MODULE, NEWCHRLED_NAME);
  • device_create(newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME);

2.2 程序框架流程

3. 代碼詳解:

??注意幾個點:

  1. 在寫驅動程序時不能直接操控物理寄存器,我們只能操控虛擬化的地址,然后虛擬化的地址通過映射間接操控真實的寄存器;
  2. 操控虛擬化的寄存器地址時是通過read(),write()函數來完成的,不能直接賦值;
  3. 我們接收用戶端的寫的數據時要通過copy_from_user(databuf,buffer,count)函數來實現,不能直接獲取;
  4. 注意出口函數里面的注銷和刪除順序是有要求的,我們最開始是先注冊的設備號,然后注冊操作結構體,但是我們在出口函數里面是先刪除操作結構體,然后再刪除設備號,注意順序是有要求的,其它也是一樣的;

#define LED_MAJOR 200  
#define NEWCHRLED_NAME "newchrled1"
#define NEWCHRLED_COUNT 1/*物理地址*/
#define CCM_CCGR1_BASE				(0x020C406C)
#define SW_MUX_GPIO1_IO03_BASE		(0x020E0068)
#define SW_PAD_GPIO1_IO03_BASE		(0x020E02F4)
#define GPIO1_DR_BASE				(0x0209C000)
#define GPIO1_GDIR_BASE				(0x0209C004)/*虛擬地址,這些地址用于存儲物理地址映射的虛擬地址*/
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;/*宏定義,開關*/
#define	LEDOFF		0
#define LEDON		1/**LED 設備結構體**/
struct newchrled_dev{struct cdev cdev;     /*創建設備結構體*/struct class *class;  /*返回值都是指針類型*/struct device *device; /*創建設備的返回值,是個結構體指針*/dev_t devid;			/*設備號*/int major;				/*主設備號*/int minor;			/*次設備號*/
};
/*創建LED設備的結構體,這里沒有初始化*/
struct newchrled_dev newchrled;
/*led開關函數封裝*/
void led_switch(u8 sta)
{u32 val=0;if(sta==LEDON){val = readl(GPIO1_DR);val &= ~(1<<3);writel(val,GPIO1_DR);}if(sta==LEDOFF){val = readl(GPIO1_DR);val |= (1<<3);writel(val,GPIO1_DR);}
}
/*led初始化封裝*/
void led_inti(void)
{unsigned int val = 0;/*把物理地址進行虛擬化映射,映射完后把虛擬地址賦值給前面定義的虛擬地址*/IMX6U_CCM_CCGR1 	= ioremap(CCM_CCGR1_BASE,4);SW_MUX_GPIO1_IO03 	= ioremap(SW_MUX_GPIO1_IO03_BASE,4);SW_PAD_GPIO1_IO03 	= ioremap(SW_PAD_GPIO1_IO03_BASE,4);GPIO1_DR 			= ioremap(GPIO1_DR_BASE,4);GPIO1_GDIR 			= ioremap(GPIO1_GDIR_BASE,4);/*開時鐘*/val=readl(IMX6U_CCM_CCGR1);val &= ~(3<<26);/*clear*/val |= (3<<26);/*set bit 27 26 into 1*/writel(val,IMX6U_CCM_CCGR1);/*配置寄存器*/writel(0x5,SW_MUX_GPIO1_IO03);writel(0x10B0,SW_PAD_GPIO1_IO03);val = readl(GPIO1_GDIR);val |= (1<<3);writel(val,GPIO1_GDIR);
}static int newchrled_release(struct inode *inode, struct file *file)
{printk("Close ok\r\n");//struct newchrled_dev *dev=(struct newchrled_dev*)file->private_data;return 0;
}static int newchrled_open(struct inode *inode, struct file *file)
{printk("Open ok\r\n");//file->private_data = &newchrled;return 0;
}static ssize_t newchrled_write(struct file *file, const char __user *buffer,size_t count, loff_t *pos)
{unsigned int retvalue;unsigned char databuf[1];/*從用戶哪里獲取寫入的數據,這里不能直接獲得,要通過下面的函數進行獲得*/retvalue=copy_from_user(databuf,buffer,count);if(retvalue<0){printk("Kernel write failed!\r\n");return -EFAULT;}/*判斷是開燈還是關燈*/led_switch(databuf[0]);return 0;
}static const struct file_operations newchrled_fops={.owner 		= 	THIS_MODULE,.write		=	newchrled_write,.open		=	newchrled_open,.release	=	newchrled_release,
};/**into**/
static int __init newchrled_init(void)
{int ret = 0;printk("newchrled init!\r\n");/*1.初始化LED燈,地址映射*/	led_inti();/*2.注冊設備號*/newchrled.major = 0;if(newchrled.major){newchrled.devid = MKDEV(newchrled.major,0);ret = register_chrdev_region(newchrled.devid,NEWCHRLED_COUNT,NEWCHRLED_NAME);}else{ret = alloc_chrdev_region(&newchrled.devid,0,NEWCHRLED_COUNT,NEWCHRLED_NAME);newchrled.major = MAJOR(newchrled.devid);newchrled.minor = MINOR(newchrled.devid);}if(ret<0){printk("newchrled chrdev err!\r\n");return -1;}printk("major=%d,minor=%d\r\n",newchrled.major,newchrled.minor);/*3 注冊操作函數*/newchrled.cdev.owner=THIS_MODULE;cdev_init(&newchrled.cdev, &newchrled_fops);cdev_add(&newchrled.cdev, newchrled.devid,1);/*添加到linux內核中*///  第二步和第三歩本來在前兩節是通過下面的函數實現的://  register_chrdev(LED_MAJOR, LED_NAME,&led_fops);//  這里改寫成了改寫成了兩步,第一步是申請設備號,第二步是注冊設備操作函數/*4.自動創建設備節點*/newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);if (IS_ERR(newchrled.class)){return PTR_ERR(newchrled.class);}/*5.創建一個設備*/newchrled.device = device_create(newchrled.class, NULL, newchrled.devid,NULL,NEWCHRLED_NAME);if (IS_ERR(newchrled.device)){return PTR_ERR(newchrled.device);}return 0;
}/**exit**/
static void __exit newchrled_exit(void)
{printk("newchrled exit!\r\n");/*1.注銷字符操作函數*/cdev_del(&newchrled.cdev);/*2.注銷設備號*/unregister_chrdev_region(newchrled.devid,NEWCHRLED_COUNT);/*3.先摧毀設備*/device_destroy(newchrled.class, newchrled.devid);/*4.后摧毀類*/class_destroy(newchrled.class);
}module_init(newchrled_init);
module_exit(newchrled_exit);
MODULE_LICENSE("GPL");

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

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

相關文章

TCP 與 UDP

0. tcp 與 udp 的 異同特性 TCPUDPname傳輸控制協議用戶數據報協議面向連接&#xff1f; 需要 傳輸數據前建立連接傳輸完畢后斷開連接不需要可靠的傳輸數據&#xff1f; 可靠 有確認機制&#xff08;三次握手&#xff09; 有確認、窗口、重傳、擁塞控制的機制保證數據可靠傳輸…

itertools拼裝迭代器

itertools拼裝迭代器 連接多個迭代器 內置的itertools模塊有一些函數可以把多個迭代器連城一個使用。 chain chain可以把多個迭代器從頭到尾連成一個迭代器。 import itertoolsit itertools.chain([1, 2, 3], [4, 5, 6]) print(list(it))>>> [1, 2, 3, 4, 5, 6]…

操作視頻號小店,新手最關心的問題,一篇給你講解清楚!

大家好&#xff0c;我是電商小V 新手去做視頻號小店的時候&#xff0c;心里面一定是有很多疑問的&#xff0c;會反復咨詢一些最關心的問題&#xff0c;因為他們要做好準備&#xff0c;以防后續做店過程中出現問題&#xff0c;其實新手關心的問題就那幾個&#xff0c;咱們今天就…

C++貪心算法3

過河的最短時間 #include<bits/stdc.h> using namespace std; void f(int); int n; int main() {system("color 1");cin>>n;int a[10010];for(int i0;i<n;i){cin>>a[i];}sort(a0,an);int ta[1];int k1n-2;int k2n-1;while(true){int t1a[0]a[k…

springboot2+mybatis-plus+vue3創建入門小項目[學生管理系統]02[實戰篇]

創建一個 vue 項目 創建這個新的文件夾 創建前端項目 eggbox 數據庫 SQL CREATE DATABASE IF NOT EXISTS egg DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; USE egg;CREATE TABLE stu (id INT AUTO_INCREMENT, -- 自增主鍵name VARCHAR(64) NOT NULL, -- 非空姓名字段&a…

前端傳參的三種方式

1、params 傳參 參數拼接在地址 url 的后面給后臺&#xff1b;地址欄中可見 案例1 地址欄&#xff1a;https://xxxxxxxx/admin/clues/detail?id558 接口代碼&#xff1a; export function getClueDetail(query: any) {return request<clueItem>({url: /clues/detai…

Java:圖書管理系統

目錄 一.book 1.在book包中的Book 類用來定義和引用書的名字&#xff0c;作者&#xff0c;價格&#xff0c;類型等。 2.在book包中的第二個類是BookList是用來構建書架&#xff0c;和書架上的初始書本&#xff0c; 二、ioperations 1.AddOperation (增加圖書) 2.BorrowOp…

保研機試算法訓練個人記錄筆記(七)

輸入格式&#xff1a; 在第1 行給出不超過10^5 的正整數N, 即參賽&#xff5d;人數。隨后N 行&#xff0c;每行給出一位參賽者的 信息和成績&#xff0c;包括其所代表的學校的編號&#xff08;從1 開始連續編號&#xff09;及其比賽成績&#xff08;百分制&#xff09;&#xf…

Linux環境基礎開發工具的使用(yum,vim,gcc/g++,make/Makefile,gdb)

Linux 軟件包管理器-yum 什么是軟件包及安裝方式 在Linux下安裝軟件, 一個通常的辦法是下載到程序的源代碼, 并進行編譯, 得到可執行程序。 但是這樣太麻煩了, 于是有些人把一些常用的軟件提前編譯好, 做成軟件包(可以理解成windows上的安裝程序)放在一個服務器上, 通過包管理…

數據結構——棧(詳細分析)

目錄 &#x1f349;引言 &#x1f349;棧的本質和特點 &#x1f348;棧的基本操作 &#x1f348;棧的特點 &#x1f34d;后進先出 &#x1f34d;操作受限 &#x1f34d;動態調整 &#x1f348;棧的優缺點 &#x1f34d;優點 &#x1f34d;缺點 &#x1f349;棧的應用…

002 遞歸評論 mongodb websocket消息推送

文章目錄 商品評論CommentController.javaComment.javaCommentServiceImpl.javaCommentRepository.javaCommentService.javaWebSocketConfig.javaWebSocketProcess.javaapplication.yamlproductReview.htmlindex.htmlindex.jsindex.css 訂單評論EvaluateMapper.xmlEvaluateMapp…

從零手寫實現 nginx-01-為什么不能有 java 版本的 nginx?

前言 大家好&#xff0c;我是老馬。很高興遇到你。 作為一個 java 開發者&#xff0c;工作中一直在使用 nginx。卻發現一直停留在使用層面&#xff0c;無法深入理解。 有一天我在想&#xff0c;為什么不能有一個 java 版本的 nginx 呢&#xff1f; 一者是理解 nginx 的設計…

HTTP 協議中 GET 和 POST 有什么區別?分別適用于什么場景?

HTTP 協議中 GET 和 POST 是兩種常用的請求方法&#xff0c;它們的區別如下: 1. 參數傳遞方式不同 GET 請求參數是在 URL 中以鍵值對的形式傳遞的&#xff0c;例如:http://www.example.com/&#xff1f;key1value1&k ey2value2。 而 POST 請求參數是在請求體中以鍵值對的…

SQOOP詳細講解

SQOOP安裝及使用 SQOOP安裝及使用SQOOP安裝1、上傳并解壓2、修改文件夾名字3、修改配置文件4、修改環境變量5、添加MySQL連接驅動6、測試準備MySQL數據登錄MySQL數據庫創建student數據庫切換數據庫并導入數據另外一種導入數據的方式使用Navicat運行SQL文件導出MySQL數據庫impo…

數據訪問與Spring Data JPA

數據訪問與Spring Data JPA 在現代Java應用程序中&#xff0c;持久化數據是核心功能之一。Spring Data JPA&#xff08;Java Persistence API&#xff09;為開發者提供了一種簡單且高效的方式來訪問和操作數據庫。在本博文中&#xff0c;我將向您展示如何使用Spring Data JPA來…

數據結構------二叉樹經典習題2

博主主頁: 碼農派大星. 關注博主帶你了解更多數據結構知識 1.非遞歸的前序遍歷 1.用棧來實現 2,前序遍歷是根左右, 先是根節點入棧,,然后不為空時向左遍歷,當為空時就返回向右遍歷,右為空時直接出棧,依次循環即可. public void preOrderNot(TreeNode root){Stack<TreeNo…

科技賦能,打破視障人士的溝通壁壘

在探索如何增強盲人群體的社會參與度與幸福感的旅程中&#xff0c;盲人社交能力提升策略成為了不容忽視的一環。隨著科技的不斷進步&#xff0c;像“蝙蝠避障”這樣的輔助軟件&#xff0c;不僅在日常出行中為盲人提供了實時避障和拍照識別的便利&#xff0c;也在無形中為他們拓…

華為數通 HCIP-Datacom(H12-821)題庫

最新 HCIP-Datacom&#xff08;H12-821&#xff09;完整題庫請掃描上方二維碼訪問&#xff0c;持續更新中。 BGP路由的Update消息中可不包含以下哪些屬性&#xff1f; A、Local Preference B、AS Path C、MED D、Origin 答案&#xff1a;AC 解析&#xff1a;as-path和ori…

深度學習訓練框架——監督學習為例

訓練框架 文章目錄 訓練框架1. 模型網絡結構2. 數據讀取與數據加載2.1Dataloater參數2.2 collate_fn 3. 優化器與學習率調整3.1 優化器3.2 學習率調度 4迭代訓練4.1 train_epoch4.2 train iteration 5.1 保存模型權重 本文內容以pytorch為例 1. 模型網絡結構 自定義網絡模型繼…

測試開發面試題

簡述自動化測試的三大等待 強制等待。直接使用time.sleep()方法讓程序暫停指定的時間。優點是實現簡單&#xff0c;缺點是不夠靈活&#xff0c;可能會導致不必要的等待時間浪費。隱式等待。設置一個固定的等待時間&#xff0c;在這個時間內不斷嘗試去查找元素&#xff0c;如果…