当前位置: 首页 > news >正文

linux驱动开发--day4(字符设备驱动注册内部流程、及实现备文件和设备的绑定下LED灯实验)

一、字符设备驱动注册的内部过程

1.分配struct cdev对象空间

2.初始化struct cdev对象

3.注册cdev对象

二、注册字符设备驱动分步实现

1.分配字符设备驱动对象

2.字符设备驱动对象初始化

3.设备号的申请

4.根据申请的设备号和驱动对象注册驱动

三、open函数回调驱动中操作方法open的路线

1.应用层打开文件系统中的存在文件,会有inode号,且系统内核中就会存在一个inode对象(struct inode)保存文件相关信息

2.inode对象里字符设备结构体成员(struct cdev)里,有操作方法结构体成员(struct file_operations *ops)

3.操作方法结构体中会调用VFS(虚拟文件系统层)中sys_open()得到文件描述符,申请file对象并填充,根据路线再回调驱动中的open操作方法

四、通过文件描述符回调驱动操作的路线

1.因为文件描述符依赖进程存在,只要进程加载到系统上,系统内核就存在task_struct对象描述进程信息

2.在进程里打开一个文件,内核就会存在一个struct file对象,用于保存打开文件的信息

3.struct file对象的成员里fd_array数组保存的每个成员是打开的文件的相关信息

4.数组每个成员都是struct file类型,存储的是打开文件的相关信息,里面有操作方法结构体(驱动中的操作方法)去驱使硬件实现特定功能

任务:

通过字符设备驱动分步注册方式编写LED驱动,完成设备文件和设备的绑定
cdev)_led.c:

