驅動DAY4 字符設備驅動分步注冊和ioctl函數點亮LED燈

頭文件

#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/cdev.h>
#include <linux/device.h>
#include "head.h"
#include <linux/slab.h>
#include <linux/io.h>struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
struct class *cls;
struct device *dev;char kbuf[128] = {0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;// 封裝操作方法
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)
{// 根據用戶空間功能碼的不同實現硬件不同的控制switch (cmd){case LED_ON: // 開燈switch (arg){case 1:vir_led1->ODR |= (0X1 << 10);break;case 2:vir_led2->ODR |= (0X1 << 10);break;case 3:vir_led3->ODR |= (0X1 << 8);break;default:printk("燈選擇輸入錯誤\n");break;}break;case LED_OFF: // 關燈switch (arg){case 1:vir_led1->ODR &= (~(0X1 << 10));break;case 2:vir_led2->ODR &= (~(0X1 << 10));break;case 3:vir_led3->ODR &= (~(0X1 << 8));break;default:printk("燈選擇輸入錯誤\n");break;}break;default:printk("開關燈選擇輸入錯誤\n");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)
{int ret;// 1.分配字符設備驅動對象cdev = cdev_alloc();if (cdev == NULL){printk("申請字符設備驅動對象失敗\n");ret = -EFAULT;goto OUT1;}printk("申請字符設備驅動成功\n");// 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); // 根據設備號獲取主設備號}printk("申請設備號成功\n");// 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");ret = -PTR_ERR(cls);goto OUT4;}printk("向上提交目錄成功\n");// 向上提交設備節點信息int i=0;for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);if (IS_ERR(dev)){printk("向上提交設備節點信息失敗\n");ret = -PTR_ERR(dev);goto OUT5;}}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)
{// 銷毀設備節點信息int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 銷毀目錄class_destroy(cls);// 注銷字符設備驅動對象cdev_del(cdev);// 釋放設備號unregister_chrdev_region(MKDEV(major, minor), 3);// 釋放對象空間kfree(cdev);
}
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;default:printf("開關燈功能選擇輸入錯誤\n");break;}}close(fd);return 0;
}

Makefile

#通用makefile
modname ?= demo
arch ?= arm
ifeq ($(arch),arm)
KERNELDIR:= /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
#生成ARM架構
else
KERNELDIR:= /lib/modules/$(shell uname -r)/build
#生成x86架構
endifPWD:= $(shell pwd)
all:make -C $(KERNELDIR) M=$(PWD) modulesclean:make -C $(KERNELDIR) M=$(PWD) cleanobj-m:= $(modname).o

實驗現象

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

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

相關文章

一百五十八、Kettle——Kettle各版本及其相關安裝包分享(網盤鏈接,不需積分、不需驗證碼) 持續更新、持續分享

一、目的 最近因為kettle9.3的shim問題看了好多博客&#xff0c;都沒有網盤分享。后來有一位博主分享了kettle9.2的shim安裝包&#xff0c;已經很感謝他&#xff0c;但是是博客分享&#xff0c;下載還需要搞驗證碼下載碼之類的。 kettle9.2的shim安裝包下載好后&#xff0c;一…

圖數據庫_Neo4j基于docker服務版安裝_Neo4j Desktop桌面版安裝---Neo4j圖數據庫工作筆記0004

然后我們來看看如何用docker來安裝Neo4j community server 首先去執行docker pull neo4j:3.5.22-community 去拉取鏡像 然后執行命令就可以安裝了 可以用docker ps查看一下 看看暴露了哪些端口 然后再看一下訪問一下這個時候,要用IP地址了注意 然后再來看一下安裝Desktop 去下…

Sigmastar SSC8826Q 2K行車記錄儀解決方案

一、方案描述 行車記錄儀是智能輔助汽車駕駛&#xff0c;和管理行車生活的車聯網智能終端設備&#xff0c;利用智能芯片處理器、GPS定位、網絡通信、自動控制等技術&#xff0c;將與行車生活有關的各項數據有機地結合在一起。 行車記錄儀如今已經成了必不可少的車載用品之一&…

雙向-->帶頭-->循環鏈表

目錄 一、雙向帶頭循環鏈表概述 1.什么是雙向帶頭循環鏈表 2.雙向帶頭循環鏈表的優勢 3.雙向帶頭循環鏈表簡圖 二、雙向帶頭循環鏈表的增刪查改圖解及代碼實現 1.雙向帶頭循環鏈表的頭插 2.雙向帶頭循環鏈表的尾插 3.雙向帶頭循環鏈表的頭刪 4.雙向帶頭循環鏈表的尾刪…

ATF(TF-A) 威脅模型匯總

安全之安全(security)博客目錄導讀 目錄計劃如下&#xff0c;相關內容補充中&#xff0c;待完成后進行超鏈接&#xff0c;敬請期待&#xff0c;歡迎您的關注 1、通用威脅模型 2、SPMC威脅模型 3、EL3 SPMC威脅模型 4、fvp_r 平臺威脅模型 5、RSS-AP接口威脅模型 威脅建模是安全…

淺學實戰:探索PySpark實踐,解鎖大數據魔法!

文章目錄 Spark和PySpark概述1.1 Spark簡介1.2 PySpark簡介 二 基礎準備2.1 PySpark庫的安裝2.2 構建SparkContext對象2.3 SparkContext和SparkSession2.4 構建SparkSession對象2.5 PySpark的編程模型 三 數據輸入3.1 RDD對象3.2 Python數據容器轉RDD對象3.3 讀取文件轉RDD對象…

IDEA的常用設置,讓你更快速的編程

