驱动开发platform传地址,led点灯

news/2024/5/10 1:41:02

除了platform传地址,其他的跟指定入口地址和指定出口地址没区别

platform和指定入口地址不能同时存在,一直报错模块初始化重定义,半个小时搞完程序没问题,这个重复定义因为代码太多没看懂错误,删了又加没试出来怎么改错。

1.myled.h

#ifndef __MYLED_H__
#define __MYLED_H__enum{LED1, //0LED2, //1LED3, //2
};
typedef struct {volatile unsigned int MODER;   // 0x00volatile unsigned int OTYPER;  // 0x04volatile unsigned int OSPEEDR; // 0x08volatile unsigned int PUPDR;   // 0x0Cvolatile unsigned int IDR;     // 0x10                                                                        volatile unsigned int ODR;     // 0x14volatile unsigned int BSRR;    // 0x18volatile unsigned int LCKR;    // 0x1C volatile unsigned int AFRL;    // 0x20 volatile unsigned int AFRH;    // 0x24volatile unsigned int BRR;     // 0x28volatile unsigned int res;volatile unsigned int SECCFGR; // 0x30
}gpio_t;#define LED_ON  _IOW('a',1,int) //封装灯亮命令码
#define LED_OFF _IOW('a',0,int) //封装灯灭命令码
#define GET_CMD_SIZE(cmd) (cmd >> 16 & 0x3fff)  //封装命令码大小#endif

