Linux驱动开发之点亮三盏小灯

头文件
#ifndef __HEAD_H__
#define __HEAD_H__//LED1和LED3的硬件地址
#define PHY_LED1_MODER 0x50006000
#define PHY_LED1_ODR 0x50006014
#define PHY_LED1_RCC 0x50000A28
//LED2的硬件地址
#define PHY_LED2_MODER 0x50007000
#define PHY_LED2_ODR 0x50007014
#define PHY_LED2_RCC 0x50000A28#endif
驱动代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"
int major;
char kbuf[128]={0};
//定义指针接收映射成功的虚拟内存首地址
unsigned int *vir_moder1;
unsigned int *vir_odr1;
unsigned int *vir_rcc1;unsigned int *vir_moder2;
unsigned int *vir_odr2;
unsigned int *vir_rcc2;//定义一个指针用来接收创建类
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;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);int ret;ret=copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user filad\n");return ret;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{int ret;ret=copy_from_user(kbuf,ubuf,size);if(ret){printk("copy_from_user filed\n");return ret;}if(kbuf[0]=='1' && kbuf[1] == '1')//LED1开灯{//开灯逻辑(*vir_odr1) |= (0X1<<10);}else if(kbuf[0]=='1' && kbuf[1] == '0')//LED1关灯{//关灯逻辑(*vir_odr1) &= (~(0X1<<10));}else if(kbuf[0]=='2' && kbuf[1] == '1')//LED2开灯{//开灯逻辑(*vir_odr2) |= (0X1<<10);}else if(kbuf[0]=='2' && kbuf[1] == '0')//LED1关灯{//关灯逻辑(*vir_odr2) &= (~(0X1<<10));}else if(kbuf[0]=='3' && kbuf[1] == '1')//LED#开灯{//开灯逻辑(*vir_odr1) |= (0X1<<8);}else if(kbuf[0]=='3' && kbuf[1] == '0')//LED3关灯{//关灯逻辑(*vir_odr1) &= (~(0X1<<8));}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,.read=mycdev_read,.write=mycdev_write,.release=mycdev_close,
};static int __init mycdev_init(void)
{int i;// 注册字符设备驱动major = register_chrdev(0, "mychrdev", &fops);if(major<0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功major=%d\n",major);//向上提交目录信息cls = class_create(THIS_MODULE,"mycdev");if(IS_ERR(cls)){printk("向上提交目录信息失败\n");return -PTR_ERR(cls);}printk("向上提交目录信息成功\n");//向上提交设备信息for(i=0;i<3;i++){dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);if(IS_ERR(cls)){printk("向上提交设备信息信息失败\n");return -PTR_ERR(cls);}}printk("向上提交设备信息成功\n");//完成硬件寄存器物理内存的映射vir_moder1=ioremap(PHY_LED1_MODER,4);if(vir_moder1==NULL){printk("LED1物理内存映射失败%d\n",__LINE__);return -EFAULT;}vir_odr1=ioremap(PHY_LED1_ODR,4);if(vir_odr1==NULL){printk("LED1物理内存映射失败%d\n",__LINE__);return -EFAULT;}vir_rcc1=ioremap(PHY_LED1_RCC,4);if(vir_rcc1==NULL){printk("LED1物理内存映射失败%d\n",__LINE__);return -EFAULT;}printk("LED1物理内存映射成功\n");//LED2物理内存映射vir_moder2=ioremap(PHY_LED2_MODER,4);if(vir_moder2==NULL){printk("LED2物理内存映射失败%d\n",__LINE__);return -EFAULT;}vir_odr2=ioremap(PHY_LED2_ODR,4);if(vir_odr2==NULL){printk("LED2物理内存映射失败%d\n",__LINE__);return -EFAULT;}vir_rcc2=ioremap(PHY_LED2_RCC,4);if(vir_rcc2==NULL){printk("LED2物理内存映射失败%d\n",__LINE__);return -EFAULT;}printk("LED2物理内存映射成功\n");//LED3物理内存映射vir_moder1=ioremap(PHY_LED1_MODER,4);if(vir_moder1==NULL){printk("LED3物理内存映射失败%d\n",__LINE__);return -EFAULT;}vir_odr1=ioremap(PHY_LED1_ODR,4);if(vir_odr1==NULL){printk("LED3物理内存映射失败%d\n",__LINE__);return -EFAULT;}vir_rcc1=ioremap(PHY_LED1_RCC,4);if(vir_rcc1==NULL){printk("LED3物理内存映射失败%d\n",__LINE__);return -EFAULT;}printk("LED3物理内存映射成功\n");//硬件寄存器的初始化//LED1硬件初始化(*vir_moder1) &= (~(0X3<<20));//设置为输出(*vir_moder1) |= (0X1<<20);//LED2硬件初始化(*vir_moder2) &= (~(0X3<<20));//设置为输出(*vir_moder2) |= (0X1<<20);//LED3硬件初始化(*vir_moder1) &= (~(0X3<<16));//设置为输出(*vir_moder1) |= (0X1<<16);//rcc使能(*vir_rcc1) |= (0X1<<4);(*vir_rcc2) |= (0X1<<5);//默认关灯(*vir_odr1) &= (~(0X1<<10));(*vir_odr2) &= (~(0X1<<10));(*vir_odr1) &= (~(0X1<<8));return 0;
}
static void __exit mycdev_exit(void)
{//取消物理内存的映射iounmap(vir_moder1);iounmap(vir_odr1);iounmap(vir_rcc1);iounmap(vir_moder2);iounmap(vir_odr2);iounmap(vir_rcc2);//销毁设备信息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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char *argv[])
{char buf[128] = {};int fd0 = open("/dev/mycdev0", O_RDWR);int fd1 = open("/dev/mycdev1", O_RDWR);int fd2 = open("/dev/mycdev2", O_RDWR);if (fd0 < 0){printf("打开设备文件失败\n");exit(-1);}printf("成功打开设备文件\n");while (1){printf("逻辑关系:例如11表示LED1亮 10表示LED1灭...\n");fgets(buf, sizeof(buf), stdin); // 从终端读一个字符串存放在bufbuf[strlen(buf) - 1] = '\0';if(buf[0] == '1'){write(fd0, buf, sizeof(buf)); // 将从终端得到的字符串传递到驱动}else if(buf[0] == '2'){write(fd1, buf, sizeof(buf));}else if(buf[0] == '3'){write(fd2, buf, sizeof(buf));}}close(fd0);return 0;
}
结果


实现效果如上
相关文章:
Linux驱动开发之点亮三盏小灯
头文件 #ifndef __HEAD_H__ #define __HEAD_H__//LED1和LED3的硬件地址 #define PHY_LED1_MODER 0x50006000 #define PHY_LED1_ODR 0x50006014 #define PHY_LED1_RCC 0x50000A28 //LED2的硬件地址 #define PHY_LED2_MODER 0x50007000 #define PHY_LED2_ODR 0x50007014 #define…...
【SA8295P 源码分析】71 - QAM8295P 原理图参考设计 之 MIPI DSI 接口硬件原理分析
【SA8295P 源码分析】71 - QAM8295P 原理图参考设计 之 MIPI DSI 接口硬件原理分析 一、MIPI-DSI 接口介绍二、高通参考硬件原理图分析:ANX7625 桥接芯片方案2.1 高通参考设计:两路 4-Lane DSI 接口2.2 高通参考设计:DSI0 硬件原理图,将 4 Lane DSI数据通过 ANX7625 桥接芯…...
macOS(m1/m2)破解Sublime Text和Navicat16
破解Sublime Text 说明:全程使用的是终端操作 1. 下载Sublime Text,建议使用brew下载 2. 进入到下载的app的文件夹 cd "/Applications/Sublime Text.app/Contents/MacOS/"3. 执行以下操作以确认版本是否匹配 md5 -q sublime_text | grep -i…...
【排排站:探索数据结构中的队列奇象】
本章重点 队列的概念及结构 队列的实现方式 链表方式实现栈接口 队列面试题 一、队列的概念及结构 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列&#x…...
Mac OS 中JDK 环境(jdk 1.8.0_831)安装配置、环境变量配置及卸载操作
前言: 摊牌了,本来就有点喜新厌旧的我,特意把系统和开发环境都拉到比较高,想试验一下兼容性和某些新特性,探索了一下新大陆,也见识了各种光怪陆离的妖魔鬼怪。 因为要着手云平台项目的重构改版和新系统的架…...
[JAVAee]Tomcat - Servlet
目录 Tomcat Servlet的工作 创建Servlet ①项目 ②依赖 ③目录 ④代码 ⑤打包 ⑥部署 ⑦验证 Servlet的运行原理 Servlet API HttpServlet 方法 处理Get/POST请求 HttpServletRequest 方法 获取请求中的信息 获取GET请求中的参数 获取POST请求中的参数…...
MAC钓鱼并Root权限上线CS并权限维持,以及所有的坑如何解决
本文转载于:https://www.freebuf.com/articles/web/350592.html 作者:文鸯涂鸦智能安全实验室 制作MAC 一、下载工具 首先从github上下载CrossC2。链接:https://github.com/gloxec/CrossC2/releases/tag/v3.1.0。 根据你CS客户端的操作系统选…...
浅谈OCR中的David Shepard
在OCR(Optical Character Recognition,光学字符识别)中,David Shepard是一种早期的OCR技术,也被称为Shepards Method。 David Shepard是该OCR方法的原始作者。这种方法基于边界追踪算法,用于识别印刷体文本…...
draw.io导出矢量图到word报错text is not svg - cannot display
先参考https://blog.csdn.net/a625750076/article/details/126384831 如果不行,可能是转存的问题 解决方法:直接在draw.io上操作 第一步 第二步 然后再word中粘贴,依旧是矢量图哦!...
JVM加强
目录 JVM运行时的数据区(内存结构): 线程独享: 线程共享: 什么时候会内存溢出 JVM有哪些垃圾回收算法 GC如何判断对象可以被回收 典型的垃圾回收器 CMS: G1: 类加载器和双亲委派机制&a…...
解决Oracle中XML插入数据时的空格问题
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
微服务中间件--分布式事务
分布式事务 a.理论基础1) CAP定理2) BASE理论 b.Seata1) XA模式1.a) 实现XA模式 2) AT模式3) TCC模式3.a) 代码实现 4) Saga模式5) 四种模式对比6) TC的异地多机房容灾架构 a.理论基础 1) CAP定理 分布式系统有三个指标: Consistency(一致性ÿ…...
计算机网络(9) --- 数据链路层与MAC帧
计算机网络(8) --- IP与IP协议_哈里沃克的博客-CSDN博客IP与IP协议https://blog.csdn.net/m0_63488627/article/details/132155460?spm1001.2014.3001.5502 目录 1.MAC帧 1.MAC地址 2.MAC帧报头 3.资源碰撞 4.MTU 1.对IP协议的影响 2.对UDP协议…...
【学会动态规划】环绕字符串中唯一的子字符串(25)
目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 动态规划怎么学? 学习一个算法没有捷径,更何况是学习动态规划, 跟我…...
CNN卷积详解(三)
一、卷积层的计算 4 ∗ * ∗ 4的输入矩阵 I I I 和 3 ∗ * ∗ 3 的卷积核 K K K: 在步长(stride)为 1 时,输出的大小为 ( 4 − 3 1 ) ( 4 − 3 1) 计算公式: ● 输入图片矩阵 I I I 大小: w w w w ww ●…...
使用 Amazon Redshift Serverless 和 Toucan 构建数据故事应用程序
这是由 Toucan 的解决方案工程师 Django Bouchez与亚马逊云科技共同撰写的特约文章。 带有控制面板、报告和分析的商业智能(BI,Business Intelligence)仍是最受欢迎的数据和分析使用场景之一。它为业务分析师和经理提供企业的过去状态和当前状…...
CentOS 上快速安装包管理工具Conda
要在 CentOS 上安装 Conda,您可以按照以下步骤进行操作: 1. 下载 Miniconda 或 Anaconda 安装脚本: Miniconda:适用于轻量级安装的 Miniconda 版本。 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.…...
opencv-手势识别
# HandTrackingModule.py import cv2 import mediapipe as mpclass HandDetector:"""使用mediapipe库查找手。导出地标像素格式。添加了额外的功能。如查找方式,许多手指向上或两个手指之间的距离。而且提供找到的手的边界框信息。"""…...
【SA8295P 源码分析】10 - HQX Display(OpenWFD)qcdisplaycfg_ADP_STAR_LA.xml 配置文件解析
【SA8295P 源码分析】10 - HQX Display(OpenWFD)qcdisplaycfg_ADP_STAR_LA.xml 配置文件解析 一、HQX Display 介绍1.1 OpenWF Display Driver二、HQX Display 配置文件参数解析2.1 qcdisplaycfg.xml 配置文件2.1 配置两个 DPUs in QNX2.1.1 配置 graphics_ADP_STAR.conf : …...
达梦数据库权限和预定角色介绍
概述 本文对达梦数据库数据库和对象权限及DM预定义角色及角色创建进行介绍。 1.权限管理 用户权限有两类:数据库权限和对象权限。 数据库权限主要是指针对数据库对象的创建、删除、修改的权限,对数据库备份等权限。 数据库权限一般由 SYSDBA、SYSAU…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