一、前言 在使用JetBrains的IntelliJ IDEA進行軟件開發時&#xff0c;了解和正確配置一些常用設置是非常重要的。IDEA的強大功能和定制性使得開發過程更加高效和舒適。 在本文中&#xff0c;我們將介紹一些常用的IDEA設置&#xff0c;幫助您更好地利用IDEA進行開發。這些設置包…

Java面向對象——封裝以及this關鍵字

封 裝 封裝是面向對象編程&#xff08;OOP&#xff09;的三大特性之一&#xff0c;它將數據和操作數據的方法組合在一個單元內部&#xff0c;并對外部隱藏其具體實現細節。在Java中&#xff0c;封裝是通過類的訪問控制修飾符&#xff08;如 private、protected、public&#x…

Linux MQTT智能家居項目(智能家居界面布局)

文章目錄 前言一、創建工程項目二、界面布局準備工作三、正式界面布局總結 前言 一、創建工程項目 1.選擇工程名稱和項目保存路徑 2.選擇QWidget 3.添加保存圖片的資源文件&#xff1a; 在工程目錄下添加Icon文件夾保存圖片&#xff1a; 將文件放入目錄中&#xff1a; …

網絡層協議

網絡層協議 IP協議基本概念協議頭格式網段劃分特殊的IP地址IP地址的數量限制私有IP地址和公網IP地址路由IP協議頭格式后續 在復雜的網絡環境中確定一個合適的路徑 IP協議 承接上文&#xff0c;TCP協議并不會直接將數據傳遞給對方&#xff0c;而是交付給下一層協議&#xff0c;…

機器學習基礎(四)

KNN算法 KNN:K-Nearest Neighbor,最近領規則分類。 為了判斷位置實例的類別,以所有已知類別的實例作為參照選擇參數K。計算未知實例與所有已知實例的距離。(一般采用歐氏距離)選擇最近K個已知實例。根據少數服從多數的投票法則,讓未知實例歸類為K個最近鄰樣本中最多數的類…

音視頻FAQ(三):音畫不同步

摘要 本文介紹了音畫不同步問題的五個因素&#xff1a;編碼和封裝階段、網絡傳輸階段、播放器中的處理階段、源內容產生的問題以及轉碼和編輯。針對這些因素&#xff0c;提出了相應的解決方案&#xff0c;如使用標準化工具、選擇強大的傳輸協議、自適應緩沖等。此外&#xff0…

uniapp微信小程序區分正式版,開發版,體驗版

小程序代碼區分是正式版&#xff0c;開發版&#xff0c;還是體驗版 通常正式和開發環境需要調用不同域名接口&#xff0c;發布時需要手動更換 或者有些東西不想在正式版顯示&#xff0c;只在開發版體驗版中顯示&#xff0c;也需要去手動隱藏 官方沒有明確給出判斷環境的方法&a…

SciencePub學術 | CCF推薦重點計算機SCIE征稿中

SciencePub學術 刊源推薦: CCF推薦重點計算機SCIE征稿中&#xff01;信息如下&#xff0c;錄滿為止&#xff1a; 一、期刊概況&#xff1a; CCF推薦重點SCIE簡介 【期刊簡介】IF&#xff1a;4.0&#xff0c;JCR2區&#xff0c;中科院3區&#xff1b; 【版面類型】正刊&#…

Swift 基礎

工程目錄 請點擊下面工程名稱&#xff0c;跳轉到代碼的倉庫頁面&#xff0c;將工程 下載下來 Demo Code 里有詳細的注釋 點擊下載代碼&#xff1a;swift-01

記錄一下基于jeecg-boot3.0的待辦消息移植記錄

因為之前沒有記錄&#xff0c;所以還要看代碼進行尋找&#xff0c;比較費勁&#xff0c;所以今天記錄一下&#xff1a; 1、后端 SysAnnouncementController 下面函數增加待辦的幾個顯示內容給前端用 具體代碼如下&#xff1a; /*** 功能&#xff1a;補充用戶數據&#xff0c…

由小波變換模極大值重建信號

給定信號&#xff0c; 令小波變換的尺度 則x(t)的二進小波變換為 令為取模極大值時的橫坐標&#xff0c;那么就是模極大值。 目標是由坐標、模極大值及最后一級的低頻分量重建信號x(t) 為了重建x(t)&#xff0c;假定有一信號集合h(t)&#xff0c;該集合中信號的小波變換和x(…

打印出二進制的奇數位和偶數位

void print(int a) {int i0;printf("奇數位&#xff1a;");for(i30;i>0;i-2){printf("%d ",(a>>i)&1);}printf("\n");printf("偶數位&#xff1a;");for(i31;i>1;i-2){printf("%d ",(a>>i)&1);} …

人臉圖像處理

1,人臉圖像與特征基礎 人臉圖像的特點 規律性: 人的兩只眼睛總是對稱分布在人臉的上半部分,鼻子和嘴唇中心點的連線基本與兩眼之間的連線垂直,嘴絕對不會超過眼鏡的兩端點(雙眼為d,則雙眼到嘴巴的垂直距離一般在0.8-1.25) 唯一性 非侵擾與便利性 可擴展性 人臉圖像的應用 身份…

Linux MQTT智能家居(溫度,濕度,環境監測,攝像頭等界面布局設置)

文章目錄 前言一、溫度濕度曲線布局二、環境監測界面布局三、攝像頭界面布局總結 前言 本篇文章來完成另外三個界面的布局設置。 這里會使用到 feiyangqingyun的一些控件庫。 一、溫度濕度曲線布局 TempHumtiy.h: #ifndef TEMPHUMTIY_H #define TEMPHUMTIY_H#include <…