当前位置: 首页 > 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 …...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...