Linux設備驅動-練習

練習要求:

一、設備樹

1、配置設備樹信息:將3個led燈和1個風扇使用到的設備信息配置到設備樹中

二、設備驅動層

1、通過of_find_node_by_name、of_get_named_gpion等內核核心層統一的api接口調用外設;

2、通過udev設備管理器自動注冊并創建設備文件

3、通過ioctl控制開啟/關閉外設,其中,3個led燈通過傳遞 設備名稱-次設備號minor 控制具體的某棧燈;

三、應用層

1、多線程開發,第一個線程實現三個燈的流水,第二個線程實現風扇的控制

2、通過open、close、ioctl 對應的字符設備文件調用對應的驅動

1、設備樹的配置

  • arch/arm/boot/dts/stm32mp157a-fsmp1a.dts? (根目錄 / 里面)
leds{led1-gpio = <&gpioe 10 0>;led2-gpio = <&gpiof 10 0>;led3-gpio = <&gpioe 8 0>;
};fans{fan-gpio = <&gpioe 9 0>;
};

2、源碼

2.1、應用程序

  • app.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include "led_driver.h"
#include "fan_driver.h"void *led_task(void *args)
{// 打開文件int fd1 = open("/dev/myled1", O_RDWR);int fd2 = open("/dev/myled2", O_RDWR);int fd3 = open("/dev/myled3", O_RDWR);// 操作硬件for (int i = 0;; i++){if (i % 3 == 0){ioctl(fd1, CMD_LED_ON);ioctl(fd2, CMD_LED_OFF);ioctl(fd3, CMD_LED_OFF);}else if (i % 3 == 1){ioctl(fd1, CMD_LED_OFF);ioctl(fd2, CMD_LED_ON);ioctl(fd3, CMD_LED_OFF);}else{ioctl(fd1, CMD_LED_OFF);ioctl(fd2, CMD_LED_OFF);ioctl(fd3, CMD_LED_ON);}sleep(1);}// 關閉文件close(fd1);close(fd2);close(fd3);
}// void *beep_task(void *args)
// {
//     // 打開文件
//     int fd = open("/dev/mybeep", O_RDWR);
//     char cmd[3] = {0};
//     unsigned short cnt = 0;
//     printf("beep_task\n");
//     for (int i = 0;; i++)
//     {
//         if (cnt % 5 == 0)
//         {
//             ioctl(fd, CMD_BEEP_ON);
//         }
//         else
//         {
//             ioctl(fd, CMD_BEEP_OFF);
//         }
//         sleep(1);
//     }
//     // 關閉文件
//     close(fd);
// }void *fan_task(void *args)
{// 打開文件int fd = open("/dev/myfan", O_RDWR);for(int i=0;;i++){if (i % 2 == 0){ioctl(fd, CMD_FAN_ON);}else{ioctl(fd, CMD_FAN_OFF);}sleep(5);}// 關閉文件close(fd);
}int main(int argc, char *argv)
{pthread_t pid1, pid2, pid3;pthread_create(&pid1, NULL, led_task, NULL);// pthread_create(&pid2, NULL, beep_task, NULL);pthread_create(&pid3, NULL, fan_task, NULL);pthread_join(pid1, NULL);// pthread_join(pid2, NULL);pthread_join(pid3, NULL);return 0;
}

2.2、led驅動程序?

  • led.h:
