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

驱动开发day4(实现通过字符设备驱动的分布实现编写LED驱动,实现设备文件的绑定)

头文件(head.h)

#ifndef __HEAD_H__
#define __HEAD_H__
#define PHY_LED1_MODER 0x50006000
#define PHY_LED2_MODER 0x50007000
#define PHY_LED3_MODER 0x50006000
#define PHY_LED1_ODR 0x50006014
#define PHY_LED2_ODR 0x50007014
#define PHY_LED3_ODR 0x50006014
#define PHY_RCC 0x50000A28
//构建开灯关灯的功能码
#define LED_ON _IO('l',1)
#define LED_OFF _IO('l',0)
#endif

c文件:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "head.h"
int main(int argc, char const *argv[])
{char buf[128] = "";int a;int fd = open("/dev/mycdev1", O_RDWR);if (fd < 0){printf("打开设备文件失败\n");return -1;}printf("打开设备文件成功\n");while (1){printf("请输入要进行的操作,0(关灯),1(开灯) >");scanf("%d", &a);switch (a){case 1:ioctl(fd, LED_ON);break;case 0:ioctl(fd, LED_OFF);break;}}close(fd);return 0;
}
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include "head.h"
struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
// 定义RCC控制器指针指向映射后的虚拟内存
unsigned int *vir_rcc;
// LED1定义两个指针指向映射后的虚拟内存
unsigned int *vir_moder_led1;
unsigned int *vir_odr_led1;
// LED2定义两个指针指向映射后的虚拟内存
unsigned int *vir_moder_led2;
unsigned int *vir_odr_led2;
// LED3定义两个指针指向映射后的虚拟内存
unsigned int *vir_moder_led3;
unsigned int *vir_odr_led3;
struct class *cls;
struct device *dev;
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 mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{// 获取文件的次设备号int min = (int)file->private_data;switch (min){case 0://操作LED1switch(cmd){case LED_ON:(*vir_odr_led1) |= (0x1 << 10); // LED1开灯break;case LED_OFF:(*vir_odr_led1) &= (~(0x1 << 10)); // LED1关灯break;}break;case 1://操作LED2switch(cmd){case LED_ON:(*vir_odr_led2) |= (0x1 << 10); // LED2开灯break;case LED_OFF:(*vir_odr_led2) &= (~(0x1 << 10)); // LED2关灯break;}break;case 2://操作LED3switch(cmd){case LED_ON:(*vir_odr_led3) |= (0x1 << 10); // LED3开灯break;case LED_OFF:(*vir_odr_led3) &= (~(0x1 << 10)); // LED3关灯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,};
static int __init mycdev_init(void)
{int ret;// 1.申请一个对象空间 cdev_alloccdev = cdev_alloc();if (cdev == NULL){printk("申请字符设备驱动对象失败");ret = -EFAULT;goto cont1;}printk("字符设备驱动对象申请成功\n");// 2.初始化对象 cdev_initcdev_init(cdev, &fops);// 3.申请设备号 register_chrdev_region()/alloc_chrdev_region()if (major == 0) // 动态申请模拟{ret = alloc_chrdev_region(&devno, minor, 3, "mychrdev");if (ret){printk("动态申请设备号失败\n");goto cont2;}major = MAJOR(devno); // 根据设备号获取主设备号minor = MINOR(devno); // 根据设备号获取次设备号}else // 静态申请模拟{ret = register_chrdev_region(MKDEV(major, minor), 3, "mychrdev");if (ret){printk("静态指定设备号失败\n");goto cont2;}}printk("设备号申请成功\n");// 4.注册驱动对象 cdev_addret = cdev_add(cdev, MKDEV(major, minor), 3);if (ret){printk("注册驱动对象失败\n");goto cont3;}printk("注册字符设备驱动对象成功\n");// 5.向上提交目录 class_createcls = class_create(THIS_MODULE, "mychrdev");if (IS_ERR(cls)){printk("向上提交目录失败\n");goto cont4;}printk("向上提交目录成功\n");// 6.向上提交设备节点信息 device_createint 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");goto cont5;}}printk("向上提交设备节点信息成功\n");// RCC控制器地址映射vir_rcc = ioremap(PHY_RCC, 4);if (vir_rcc == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}// LED1进行寄存器的地址映射vir_moder_led1 = ioremap(PHY_LED1_MODER, 4);if (vir_moder_led1 == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}vir_odr_led1 = ioremap(PHY_LED1_ODR, 4);if (vir_odr_led1 == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}printk("LED1寄存器内存映射成功\n");// LED2进行寄存器的地址映射vir_moder_led2 = ioremap(PHY_LED2_MODER, 4);if (vir_moder_led2 == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}vir_odr_led2 = ioremap(PHY_LED2_ODR, 4);if (vir_odr_led2 == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}printk("LED2寄存器内存映射成功\n");// LED3进行寄存器的地址映射vir_moder_led3 = vir_moder_led1;if (vir_moder_led3 == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}vir_odr_led3 = vir_odr_led1;if (vir_odr_led3 == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -1;}printk("LED3寄存器内存映射成功\n");// RCC寄存器初始化(*vir_rcc) |= (0x3 << 4); // GPIOE/GPIOF控制器时钟使能// LED1寄存器初始化(*vir_moder_led1) &= (~(0x3 << 20)); // MODER[21:20]->00(*vir_moder_led1) |= (0x1 << 20);    // MODER[21:20]->01(*vir_odr_led1) &= (~(0x1 << 10));   // 默认关灯// LED2寄存器初始化(*vir_moder_led2) &= (~(0x3 << 20)); // MODER[21:20]->00(*vir_moder_led2) |= (0x1 << 20);    // MODER[21:20]->01(*vir_odr_led2) &= (~(0x1 << 10));   // 默认关灯// LED3寄存器初始化(*vir_moder_led3) &= (~(0x3 << 16)); // MODER[17:16]->00(*vir_moder_led3) |= (0x1 << 16);    // MODER[17:16]->01(*vir_odr_led3) &= (~(0x1 << 8));    // 默认关灯return 0;
cont5:// 将提交成功的节点信息释放for (--i; i > 0; i--){device_destroy(cls, MKDEV(major, i));}// 销毁目录class_destroy(cls);
cont4:cdev_del(cdev);
cont3:unregister_chrdev_region(MKDEV(major, minor), 3);
cont2:kfree(cdev);
cont1:return ret;
}
static void __exit mycdev_exit(void)
{// 取消RCC控制器内存映射iounmap(vir_rcc);// 取消LED1内存映射iounmap(vir_moder_led1);iounmap(vir_odr_led1);// 取消LED2内存映射iounmap(vir_moder_led2);iounmap(vir_odr_led2);// 1.销毁设备节点信息int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 2.销毁目录class_destroy(cls);// 3.注销字符设备驱动对象cdev_del(cdev);// 4.释放设备号unregister_chrdev_region(MKDEV(major, minor), 3);// 5.释放申请到的字符设备驱动对象空间kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

相关文章:

驱动开发day4(实现通过字符设备驱动的分布实现编写LED驱动,实现设备文件的绑定)

头文件&#xff08;head.h&#xff09; #ifndef __HEAD_H__ #define __HEAD_H__ #define PHY_LED1_MODER 0x50006000 #define PHY_LED2_MODER 0x50007000 #define PHY_LED3_MODER 0x50006000 #define PHY_LED1_ODR 0x50006014 #define PHY_LED2_ODR 0x50007014 #define PHY_LE…...

《深入浅出.NET框架设计与实现》阅读笔记(一)

.NET CLI概述 命令说明dotnet add将包或引用添加到.NET项目中dotnet build构建.NET项目&#xff0c;并编译为IL二进制文件dotnet clean清理.NET项目的构建输出dotnet help显示命令行帮助dotnet list罗列项目中的yinyongdotnet publish发布项目&#xff0c;用于部署dotnet sln修…...

Flutter 类似onResume 监听,解决入场动画卡顿(2)

接着完善上一篇内容&#xff0c;上一篇我们是能监听到初次进入路由页面节点&#xff0c;往往还想监听从当前路由跳转到其他路由后&#xff0c;再返回到当前路由页面&#xff0c;上一篇内容就无法满足当前需求了&#xff0c;不过我们完全可以按照上一篇的原理实现这个需求。 直…...

rabbitmq-3.8.15集群、集群镜像模式安装部署

目录 一、环境 1、映射、域名、三墙 2、Erlang和socat安装&#xff08;三台服务器都实行&#xff09; 二、部署三台rabbitmq-3.8.15实例 1、rabbitmq官网下载地址 &#xff1a; 2、解压rabbitmq 3、添加系统变量 4、启动web插件、启动rabbitmq 5、在rabbitmq1上添加用…...

import导入顺序杂乱的问题

我们经常会遇到项目中的import语句顺序混乱的问题。这不仅会影响代码的可读性&#xff0c;还可能使我们代码在提交的时候产生不必要的冲突。 解决方案 eslint-plugin-import 开始我调研了一下eslint-plugin-import插件。这款插件的排序逻辑是这样&#xff1a; builtin: 这代…...

Hadoop3教程(二十六):(生产调优篇)NameNode核心参数配置与回收站的启用

文章目录 &#xff08;143&#xff09;NameNode内存配置&#xff08;144&#xff09;NN心跳并发配置&#xff08;145&#xff09;开启回收站参考文献 &#xff08;143&#xff09;NameNode内存配置 每个文件块&#xff08;的元数据等&#xff09;在内存中大概 占用150byte&…...

PaddleX场景实战:PP-TS在电压预测场景上的应用

时间序列是按照时间发生的先后顺序进行排列的数据点序列&#xff0c;简称时序。时间序列预测即运用历史的多维数据进行统计分析&#xff0c;推测出事物未来的发展趋势。时间序列预测是最常见的时序问题之一&#xff0c;在很多行业都有其应用&#xff0c;且通常时序预测效果对业…...

pdf误删恢复如何恢复?分享4种恢复方法!

如何将pdf误删恢复&#xff1f;使用电脑的时候&#xff0c;经常会需要使用到pdf文件&#xff0c;但是有时候&#xff0c;因为一些操作上的失误&#xff0c;我们会丢失一些重要的文件。如果你不小心将pdf误删了&#xff0c;该如何进行恢复呢&#xff1f; PDF文件丢失的原因可以…...

简析新能源汽车充电桩设计与应用

叶根胜 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;本文针对新能源汽车充电桩建设工作进行探究&#xff0c;采用案例分析法、文献查阅法&#xff0c;指出了新能源汽车充电桩建设存在的问题&#xff0c;阐述了充电桩建设与优化的对策。研究表明&#xff1a;目前…...

Java零基础入门-算术运算符

本文旨在帮助零基础的读者快速了解Java中的算术运算符&#xff0c;包括基本的加减乘除运算符、取余运算符、自增自减运算符等常见的数学运算符。 在学习本文前&#xff0c;需要先掌握基本的Java语法&#xff0c;包括数据类型、变量、赋值语句等。 前言 在编写Java程序时&…...

java实现hbase数据导出

1. HBase-client方式实现 1.1 依赖 <!--HBase依赖坐标--><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.2.6</version></dependency><dependency><group…...

Unity之ShaderGraph如何实现旋涡效果

前言 今天我们来通过ShaderGraph来实现一个旋涡的效果 如下图所示&#xff1a; 主要节点 Distance&#xff1a;返回输入 A 和输入 B 的值之间的欧几里德距离。除了其他方面的用途&#xff0c;这对于计算空间中两点之间的距离很有用&#xff0c;通常用于计算有符号距离函数 (…...

【分布式】: 幂等性和实现方式

【分布式】: 幂等性和实现方式 幂等&#xff08;idempotent、idempotence&#xff09;是一个数学与计算机学概念&#xff0c; 常见于抽象代数中。在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数&#xff0c;或幂等方法&#xff0c;是…...

idea 设置serlvet 类模板(快捷生成servlet类)

我的版本是idea2020.3.4&#xff0c;博客中有相应安装教程&#xff0c;其他版本设置类似&#xff1a; 1.选择文件-->设置 2.选择编辑器-->文件和代码模板-->其他 3.选择Web-->Servlet Annotated Class.java-->复制相应模板&#xff0c;下面顺便设置了注释模板 …...

SpringBoot自动配置原理解析 | 京东物流技术团队

1: 什么是SpringBoot自动配置 首先介绍一下什么是SpringBoot&#xff0c;SpringBoost是基于Spring框架开发出来的功能更强大的Java程序开发框架&#xff0c;其最主要的特点是&#xff1a;能使程序开发者快速搭建一套开发环境。SpringBoot能将主流的开发框架&#xff08;例如Sp…...

AOP 笔记

AOP【面向切面编程】 作用&#xff1a;在不惊动原始设计的基础上进行功能增强。 无侵入式编程 连接点&#xff1a;程序执行的任意位置&#xff0c;SpringAOP中&#xff0c;理解为方法的执行。 切入点&#xff1a;匹配连接点的式子,要追加功能的方法 通知&#xff08;写在通…...

微信小程序导航退回及跳转 传参(navigateBack,navigateTo)

一、uniapp navigateBack 退回上一级 当前页面-传递参数 uni.$emit(update, params)uni.navigateBack({delta: 1});退回的页面-接收参数 可以写在 onLoad 和 onShow 里面 onLoad(o) {uni.$on(update, function(e) {//参数e}}onShow() {}返回前两级 uni.navigateBack({delta: 2}…...

python实例代码介绍python基础知识

TODO: 知识点仍有待整理 import 使用 import 关键字可以让你选择性地导入所需的模块&#xff0c;而不必导入整个模块库。这样可以减少内存占用和加载时间&#xff0c;尤其是当你只需要使用模块中的某些功能时。 同时&#xff0c;使用 import 可以提高代码的可读性和可维护性&…...

【每日一题】掷骰子等于目标和的方法数

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;动态规划 写在最后 Tag 【动态规划】【数组】 题目来源 1155. 掷骰子等于目标和的方法数 题目解读 你手里有 n 个一样的骰子&#xff0c;每个骰子都有 k 个面&#xff0c;分别标号 1 到 n。给定三个整数 n&#xff0…...

霸王条款惹品牌争议,京东双11站在商家对立面?

作者 | 江北 来源 | 洞见新研社 双11活动第一天&#xff0c;京东就站上了风口浪尖。 与烘焙烤箱品牌海氏的话题接连登上微博热搜&#xff0c;海氏控诉京东滥用市场竞争地位&#xff0c;破坏市场竞争秩序。在海氏的声明中&#xff0c;京东的行为让吃瓜群众大开眼界&#xff1a…...

用Python和PyTorch手把手搭建你的第一个脉冲神经网络(SNN)模型

用Python和PyTorch手把手搭建你的第一个脉冲神经网络&#xff08;SNN&#xff09;模型 当你第一次听说"脉冲神经网络"时&#xff0c;脑海中可能会浮现出科幻电影里那些会思考的机器。但事实上&#xff0c;这种模拟生物神经元工作方式的算法已经悄然走进现实。作为一名…...

Qwen3.5-9B多模态应用:上传招聘JD截图生成面试问题+考察点分析

Qwen3.5-9B多模态应用&#xff1a;上传招聘JD截图生成面试问题考察点分析 1. 项目概述 Qwen3.5-9B是一款拥有90亿参数的开源大语言模型&#xff0c;具备强大的多模态理解能力。该模型特别适合处理需要结合文本和图像信息的任务&#xff0c;比如从招聘JD截图中提取关键信息并生…...

文字的编码方式————不同UTF之间的区别

目录 1. 编码与字体 A. ASCII&#xff08;American Standard Code for Information Interchange&#xff09; B. ANSI C. UNICODE 2 . UNICODE 编码实现 &#xff08;1&#xff09;UTF-16 a. UTF-16 LE b. UTF-16 BE &#xff08;2&#xff09;UTF-8 &#xff08;3&#xff…...

OpenClaw+千问3.5-9B智能翻译:多语言文档自动处理

OpenClaw千问3.5-9B智能翻译&#xff1a;多语言文档自动处理 1. 为什么需要本地化智能翻译 去年参与一个跨国开源项目时&#xff0c;我每天要处理英日韩三种语言的开发文档。传统翻译工具需要手动复制粘贴&#xff0c;遇到代码片段还会破坏格式。更麻烦的是技术术语的准确性—…...

实战应用:基于快马平台开发类似ahflt.sys的文件操作监控工具

实战应用&#xff1a;基于快马平台开发类似ahflt.sys的文件操作监控工具 最近在研究Windows内核驱动开发时&#xff0c;发现ahflt.sys这类文件系统过滤驱动特别有意思。它能够在系统底层监控文件操作&#xff0c;实现各种高级功能。作为一个开发者&#xff0c;我决定在InsCode…...

ChilloutMix NiPrunedFp32Fix模型部署全攻略:从原理到实战

ChilloutMix NiPrunedFp32Fix模型部署全攻略&#xff1a;从原理到实战 【免费下载链接】chilloutmix_NiPrunedFp32Fix 项目地址: https://ai.gitcode.com/hf_mirrors/emilianJR/chilloutmix_NiPrunedFp32Fix 一、技术原理&#xff1a;模型架构与工作流程 1.1 核心组件…...

Scroll Reverser终极指南:让Mac滚动方向完全掌控

Scroll Reverser终极指南&#xff1a;让Mac滚动方向完全掌控 【免费下载链接】Scroll-Reverser Per-device scrolling prefs on macOS. 项目地址: https://gitcode.com/gh_mirrors/sc/Scroll-Reverser Scroll Reverser是一款专为macOS设计的开源工具&#xff0c;能够独立…...

SILERGY矽力杰 SY81103ABT NA DC-DC电源芯片

特性 内部MOSFET低导通电阻:顶部80m2&#xff0c;底部40mO 宽输入电压范围:4.5V~18V 最高输出电流3A 1.5%0.6V参考电压 精确的EN阈值 SY81103和SY81103C采用脉冲频率调制(PFM)模式运行 SY81103E和SY81103B的强制连续导通模式(FCCM)操作 内部软启动限制浪涌电流 支持预偏置输出的…...

让AI当你的面试官:基于快马平台打造智能前端面试辅导助手

最近在准备前端面试时&#xff0c;我发现很多题目看似简单&#xff0c;但真要回答得全面深入并不容易。比如经典的"深拷贝"问题&#xff0c;不仅要写出代码&#xff0c;还得考虑循环引用、性能优化等细节。这时候如果能有个AI助手帮忙分析题目、提供思路&#xff0c;…...

科学护眼智能提醒:3个维度破解数字时代眼健康难题

科学护眼智能提醒&#xff1a;3个维度破解数字时代眼健康难题 【免费下载链接】ProjectEye &#x1f60e; 一个基于20-20-20规则的用眼休息提醒Windows软件 项目地址: https://gitcode.com/gh_mirrors/pr/ProjectEye 在数字时代&#xff0c;我们每天面对屏幕的时间急剧增…...