linux驅動 - 20230817

練習: 通過字符設備驅動分步注冊方式編寫LED燈的驅動,應用程序使用ioctl函數編寫硬件控制邏輯

頭文件 head.h

#ifndef __HEAD_H__
#define __HEAD_H__ 
typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;
}gpio_t;
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR    0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR    0X50000A28#define LED_ON _IOW('l',1,int)//開燈
#define LED_OFF _IOW('l',0,int)//關燈#endif 

驅動代碼

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/slab.h>
#include "head.h"struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;char kbuf[128] = {0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
struct class *cls;
struct device *dev;int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int which;int ret=copy_from_user(&which,(unsigned int *)arg,4);if(ret){printk("copy_from_user err\n");return ret;}// 根據用戶空間功能碼的不同實現硬件不同的控制switch (cmd){case LED_ON: // 開燈switch (which){case 1: // LED1vir_led1->ODR |= (0X1 << 10);break;case 2: // LED2vir_led2->ODR |= (0X1 << 10);break;case 3: // LED3vir_led3->ODR |= (0X1 << 8);break;}break;case LED_OFF: // 關燈switch (which){case 1:vir_led1->ODR &= (~(0X1 << 10));break;case 2:vir_led2->ODR &= (~(0X1 << 10));break;case 3:vir_led3->ODR &= (~(0X1 << 8));break;}break;}return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}// 定義操作方法結構體變量并賦值
struct file_operations fops = {.open = mycdev_open,.unlocked_ioctl = mycdev_ioctl,.release = mycdev_close,
};int all_led_init(void)
{// 寄存器地址的映射vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));if (vir_led1 == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));if (vir_led2 == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_led3 = vir_led1;vir_rcc = ioremap(PHY_RCC_ADDR, 4);if (vir_rcc == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}printk("物理地址映射成功\n");// 寄存器的初始化// rcc(*vir_rcc) |= (3 << 4);// led1vir_led1->MODER &= (~(3 << 20));vir_led1->MODER |= (1 << 20);vir_led1->ODR &= (~(1 << 10));// led2vir_led2->MODER &= (~(3 << 20));vir_led2->MODER |= (1 << 20);vir_led2->ODR &= (~(1 << 10));// led3vir_led3->MODER &= (~(3 << 16));vir_led1->MODER |= (1 << 16);vir_led1->ODR &= (~(1 << 8));printk("寄存器初始化成功\n");return 0;
}static int __init mycdev_init(void)
{// 字符設備驅動注冊// major = register_chrdev(0, "mychrdev", &fops);// if (major < 0)// {//     printk("字符設備驅動注冊失敗\n");//     return major;// }/*** 分步實現字符設備驅動注冊*/int ret;//1. 分配字符設備驅動對象cdev = cdev_alloc();if (cdev == NULL) {printfk("申請字符設備驅動對象失敗\n");ret = -EFAULT;goto OUT1;}//2. 初始化字符設備驅動對象cdev_init(cdev, &fops);//3. 申請設備號if (major > 0) {//靜態指定ret = register_chrdev_region(MKDEV(major, minor), 3, "mycdev");if (ret) {printk("靜態指定設備號失敗\n");goto OUT2;}} else {ret = alloc_chrdev_region(&devno, minor, 3, "mycdev");if (ret) {printk("動態指定設備號失敗\n");goto OUT2;}minor = MINOR(devno);major = MAJOR(devno);}//4. 注冊字符設備驅動對象ret = cdev_add(cdev, MKDEV(major, minor), 3);if (ret) {printk("注冊字符設備驅動對象失敗\n");goto OUT3;}printk("注冊字符設備驅動對象成功\n");// 向上提交目錄信息cls = class_create(THIS_MODULE, "mycdev");if (IS_ERR(cls)){printk("向上提交目錄信息失敗\n");return -PTR_ERR(cls);}printk("向上提交目錄信息成功\n");// 向上提交設備信息int i;for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);if (IS_ERR(dev)){printk("向上提交設備節點失敗\n");return -PTR_ERR(cls);}}printk("向上提交設備節點信息成功\n");// 寄存器映射以及初始化all_led_init();return 0;OUT5:for(--i;i>=0;i--) {device_destroy(cls,MKDEV(major,i));//釋放提交成功的設備信息}class_destroy(cls);//銷毀目錄
OUT4:cdev_del(cdev);
OUT3:unregister_chrdev_region(MKDEV(major,minor),3);
OUT2:kfree(cdev);
OUT1:return ret;
}
static void __exit mycdev_exit(void)
{// 取消地址映射iounmap(vir_led1);iounmap(vir_led2);iounmap(vir_rcc);// 銷毀設備信息int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 銷毀目錄信息class_destroy(cls);// 注銷字符設備驅動unregister_chrdev(major, "mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

應用層測試代碼

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"int main(int argc, char const *argv[])
{char buf[128] = {0};int a, b;int fd = open("/dev/mycdev0", O_RDWR);if (fd < 0){printf("打開設備文件失敗\n");exit(-1);}while (1){printf("請輸入要實現的功能:1(開燈)0(關燈>)");scanf("%d", &a);printf("請輸入要控制的燈:1(LED1) 2(LED2) 3(LED3)>");scanf("%d", &b);switch (a){case 1:ioctl(fd, LED_ON, &b);break;case 0:ioctl(fd, LED_OFF, &b);break;}}close(fd);return 0;
}

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

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

相關文章

問道管理:機器人概念走勢活躍,新時達漲停,拓斯達、豐立智能等大漲

機器人概念17日盤中走勢活躍&#xff0c;到發稿&#xff0c;拓斯達大漲18%&#xff0c;昊志機電漲近16%&#xff0c;豐立智能漲超13%&#xff0c;步科股份、優德精細漲超10%&#xff0c;新時達漲停&#xff0c;天璣科技、兆龍互聯、中大力德漲逾9%。 消息面上&#xff0c;8月16…

HTTP 介紹

HTTP 介紹 HTTP 協議一般指 HTTP&#xff08;超文本傳輸協議&#xff09;。超文本傳輸協議&#xff08;英語&#xff1a;HyperText Transfer Protocol&#xff0c;縮寫&#xff1a;HTTP&#xff09;是一種用于分布式、協作式和超媒體信息系統的應用層協議&#xff0c;是因特網…

Java 計算兩個字符的相似度

在Java中&#xff0c;要計算兩個字符的相似度&#xff0c;可以借助一些字符串相似度算法。以下是幾種常見的字符串相似度算法&#xff1a; Levenshtein距離&#xff1a;也稱為編輯距離&#xff0c;用于計算兩個字符串之間的最小編輯操作次數&#xff08;插入、刪除、替換&…

解決ios隔空播放音頻到macos沒有聲音的問題

解決ios隔空播放音頻到macos沒有聲音的問題 一、檢查隔空播放支持設備和系統要求二、打開隔空播放接收器三、重置MAC控制中心進程END 一、檢查隔空播放支持設備和系統要求 Mac、iPhone、iPad 和 Apple Watch 上“連續互通”的系統要求 二、打開隔空播放接收器 ps;我設備是同一…

java 并發 簡單使用

文章目錄 概要代碼 概要 java 并發 簡單使用 代碼 public static final ExecutorService EXECUTOR_GENERAL new ThreadPoolExecutor(100, 1000,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000));int size 1000;List<UserService> userServices …