#include <linux/init.h>
#include <linux/module.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/uaccess.h>
#include<linux/slab.h>
#include<linux/io.h>
#include"head.h"struct cdev* cdev;
unsigned int major=0;
unsigned int minor=0;
dev_t devno;
module_param(major,uint,0664);
struct class* cls;
struct device* dev;
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)
{int min=MINOR(inode->i_rdev);file->private_data=(void *)min;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
long mydev_ioctl(struct file* file,unsigned int cmd,unsigned long arg)
{int min=(int)file->private_data;switch(min){case 0: //控制LED1switch(cmd){case LED_ON:  //开灯vir_led1->ODR |= 1<<10;break;case LED_OFF: //关灯vir_led1->ODR &= (~(1<<10));break;}break;case 1:  //控制LED2switch(cmd){case LED_ON:  //开灯vir_led2->ODR |= 1<<10;break;case LED_OFF: //关灯vir_led2->ODR &= (~(1<<10));break;}break;case 2:  //控制LED3switch(cmd){case LED_ON:  //开灯vir_led3->ODR |= 1<<8;break;case LED_OFF: //关灯vir_led3->ODR &= (~(1<<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=mydev_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;//为字符设备驱动对象申请空间cdev=cdev_alloc();if(cdev==NULL){printk("字符设备驱动对象申请空间失败\n");ret=-EFAULT;goto out1;}printk("申请对象空间成功\n");//初始化字符设备驱动对象cdev_init(cdev,&fops);//申请设备号if(major>0)//静态指定设备号{ret=register_chrdev_region(MKDEV(major,minor),3,"myled");if(ret){printk("静态申请设备号失败\n");goto out2;}}else if(major==0)//动态申请设备号{ret=alloc_chrdev_region(&devno,minor,3,"myled");if(ret){printk("动态申请设备号失败\n");goto out2;}major=MAJOR(devno);//获取主设备号minor=MINOR(devno);//获取次设备号}printk("申请设备号成功\n");//注册字符设备驱动对象ret=cdev_add(cdev,MKDEV(major,minor),3);if(ret){printk("注册字符设备驱动对象失败\n");goto out3;}printk("注册字符设备驱动对象成功\n");//寄存器映射以及初始化all_led_init();//向上提交目录信息cls=class_create(THIS_MODULE,"myled");if(IS_ERR(cls)){printk("向上提交目录失败\n");ret=-PTR_ERR(cls);goto out4;}printk("向上提交目录成功\n");//向上提交设备节点信息int i;for(i=0;i<3;i++){dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);if(IS_ERR(dev)){printk("向上提交设备节点信息失败\n");ret=-PTR_ERR(dev);goto out5;}}printk("向上提交设备信息成功\n");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);//注销驱动对象cdev_del(cdev);//释放设备号unregister_chrdev_region(MKDEV(major,minor),3);//释放对象空间kfree(cdev);}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

test.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"
int main(int argc, const char *argv[])
{char buf[128] = "";int a;int fd;while (1){printf("请选择要打开的灯(1,2,3)\n");scanf(" %d", &a);switch (a){case 1:fd = open("/dev/myled0", O_RDWR);if (fd < 0){printf("设备文件打开失败\n");exit(-1);}printf("打开文件myled0成功\n");break;case 2:fd = open("/dev/myled1", O_RDWR);if (fd < 0){printf("设备文件打开失败\n");exit(-1);}printf("打开文件myled1成功\n");break;case 3:fd = open("/dev/myled2", O_RDWR);if (fd < 0){printf("设备文件打开失败\n");exit(-1);}printf("打开文件myled2成功\n");break;default:printf("请输入范围内的数\n");}int b;printf("请开灯关灯(0/1)\n");scanf(" %d",&b);switch(b){case 1:ioctl(fd,LED_ON);break;case 0:ioctl(fd,LED_OFF);break;default:printf("请输入'0'或'1'\n");}close(fd);printf("关闭文件\n");		}return 0;
}

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//构建LED开关功能码
#define LED_ON _IO('l',1)
#define LED_OFF _IO('l',0)
#endif 

测试现象:

相关文章:

linux驱动开发--day4(字符设备驱动注册内部流程、及实现备文件和设备的绑定下LED灯实验)

一、字符设备驱动注册的内部过程 1.分配struct cdev对象空间 2.初始化struct cdev对象 3.注册cdev对象 二、注册字符设备驱动分步实现 1.分配字符设备驱动对象 2.字符设备驱动对象初始化 3.设备号的申请 4.根据申请的设备号和驱动对象注册驱动 三、open函数回调驱动中…...

elasticsearch5-RestAPI操作

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…...

数据结构与算法(一)

文章目录 数据结构与算法(一)1 位运算、算法是什么、简单排序1.1 实现打印一个整数的二进制1.2 给定一个参数N,返回1!+2!+3!+4!+...+N!的结果1.3 简单排序算法2 数据结构大分类、前缀和、对数器2.1 实现前缀和数组2.2 如何用1\~5的随机函数加工出1\~7的随机函数2.3 如何把不…...

Matlab--微积分问题的计算机求解

目录 1.单变量函数的极限问题 1.1.公式例子 1.2.对应例题 1 2.多变量函数的极限问题 3.函数导数的解析解 4.多元函数的偏导数 5.Jacobian函数 6.Hessian矩阵 7.隐函数的偏导 8.不定积分问题的求解 9.定积分的求解问题 10. 多重积分的问题求解 1.单变量函数的极限问题 …...

GRU实现时间序列预测(PyTorch版)

&#x1f4a5;项目专栏&#xff1a;【深度学习时间序列预测案例】零基础入门经典深度学习时间序列预测项目实战&#xff08;附代码数据集原理介绍&#xff09; 文章目录 前言一、基于PyTorch搭建GRU模型实现风速时间序列预测二、时序数据集的制作三、数据归一化四、数据集加载器…...

文本框粘贴时兼容Unix、Mac换行符的方法源码

本篇文章属于《518抽奖软件开发日志》系列文章的一部分。 我在开发《518抽奖软件》&#xff08;www.518cj.net&#xff09;的时候&#xff0c;要在文本框粘贴从别处复制来的名单。发现一个问题&#xff0c;就是一些Unix传过来的多行文本&#xff0c;粘贴后都变成了一行。原来&a…...

2023年华为杯研究生数学建模竞赛辅导

2023年华为杯研究生数学建模竞赛辅导 各研究生培养单位&#xff1a; 中国研究生数学建模竞赛作为教育部学位管理与研究生教育司指导&#xff0c;中国学位与研究生教育学会、中国科协青少年科技中心主办的“中国研究生创新实践系列大赛”主题赛事之一&#xff0c;是一项面向在校…...

post更新,put相当于删除重新增一条

索引数据 //删除后新增 PUT my_dynamic_temp/_doc/1 { “name”:“test”, “class”:“1204” } //覆盖更新 POST my_dynamic_temp/_update/1 { “doc”: { “name”:“test”, “class”:“1203”, “pernum”:“998” } }...

python责任链模式

责任链模式是一种行为设计模式&#xff0c;它允许你将请求沿着处理者链进行传递&#xff0c;直到有一个处理者能够处理它为止。在Python中&#xff0c;你可以使用多线程来实现责任链模式的框架。 首先&#xff0c;你需要定义一个基础的处理者类&#xff0c;它包含处理请求的方…...

大数据技术准备

Hbase&#xff1a;HBase 底层原理详解&#xff08;深度好文&#xff0c;建议收藏&#xff09; - 腾讯云开发者社区-腾讯云 Hbase架构图 同一个列族如果有多个store&#xff0c;那么这些store在不同的region Hbase写流程&#xff08;读比写慢&#xff09; MemStore Flush Hbas…...

【力扣周赛】第 362 场周赛(⭐差分匹配状态压缩DP矩阵快速幂优化DPKMP)

文章目录 竞赛链接Q1&#xff1a;2848. 与车相交的点解法1——排序后枚举解法2——差分数组⭐差分数组相关题目列表&#x1f4d5;1094. 拼车1109. 航班预订统计2381. 字母移位 II2406. 将区间分为最少组数解法1——排序贪心优先队列解法2——差分数组 2772. 使数组中的所有元素…...

四大函数式接口(重点,必须掌握)

新时代程序员必须要会的 &#xff1a;lambda表达式、链式编程、函数式接口、Stream流式计算 什么是函数式接口 1.函数型接口 package com.kuang.function;import java.util.function.Function;/*** Function函数型接口 有一个输入参数&#xff0c;有一个输出* 只要是函数式接口…...

2023Web前端逻辑面试题

1、现有9个小球&#xff0c;已知其中一个球比其它的重&#xff0c;如何只用天平称2次就找出该球&#xff1f; ①把9个球分成三份&#xff0c;三个一份&#xff1b; ②拿出其中两份进行称量&#xff1b;会分为两种情况 若拿出的两份小球称量结果&#xff0c;重量相等&#xff1b…...

uniapp中git忽略node_modules,unpackage文件

首先在当前项目的命令行新建.gitignore文件&#xff1a; touch .gitignore再在编辑器中打开该文件&#xff0c;并在该文件中加入需要忽略的文件名&#xff1a; node_modules/ .project unpackage/ .DS_Store 提示&#xff1a;如果以前提交过unpackage文件的话&#xff0c;需…...

Json-Jackson和FastJson

狂神&#xff1a; 测试Jackson 纯Java解决日期格式化 设置ObjectMapper FastJson&#xff1a; 知乎&#xff1a;Jackson使用指南 1、常见配置 方式一&#xff1a;yml配置 spring.jackson.date-format指定日期格式&#xff0c;比如yyyy-MM-dd HH:mm:ss&#xff0c;或者具体的…...

RK3588 点亮imx586摄像头

一.硬件原理图 mipi摄像头硬件确认点&#xff1a; 1.供电&#xff1a;5V&#xff0c;2.8V&#xff0c;1.2V&#xff0c;1.8V&#xff0c;reset脚&#xff08;硬拉3.3&#xff0c;上电的时候从低到高&#xff09;&#xff0c;pwron脚外接 3.3V。 2,时钟&#xff1a;MCLKOUT是2…...

C++---继承

继承 前言继承的概念及定义继承的概念继承定义继承关系和访问限定符 基类和派生类对象赋值转换继承中的作用域派生类的默认成员函数继承与友元继承与静态成员**多重继承**多继承下的类作用域菱形继承虚继承使用虚基类 支持向基类的常规类型转换 前言 在需要写Father类和Mother…...

使用新版Maven-mvnd快速构建项目

目前我们项目的构建方式多数是 maven、gradle&#xff0c;但是 maven 相对 gradle 来说&#xff0c;构建速度较慢&#xff0c;特别是模块相对较多的时候&#xff0c;构建速度更加明显。但是我们将项目由 maven 替换为 gradle 相对来说会比较麻烦&#xff0c;成本较高。于是我们…...

【ICASSP 2023】ST-MVDNET++论文阅读分析与总结

主要是数据增强的提点方式。并不能带来idea启发&#xff0c;但对模型性能有帮助 Challenge&#xff1a; 少有作品应用一些全局数据增强&#xff0c;利用ST-MVDNet自训练的师生框架&#xff0c;集成了更常见的数据增强&#xff0c;如全局旋转、平移、缩放和翻转。 Contributi…...

MySQL 面试题——MySQL 基础

目录 1.什么是 MySQL&#xff1f;有什么优点&#xff1f;2.MySQL 中的 DDL 与 DML 是分别指什么&#xff1f;3.✨数据类型 varchar 与 char 有什么区别&#xff1f;4.数据类型 BLOB 与 TEXT 有什么区别&#xff1f;5.DATETIME 和 TIMESTAMP 的异同&#xff1f;6.✨MySQL 中 IN …...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

Tauri2学习笔记

教程地址&#xff1a;https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引&#xff1a;https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多&#xff0c;我按照Tauri1的教程来学习&…...

无需布线的革命:电力载波技术赋能楼宇自控系统-亚川科技

无需布线的革命&#xff1a;电力载波技术赋能楼宇自控系统 在楼宇自动化领域&#xff0c;传统控制系统依赖复杂的专用通信线路&#xff0c;不仅施工成本高昂&#xff0c;后期维护和扩展也极为不便。电力载波技术&#xff08;PLC&#xff09;的突破性应用&#xff0c;彻底改变了…...