#ifndef _LED_H_
#define _LED_H_//
#define CMD_LED_ON _IO('L', 0)
#define CMD_LED_OFF _IO('L', 1)
//#endif
  • led.c:
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device/class.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "led_driver.h"int major;              // 主設備號
struct device_node *np; // 設備樹節點
int led1_gpio_no;       // gpio編號
int led2_gpio_no;
int led3_gpio_no;
struct class *pClass; // udev的文件類指針long file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int signal = 0;int minor = (int)file->private_data;int gpio_no;if (minor == 1)gpio_no = led1_gpio_no;else if(minor == 2)gpio_no = led2_gpio_no;else gpio_no = led3_gpio_no;if (cmd == CMD_LED_ON){signal=1;}else{signal=0;}//改變gpio的電平值gpio_set_value(gpio_no, signal);return 0;
}int file_open(struct inode *inode, struct file *file)
{file->private_data = (void*)MINOR(inode->i_rdev);return 0;
}int file_close(struct inode *inode, struct file *file)
{return 0;
}struct file_operations led_fops = {.unlocked_ioctl = file_ioctl,.open = file_open,.release = file_close};int __init led_driver_init(void)
{int minor;// 注冊字符設備驅動 register_chrdevmajor = register_chrdev(0, "myled", &led_fops);if (major == 0){printk("register_chrdev failed\n");return -1;}printk("register_chrdev succes. major=[%d]\n", major);// 從設備樹獲取硬件信息np = of_find_node_by_name(NULL, "leds");if (np == NULL){printk("of_find_node_by_name failed\n");return -1;}printk("of_find_node_by_name success\n");// led1 = 獲取gpio操作句柄led1_gpio_no = of_get_named_gpio(np, "led1-gpio", 0);if (led1_gpio_no < 0){printk("of_get_named_gpio failed\n");return -1;}printk("of_get_named_gpio success.  no1=[%d]\n", led1_gpio_no);if (gpio_request(led1_gpio_no, "led1") < 0){printk("gpio_request failed\n");return -1;}printk("gpio_request success\n");gpio_direction_output(led1_gpio_no, 0);// led1 = 獲取gpio操作句柄led2_gpio_no = of_get_named_gpio(np, "led2-gpio", 0);if (led2_gpio_no < 0){printk("of_get_named_gpio failed\n");return -1;}printk("of_get_named_gpio success.  no2=[%d]\n", led2_gpio_no);if (gpio_request(led2_gpio_no, "led2") < 0){printk("gpio_request failed\n");return -1;}printk("gpio_request success\n");gpio_direction_output(led2_gpio_no, 0);// led3 = 獲取gpio操作句柄led3_gpio_no = of_get_named_gpio(np, "led3-gpio", 0);if (led3_gpio_no < 0){printk("of_get_named_gpio failed\n");return -1;}printk("of_get_named_gpio success.  no3=[%d]\n", led3_gpio_no);if (gpio_request(led3_gpio_no, "led3") < 0){printk("gpio_request failed\n");return -1;}printk("gpio_request success\n");gpio_direction_output(led3_gpio_no, 0);// 初始化gpio// 向設備管理器udev注冊設備文件信息pClass = class_create(THIS_MODULE, "myled");if (IS_ERR(pClass)){printk("class_create failed\n");return -1;}printk("class_create success\n");for (minor = 1; minor < 4; minor++){struct device *pDev = device_create(pClass, NULL, MKDEV(major, minor), NULL, "myled%d", minor);if (IS_ERR(pDev)){printk("device_create failed\n");return -1;}printk("device_create success. major=[%d], monor=[%d]\n", major, minor);}return 0;
}void __exit led_driver_exit(void)
{int minor;// 從設備管理器udev注銷設備文件信息for (minor = 1; minor < 4; minor++){device_destroy(pClass, MKDEV(major, minor));}class_destroy(pClass);// 釋放gpio資源gpio_free(led1_gpio_no);// 注銷字符設備驅動 unregister_chrdevunregister_chrdev(major, "myled");
}module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");

2.3、fan驅動程序

  • fan.h:
#ifndef _FAN_H_
#define _FAN_H_#define CMD_FAN_ON _IO('F', 0)
#define CMD_FAN_OFF _IO('F', 1)#endif
  • fan.c:
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device/class.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "fan_driver.h"int major;//主設備號
struct device_node * np;//設備樹節點
int fan_gpio_no;//設備樹種gpio編號
struct class *pClass;//udev中的文件分類long file_ioctl(struct file * file, unsigned int cmd, unsigned long arg){if(cmd == CMD_FAN_ON){printk("!!!!開風扇\n");gpio_set_value(fan_gpio_no, 1);}else if(cmd == CMD_FAN_OFF){printk("!!!!關風扇\n");gpio_set_value(fan_gpio_no, 0);}return 0;
}int file_open(struct inode * inode, struct file * file){return 0;
}int file_close(struct inode * inode, struct file * file){return 0;
}struct file_operations led_fops={.unlocked_ioctl = file_ioctl,.open = file_open,.release = file_close
};int __init fan_driver_init(void){//注冊字符設備驅動 register_chrdevmajor = register_chrdev(0, "myfan", &led_fops);if(major == 0){printk("register_chrdev failed\n");return -1;}printk("register_chrdev succes. major=[%d]\n", major);//從設備樹獲取硬件信息np = of_find_node_by_name(NULL, "fans");if(np == NULL){printk("of_find_node_by_name failed\n");return -1;  }printk("of_find_node_by_name success\n");//獲取gpio操作句柄fan_gpio_no =of_get_named_gpio(np, "fan-gpio", 0);if (fan_gpio_no < 0){printk("of_get_named_gpio failed\n");return -1;}printk("of_get_named_gpio success.  fan_gpio_no=[%d]\n", fan_gpio_no);if(gpio_request(fan_gpio_no, "fan-gpio") < 0){printk("gpio_request failed\n");return -1;}printk("gpio_request success\n");//初始化gpio//設置gpio為輸出gpio_direction_output(fan_gpio_no, 0);//向設備管理器udev注冊設備文件信息pClass = class_create(THIS_MODULE, "fan_class");if (IS_ERR(pClass)) {printk("class_create failed\n");return -1;}printk("class_create success\n");struct device * pDevice=device_create(pClass, NULL, MKDEV(major, 0), NULL, "myfan");if(IS_ERR(pDevice)){printk("device_create failed\n");return -1;}printk("device_create success\n");return 0;
}void __exit fan_driver_exit(void){//從設備管理器udev注銷設備文件信息device_destroy(pClass, MKDEV(major, 0));class_destroy(pClass);//釋放gpio資源gpio_free(fan_gpio_no);//注銷字符設備驅動 unregister_chrdevunregister_chrdev(major, "myfan");
}module_init(fan_driver_init);
module_exit(fan_driver_exit);
MODULE_LICENSE("GPL");