element+vue 表格行拖拽功能

解決方案 使用 sortable.js 步驟一&#xff1a; 安裝 npm install vuedraggable步驟二&#xff1a;引入 import Sortable from sortablejs;步驟三&#xff1a; el-table 添加row-key屬性&#xff0c;外層包一層 sortableDiv <div class"sortableDiv"> 拖…

分類預測 | MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測

分類預測 | MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測 目錄 分類預測 | MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測分類效果基本描述程序設計參考資料 分類效果 基本描述 1.MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測&#xff0c;運行環境Matlab2023b及以上…

Django圖書商城系統實戰開發-部署上線操作

Django圖書商城系統實戰開發-打包部署 技術背景掌握 當你需要在服務器上部署Web應用程序時&#xff0c;Nginx是一個強大且常用的選擇。Nginx是一個高性能的Web服務器和反向代理服務器&#xff0c;它可以處理大量的并發連接&#xff0c;并提供負載均衡、緩存、SSL等功能。下面…

seata 的部署和集成

文章目錄 seata的部署和集成一、部署Seata的tc-server1.下載2.解壓3.修改配置4.在nacos添加配置5.創建數據庫表6.啟動TC服務 二、微服務集成seata1.引入依賴2.修改配置文件 TODO三、TC服務的高可用和異地容災1.模擬異地容災的TC集群2.將事務組映射配置到nacos3.微服務讀取nacos…