2.pdrv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "myled.h"
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>struct cdev* cdev;
#if 1
unsigned int major = 0; 
#else
unsigned int major = 500;
#endif
unsigned int minor = 0;
unsigned int count = 3;
#define CNAME "myled"
struct class *cls;
struct device *device;unsigned int* rcc_virt = NULL;
gpio_t* gpioe_virt = NULL;
gpio_t* gpiof_virt = NULL;#define LED1_ON (gpioe_virt->ODR |= (0x1 << 10))
#define LED1_OFF (gpioe_virt->ODR &= (~(0x1 << 10)))#define LED2_ON (gpiof_virt->ODR |= (0x1 << 10))
#define LED2_OFF (gpiof_virt->ODR &= (~(0x1 << 10)))#define LED3_ON (gpioe_virt->ODR |= (0x1 << 8))
#define LED3_OFF (gpioe_virt->ODR &= (~(0x1 << 8)))
struct resource* res;#define  GPIOE   res[0].start
#define RCC_MP_AHB4ENSETR_PHY  res[1].startint myled_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);printk("美妙的时光总有尽头\n");return 0;
}long myled_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{int ret;int whitch;switch(cmd) //判断命令码{case LED_ON: //灯亮命令码ret = copy_from_user(&whitch,(void*)args,GET_CMD_SIZE(LED_ON));if(ret){printk("copy from user is error\n");return -EIO;}switch (whitch) //判断哪一盏灯点亮{case LED1:LED1_ON; //LED1点亮break;                        }break;case LED_OFF: //灯灭命令码ret = copy_from_user(&whitch,(void*)args,GET_CMD_SIZE(LED_OFF));if(ret){printk("copy from user is error\n");return -EIO;}switch (whitch) //判断哪一盏灯熄灭{case LED1:LED1_OFF; //LED1熄灭break;                        }        break;}return 0;
}
int myled_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);printk("还起床了\n");return 0;     
}//操作方法结构体
const struct file_operations fops = {.open = myled_open,.unlocked_ioctl = myled_ioctl,.release = myled_close,
};//当设备信息端和设备驱动端匹配成功时,执行probe函数
int pdrv_probe(struct platform_device *pdev)
{int ret;int i;dev_t devno;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);printk("name = %s id = %ld\n",pdev->id_entry->name,pdev->id_entry->driver_data);//获取设备信息端地址信息res = platform_get_resource(pdev,IORESOURCE_MEM,0);if(res == NULL){printk("platform get resource is error\n");return -EIO;}//打印获取到的地址信息 中断号printk("GPIOEaddress = %#x RCCaddress = %#x\n",res[0].start,res[1].start);//分配对象cdev = cdev_alloc(); if(cdev == NULL){printk("cdev alloc is error\n");ret = -ENOMEM;goto ERR1;        }//对象初始化cdev_init(cdev,&fops);if(major > 0){ //静态指定设备号ret = register_chrdev_region(MKDEV(major,minor),count,CNAME);if(ret){printk("register chrdev region is error\n");ret =  -EIO;goto ERR2;            }}else{ //动态指定设备号ret = alloc_chrdev_region(&devno,minor,count,CNAME);if(ret){printk("alloc chrdev region is error\n");ret =  -EIO;goto ERR2;            }major = MAJOR(devno);//通过设备号,获取到主设备号的值minor = MINOR(devno);//通过设备号,获取到次设备号的值}  //注册ret = cdev_add(cdev,MKDEV(major,minor),count); if(ret){printk("cdev add is error\n");ret =  -EIO;goto ERR3;            }//向上层提交目录信息cls = class_create(THIS_MODULE,CNAME);if(IS_ERR(cls)){ret = PTR_ERR(cls);goto ERR4;}for(i=0;i<count;i++){//向上层提交设备节点信息device = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);if(IS_ERR(device)){ret = PTR_ERR(device);goto ERR5;}  }//rcc物理地址映射rcc_virt = ioremap(RCC_MP_AHB4ENSETR_PHY,4);if(rcc_virt == NULL){printk("rcc ioremap is error\n");return -EIO;}//GPIOE组寄存器物理地址映射gpioe_virt = ioremap(GPIOE,sizeof(gpio_t));if(gpioe_virt == NULL){printk("gpioe ioremap is error\n");return -EIO;}//LED1灯初始化 PE10*rcc_virt |= (0x1 << 4); //使能GPIOE组控制器 gpioe_virt->MODER &= (~(0x3 << 20)); //设置PE10引脚为输出模式gpioe_virt->MODER |= (0x1 << 20);gpioe_virt->ODR &= (~(0x1 << 10)); //设置PE10引脚输出低电平return 0; ERR5://创建三个设备节点时,第一个设备节点和第二个设备节点创建成功,第三个设备节点创建失败//需要将第一个设备节点和第二个设备节点创建成功,需要进行释放for(--i;i>=0;i--){device_destroy(cls,MKDEV(major,i));}class_destroy(cls);
ERR4:cdev_del(cdev);
ERR3:unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:kfree(cdev);
ERR1:return ret;
}//当任意一方卸载,执行remove函数
int pdrv_remove(struct platform_device *pdev)
{int i = 0;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);//取消地址映射iounmap(rcc_virt);iounmap(gpioe_virt);for(i=0;i<count;i++){device_destroy(cls,MKDEV(major,i));}class_destroy(cls);cdev_del(cdev);unregister_chrdev_region(MKDEV(major,minor),count);kfree(cdev);return 0;
}const struct platform_device_id idtable[] = {{"hello1",1},{},/*防止数组越界*/
};//初始化设备驱动端结构体
struct platform_driver pdrv = {.probe = pdrv_probe,.remove = pdrv_remove,.driver = {.name = "hello DC23111", //通过名字进行匹配},.id_table = idtable,
};
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

3.pdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>//描述设备信息结构体
struct resource res[2] = {[0] = {.start = 0x50006000, //起始地址.end = 0x50006000 + 31, //终止地址.flags = IORESOURCE_MEM, //资源类型},[1] = {.start = 0x50000A28, .end = 0x50000A28 + 31,.flags = IORESOURCE_MEM,},
};
void pdev_release(struct device *dev)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
}
//初始化设备信息端结构体
struct platform_device pdev = {.name = "hello1", //通过名字进行匹配.id = PLATFORM_DEVID_AUTO, //自动分配.dev = {.release = pdev_release,},.num_resources = ARRAY_SIZE(res),.resource = res,
};static int __init demo_init(void)
{//注册设备信息端return platform_device_register(&pdev);
}static void __exit demo_exit(void)
{//注销设备信息端platform_device_unregister(&pdev);
}module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

4.test.c

#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 "myled.h"int main(int argc, const char *argv[])
{int fd = -1;int whitch;char buf[128] = "";fd = open("/dev/myled0",O_RDWR);if(fd == -1){perror("open is error");return -1;}while(1){whitch = LED1;ioctl(fd,LED_ON,&whitch);sleep(1);ioctl(fd,LED_OFF,&whitch);sleep(1);}close(fd);return 0;
}


http://www.mrgr.cn/p/55103757

相关文章

存储器数据恢复相关知识

讲述硬盘基本结构及其储存理论,介绍如何恢复常用存储器数据。目录目录理论知识 硬盘如何储存数据? 磁道和扇区简介 盘面号 磁道 柱面 扇区 硬盘如何读写数据? 数据删除原理 数据如何丢失的? 人为原因造成的数据丢失: 自然灾害造成的数据丢失: 软件原因造成…

ARM学习(26)链接库的依赖查看

笔者今天来聊一下查看链接库的依赖。 通常情况下&#xff0c;运行一个可执行文件的时候&#xff0c;可能会出现找不到依赖库的情况&#xff0c;比如图下这种情况&#xff0c;可以看到是缺少了license.dll或者libtest.so&#xff0c;所以无法运行。怎么知道它到底缺少什么dll呢&…

构建RAG应用-day05: 如何评估 LLM 应用 评估并优化生成部分 评估并优化检索部分

评估 LLM 应用 1.一般评估思路 首先,你会在一到三个样本的小样本中调整 Prompt ,尝试使其在这些样本上起效。 随后,当你对系统进行进一步测试时,可能会遇到一些棘手的例子,这些例子无法通过 Prompt 或者算法解决。 最终,你会将足够多的这些例子添加到你逐步扩大的开发集中…

android脱壳第二发:grpc-dumpdex加修复

上一篇我写的dex脱壳&#xff0c;写到银行类型的app的dex修复问题&#xff0c;因为dex中被抽取出来的函数的code_item_off 的偏移所在的内存&#xff0c;不在dex文件范围内&#xff0c;所以需要进行一定的修复&#xff0c;然后就停止了。本来不打算接着搞得&#xff0c;但是写了…

ELK 日志分析系统(二)

一、ELK Kibana 部署 1.1 安装Kibana软件包 #上传软件包 kibana-5.5.1-x86_64.rpm 到/opt目录 cd /opt rpm -ivh kibana-5.5.1-x86_64.rpm 1.2 设置 Kibana 的主配置文件 vim /etc/kibana/kibana.yml --2--取消注释&#xff0c;Kiabana 服务的默认监听端口为5601 server.po…

简单的jmeter脚本自动化

1、创建线程组&#xff0c;定义自定义变量&#xff0c;保存请求默认值 2、用csv编写测试用例 备注&#xff1a;如果单元格内本身就有引号&#xff0c;则格式会有点小问题&#xff0c;不能直接修改为csv 用txt打开后 有引号的需要在最外层多包一层引号&#xff0c;每个引号前…

SpringBoot+vue开发记录(二)

说明&#xff1a;本篇文章的主要内容为SpringBoot开发中后端的创建 项目创建: 1. 新建项目&#xff1a; 如下&#xff0c;这样简单创建就行了&#xff0c;JDK什么的就先17&#xff0c;当然1.8也是可以的&#xff0c;后面可以改。 这样就创建好了&#xff1a; 2. pom.xml…

Golang | Leetcode Golang题解之第44题通配符匹配

题目&#xff1a; 题解&#xff1a; func isMatch(s string, p string) bool {for len(s) > 0 && len(p) > 0 && p[len(p)-1] ! * {if charMatch(s[len(s)-1], p[len(p)-1]) {s s[:len(s)-1]p p[:len(p)-1]} else {return false}}if len(p) 0 {retur…

go的编译以及运行时环境

开篇 很多语言都有自己的运行时环境&#xff0c;go自然也不例外&#xff0c;那么今天我们就来讲讲go语言的运行时环境&#xff01; 不同语言的运行时环境对比 我们都知道Java的运行时环境是jvm &#xff0c;javascript的运行时环境是浏览器内核 Java -->jvm javascript…

基于Springboot的网课管理系统

基于SpringbootVue的网课管理系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 课程表 论坛交流 学校公告 后端 学生管理 教师管理 班级管理 课程分类管理…

TODO -蓝桥杯2018年A组-付账问题

0.题目 题目描述 几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。 现在有 \(n\) 个人出去吃饭,他们总共消费了 \(S\) 元。其中第 \(i\) 个人带了 \(a_i\) 元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢? 为了…

【TCP:可靠数据传输,快速重传,流量控制,TCP流量控制】

文章目录 可靠数据传输TCP&#xff1a;可靠数据传输TCP发送方事件快速重传流量控制TCP流量控制 可靠数据传输 TCP&#xff1a;可靠数据传输 TCP在IP不可靠服务的基础上建立了rdt 管道化的报文段 GBN or SR 累计确认&#xff08;像GBN&#xff09;单个重传定时器&#xff08;像…

小伙伴:我是专升本,能不写在简历里吗?

大家好,我是树哥。 最近我推出了简历辅导服务(详见:500 块就能获得 10 年的行业经验,太赚了!),有一位同学找我做了简历辅导。 在阅读他的简历的时候,我发现他的学历没有写入学时间和毕业时间,感觉不是很直观,于是让他补全一下。小伙伴回复说:我是专升本的,本科只有…

JetBrains PhpStorm v2024.1 安装教程 (PHP集成开发IDE)

前言 PhpStorm是由JetBrains推出的一款轻量级集成开发环境&#xff0c;专为PHP开发者而设计。该软件融合了智能的HTML/CSS/JavaScript/PHP编辑器、代码质量分析工具、版本控制系统集成&#xff08;包括SVN和GIT&#xff09;、调试和测试等功能。除此之外&#xff0c;PhpStorm还…

PyQt介绍——动画使用详解之QPropertyAnimation

一、继承关系 PyQt5的动画框架是QAbstractAnimation&#xff0c;它是一个抽象类&#xff0c;不能直接使用&#xff0c;需要使用它的子类。它的类结构如下&#xff1a; QAbstractAnimation&#xff1a;抽象动画&#xff0c;是所有动画的基类&#xff0c;不能直接使用。 QVariant…

Jetpack Compose 中如何实现全面屏

看问题本质,设置全面屏,是系统窗口的行为,与 View 和 Compose 有什么关系呢? 所以,原理和传统 View 视图是一样的,甚至 Api 都是一模一样的,不熟悉的可以看我之前的文章。传送门: Android 全面屏体验 那为什么还要写这篇文章呢?主要是在 Compose 中写法上的一些区别,…

论文解读:Label Hallucination for Few-Shot Classification

文章汇总 动机 本文的一个思想就是&#xff1a;尽管新类的标签并不能“恰如其分”地表示基数据集中的样本&#xff0c;但是很多基数据集的样本会包含与新类中相似的对象&#xff0c;例如&#xff0c;基数据集中的老虎和新类中的猫有相似的特征&#xff0c;那么就有60%的概率将…

【CSS】使用 scroll snap 实现页面的垂直大屏滚动

CSS 属性 scroll-snap-type 设置了在有滚动容器的情形下吸附至吸附点的严格程度。 scroll-snap-type 使用 scroll snap 也可以用于垂直滚动&#xff0c;全屏展示就是一个很好的例子: <main><section class"section section-1"></section><sect…

4.26文件上传学习

文件上传,绕过,验证,检测一、文件上传 概念:(不赘述转web安全文件上传)[[9.6-9.7基础和过滤方式]] 前置知识:(除解析漏洞)后门代码需要以特定格式后缀解析,不能以图片后缀解析; 知识点 1、文件上传-前端验证 直接修改前端js代码,文件上传格式; 2、黑白名单 3、use…

MySQL—MySQL的存储引擎之InnoDB

MySQL—MySQL的存储引擎之InnoDB 存储引擎及种类 存储引擎说明MyISAM高速引擎&#xff0c;拥有较高的插入&#xff0c;查询速度&#xff0c;但不支持事务InnoDB5.5版本后MySQL的默认数据库存储引擎&#xff0c;支持事务和行级锁&#xff0c;比MyISAM处理速度稍慢ISAMMyISAM的…