3、疑問

配置設備樹中,引用關系并沒有搞明白,暫且認為是一種固定的格式。

例如:

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

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

相關文章

Python應用算法之貪心算法理解和實踐

一、什么是貪心算法&#xff1f; 貪心算法&#xff08;Greedy Algorithm&#xff09;是一種簡單而高效的算法設計思想&#xff0c;其核心思想是&#xff1a;在每一步選擇中&#xff0c;都采取當前狀態下最優的選擇&#xff08;即“局部最優解”&#xff09;&#xff0c;希望通…

競爭與冒險問題【數電速通】

時序邏輯電路&#xff1a; 組合邏輯電路中的競爭與冒險問題&#xff1a; 在組合邏輯電路中&#xff0c;競爭和冒險是兩種常見的時序問題&#xff0c;它們通常由電路的延時特性和不完美的設計引起。下面是這兩種現象的詳細解釋&#xff1a; 1. 競爭&#xff08;Race Condition&…

nasm - BasicWindow_64

文章目錄 nasm - BasicWindow_64概述筆記nasm_main.asmmy_build.batEND nasm - BasicWindow_64 概述 學個demo, 這個demo最主要學到了: 不用在調用每個API前都準備陰影區&#xff0c;在API調用后棧平衡。 可以在函數入口處考慮到所用的棧尺寸最大值(16字節對齊&#xff0c;陰…

JavaScript變量的作用域介紹

JavaScript變量的作用域介紹 JavaScript 變量的作用域決定了變量在代碼中的可訪問性。 var 是 JavaScript 中最早用于聲明變量的關鍵字&#xff0c;它函數作用域或全局作用域。 let 關鍵字&#xff0c;具有塊級作用域、全局作用域。 const關鍵字&#xff0c;具有塊級作用域…

Microsoft 365 Copilot中使用人數最多的是哪些應用

今天在瀏覽Microsoft 365 admin center時發現&#xff0c;copilot會自動整理過去30天內所有用戶使用copilot的概況&#xff1a; 直接把這個圖丟給copilot讓它去分析&#xff0c;結果如下&#xff1a; 總用戶情況 總用戶數在各應用中均為 561 人&#xff0c;說明此次統計的樣本…

ue5.2.1 quixel brideg顯示asset not available in uAsset format

我從未見過如此傻x的bug&#xff0c;在ue5.2.1上通過內置quixel下載資源顯示 asset not available in uAsset format 解決辦法&#xff1a;將ue更新到最新版本&#xff0c;通過fab進入商場選擇資源后add to my library 點擊view in launcher打開epic launcher&#xff0c;就可…

當電腦上有幾個python版本Vscode選擇特定版本python

查看當前vscode用的python版本命令 Import sys print(sys.version) 修改VSCODE解釋器 打開 VSCode。 按下 CtrlShiftP打開命令面板。 輸入 Python: Select Interpreter 并選擇它。 從彈出的列表中選擇你安裝的 Python 解釋器。如果你有多個 Python 版本&#xff08;例如…

Vue 中 nextTick 的原理詳解

1. 為什么需要 nextTick Vue 采用 異步渲染機制&#xff0c;當響應式數據發生變化時&#xff0c;Vue 并不會立即更新 DOM&#xff0c;而是將這些變化放入一個 隊列 中&#xff0c;并在 同一事件循環&#xff08;Event Loop&#xff09;中合并相同的修改&#xff0c;最后執行批…

Spring面試題2

1、compareable和compactor區別 定義與包位置:Comparable是一個接口&#xff0c;位于java.lang包,需要類去實現接口&#xff1b;而Compactor是一個外部比較器&#xff0c;位于java.util包 用法&#xff1a;Comparable只需要實現int compareTo(T o) 方法&#xff0c;比較當前對…

DuodooBMS源碼解讀之 cncw_statement模塊