中期國際:MT4數據挖掘與分析方法:以數據為導向,制定有效的交易策略

在金融市場中&#xff0c;制定有效的交易策略是成功交易的關鍵。而要制定一份可靠的交易策略&#xff0c;數據挖掘與分析方法是不可或缺的工具。本文將介紹如何以數據為導向&#xff0c;利用MT4進行數據挖掘與分析&#xff0c;從而制定有效的交易策略。 首先&#xff0c;我們需…

操作系統搭建相關知識

文章目錄 系統篇netstat命令systemctl命令Systemd系統資源分類&#xff08;12類&#xff09; 網絡篇ifconfig命令操作系統配置動態IP腳本dhcp服務的安裝與配置防火墻相關知識 操作系統常用配置文件 系統篇 netstat命令 netstat指路 systemctl命令 常用于重啟系統的每個服務…

注解@DependsOn

注解 DependsOn 1. 注解由來&#xff1a; DependsOn 注解是 Spring 框架提供的一種注解&#xff0c;用于指定 Bean 之間的依賴關系。通過在 Bean 上添加 DependsOn 注解&#xff0c;可以確保在初始化時先初始化指定的依賴 Bean&#xff0c;從而滿足對象之間的正確順序。 2. 注…

沒有使用springboot 單獨使用spring-boot-starter-logging

如果您不使用Spring Boot框架&#xff0c;但想單獨使用Spring Boot Starter Logging&#xff0c;您可以按照以下步驟進行&#xff1a; 1. 添加Maven依賴&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boo…

Kotlin手寫RxJava變換符

Kotlin手寫RxJava變換符 本文鏈接&#xff0c;點擊這里進入 1、核心點&#xff1a;中轉站存儲之前的數據 2、三行代碼實現RxJava 使用create、map、observer fun main() {// create構造出RxJavaCore存放&#xff0c;lambda執行完的結果create{"WCH"}.map{ // 擴展…

AI繪畫 stable diffusion Midjourney 官方GPT文檔 AIGC百科全書資料收集

教學AI繪畫 AIGC工具 SD教程 ###Redis面試題 單機Redis的qps大概是多少&#xff1f; 項目中用到了哪些Redis的數據類型&#xff1f;為什么這么用&#xff1f; Redis的key到了過期時間就被刪除了嗎&#xff1f;簡述下Redis的過期策略&#xff1f; Redis有哪幾種內存淘汰策略…

Jetpack Compose:探索聲明式UI開發的未來

Jetpack Compose&#xff1a;探索聲明式UI開發的未來 1. 引言 在移動應用開發領域&#xff0c;用戶界面&#xff08;UI&#xff09;開發一直是開發過程中的關鍵挑戰之一。傳統的UI開發方式往往涉及大量繁瑣的布局代碼、手動管理狀態和事件處理&#xff0c;不僅容易引發錯誤&a…

Google瀏覽器點擊鏈接打開新標簽頁

由于新安裝的谷歌瀏覽器點擊鏈接時默認在當前窗口打開非常不方便&#xff0c;這里提供一下解決思路 1、打開瀏覽器輸入任意內容&#xff0c;點擊右上角的設置 2、在彈出的選項欄中點擊See all Search settings 3、點擊Other settings&#xff0c;將指定選項打開即可

C++模板元編程(6)模板參數替換(Template argument substitution)

文章目錄 1、什么是模板參數替換2、實例3、模板參數替換規則 1、什么是模板參數替換 模板參數替換&#xff08;Template argument substitution&#xff09;&#xff1a;在函數模板實例化的過程中&#xff0c;模板參數會被替換為實際的參數類型或值。這個替換過程稱為模板參數…

C#__事件event的簡單使用:工具人下樓問題

// 工具人類 namespace DownStair {delegate void DownStairDelegate(); // 定義了一個下樓委托class ToolMan{public string Name { get; set; } // 聲明工具人的名字屬性// public DownStairDelegate downStairDelegate null; // 初始化委托downStair為空委托// 解決方案pu…

對接海康門禁設備-初始化SDK和登錄設備

對接海康門禁設備&#xff0c;初始化SDK /*** author czm* date 2023/2/15*/ public interface HCNetSDK extends Library {public static HCNetSDK getInstance(String sdkPath) { // sdkPath sdk 目錄路徑System.out.println("sdk_path " sdkPath);HCNetSDK …