財務應收應付擴展模組用戶使用手冊 一、模塊概述 財務應收應付擴展模組是一個基于 Odoo18 的擴展模塊&#xff0c;主要對財務應收應付相關功能進行了修改和增強。該模塊增加了多個功能模塊&#xff0c;如預收款單模塊、費用類別設置模塊等&#xff0c;同時對發票、公司、銷售…

JUC并發—9.并發安全集合四

大綱 1.并發安全的數組列表CopyOnWriteArrayList 2.并發安全的鏈表隊列ConcurrentLinkedQueue 3.并發編程中的阻塞隊列概述 4.JUC的各種阻塞隊列介紹 5.LinkedBlockingQueue的具體實現原理 6.基于兩個隊列實現的集群同步機制 4.JUC的各種阻塞隊列介紹 (1)基于數組的阻塞…

vue項目啟動時報錯:error:0308010C:digital envelope routines::unsupported

此錯誤與 Node.js 的加密模塊有關&#xff0c;特別是在使用 OpenSSL 3.0 及以上版本時。Vue 項目在啟動時可能會依賴一些舊的加密算法&#xff0c;而這些算法在 OpenSSL 3.0 中默認被禁用&#xff0c;導致 error:0308010C:digital envelope routines::unsupported 錯誤。 解決…

ncDLRES:一種基于動態LSTM和ResNet的非編碼RNA家族預測新方法

現有的計算方法主要分為兩類&#xff1a;第一類是通過學習序列或二級結構的特征來預測ncRNAs家族&#xff0c;另一類是通過同源序列之間的比對來預測ncRNAs家族。在第一類中&#xff0c;一些方法通過學習預測的二級結構特征來預測ncRNAs家族。二級結構預測的不準確性可能會導致…

愛普生 SG-8101CE 可編程晶振在筆記本電腦的應用

在筆記本電腦的精密架構中&#xff0c;每一個微小的元件都如同精密儀器中的齒輪&#xff0c;雖小卻對整體性能起著關鍵作用。如今的筆記本電腦早已不再局限于簡單的辦公用途&#xff0c;其功能愈發豐富多樣。從日常輕松的文字處理、網頁瀏覽&#xff0c;到專業領域中對圖形處理…

SPRING10_getBean源碼詳細解讀、流程圖

文章目錄 ①. getBean方法的入口-DefaultListableBeanFactory②. DefaultListableBeanFactory調用getBean③. 進入到doGetBean方法④. getSingleton三級緩存方法⑤. getSingleton()方法分析⑥. createBean創建對象方法⑦. 對象創建、屬性賦值、初始化⑧. getBean最詳細流程圖 ①…

IDEA中查詢Maven項目的依賴樹

在Maven項目中&#xff0c;查看項目的依賴樹是一個常見的需求&#xff0c;特別是當你需要了解項目中直接或間接依賴了哪些庫及其版本時。你可以通過命令行使用Maven的dependency:tree插件來做到這一點。這個命令會列出項目中所有依賴的樹狀結構。 打開idea項目的終端&#xff…

深入xtquant:財務數據獲取與應用的實戰指南

深入xtquant&#xff1a;財務數據獲取與應用的實戰指南 在量化交易領域&#xff0c;雖然技術分析和市場情緒分析占據了主導地位&#xff0c;但財務數據作為評估公司基本面的重要依據&#xff0c;同樣不可或缺。xtquant作為一個強大的Python庫&#xff0c;提供了便捷的接口來獲…

windows 安裝 stable diffusion

在windows上安裝 stable diffusion&#xff0c;如果windows沒有nvidia顯卡&#xff0c;想只使用CPU可在webui-user.bat中添加命令 set COMMANDLINE_ARGS--no-half --skip-torch-cuda-test 可正常使用stable diffusion&#xff0c;但速度較慢

Kubernetes控制平面組件:APIServer 基于 引導Token 的認證機制

云原生學習路線導航頁&#xff08;持續更新中&#xff09; kubernetes學習系列快捷鏈接 Kubernetes架構原則和對象設計&#xff08;一&#xff09;Kubernetes架構原則和對象設計&#xff08;二&#xff09;Kubernetes架構原則和對象設計&#xff08;三&#xff09;Kubernetes控…

DeepSeek 助力 Vue 開發:打造絲滑的縮略圖列表(Thumbnail List)

前言&#xff1a;哈嘍&#xff0c;大家好&#xff0c;今天給大家分享一篇文章&#xff01;并提供具體代碼幫助大家深入理解&#xff0c;徹底掌握&#xff01;創作不易&#xff0c;如果能幫助到大家或者給大家一些靈感和啟發&#xff0c;歡迎收藏關注哦 &#x1f495; 目錄 Deep…