2.18通过字符设备驱动分步注册过程实现LED驱动的编写,编写应用程序测试

应用程序:

#include<stdlib.h>
#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, char const *argv[])
{int a,b;int fd=open("/dev/myled0",O_RDWR);if(fd<0){printf("打开设备文件失败\n");exit(-1);}while(1){//从终端读取printf("请输入要实现的功能\n");printf("0(关灯) 1(开灯)\n");printf("请输入>");scanf("%d",&a);printf("请输入要控制的灯\n");printf("1(LED1) 2(LED2) 3(LED3)\n");printf("请输入>");scanf("%d",&b);switch(a){case 1:ioctl(fd,LED_ON,&b);break;case 0:ioctl(fd,LED_OFF,&b);break;}}close(fd);return 0;
}

头文件:

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

驱动程序:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include "myled.h"
struct cdev *cdev;
char kbuf[128]={0};
unsigned int major=0;//主设备号
unsigned int minor=0;//次设备号
dev_t devno;
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)
{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__);unsigned long ret;// 向用户空间读取拷贝if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size = sizeof(kbuf);ret = copy_to_user(ubuf, kbuf, size);if (ret) // 拷贝失败{printk("copy_to_user filed\n");return ret;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{unsigned long ret;// 从用户空间读取数据if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size = sizeof(kbuf);ret = copy_from_user(kbuf, ubuf, size);if (ret) // 拷贝失败{printk("copy_to_user filed\n");return ret;}return 0;
}long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int wh;int ret=copy_from_user(&wh,(void *)arg,4);if(ret)//拷贝失败{printk("copy_from_user filed\n");return ret;}switch(cmd){case LED_ON:switch(wh){case 1:vir_led1->ODR |= (1<<10);break;case 2:vir_led2->ODR |= (1<<10);break;case 3:vir_led3->ODR |= (1<<8);break;} break;case LED_OFF:switch(wh){case 1:vir_led1->ODR &= (~(1<<10));break;case 2:vir_led2->ODR &= (~(1<<10));break;case 3: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;
}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;
}
// 定义操作方法结构体变量并赋值
struct file_operations fops = {.open = mycdev_open,.read = mycdev_read,.write = mycdev_write,.unlocked_ioctl=mycdev_ioctl,.release = mycdev_close,
};
static int __init mycdev_init(void)
{
int ret;//1.申请字符设备驱动对象空间cdev=cdev_alloc();if(cdev==NULL){return -EFAULT;}printk("字符设备驱动对象申请成功\n");//2.初始化字符设备驱动对象cdev_init(cdev,&fops);//3.申请设备号if(major==0)//动态申请{ret=alloc_chrdev_region(&devno,minor,3,"myled");if(ret){printk("动态申请设备号失败\n");goto out1;}//为了统一和静态申请设备号的操作major=MAJOR(devno);minor=MINOR(devno);}else//静态指定{ret=register_chrdev_region(MKDEV(major,minor),3,"myled");if(ret){printk("静态申请设备号失败\n");goto out1;}}printk("设备号申请成功\n");//4.注册驱动 ret= cdev_add(cdev,MKDEV(major,minor),3);if(ret){printk("注册驱动失败\n");goto out2;}  printk("注册驱动成功\n");//5.向上提交目录cls=class_create(THIS_MODULE,"led");if(IS_ERR(cls)){printk("向上提交目录失败\n");ret=-PTR_ERR(cls);goto out3;}printk("向上提交目录成功\n");//6.向上提交设备节点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 out4;}}printk("向上提交设备信息成功\n");//寄存器映射以及初始化all_led_init();return 0;
out4:
//销毁提交成功的设备信息for(--i;i>=0;i--){device_destroy(cls,MKDEV(major,i));}//销毁目录class_destroy(cls);
out3:cdev_del(cdev);
out2:unregister_chrdev_region(MKDEV(major,minor),3);
out1:kfree(cdev);return ret;
}static void __exit mycdev_exit(void)
{//取消地址映射iounmap(vir_led1);iounmap(vir_led2);iounmap(vir_rcc);//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");

效果图: 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/688507.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云香港轻量应用服务器是什么线路?cn2?

阿里云香港轻量应用服务器是什么线路&#xff1f;不是cn2。 阿里云香港轻量服务器是cn2吗&#xff1f;香港轻量服务器不是cn2。阿腾云atengyun.com正好有一台阿里云轻量应用服务器&#xff0c;通过mtr traceroute测试了一下&#xff0c;最后一跳是202.97开头的ip&#xff0c;1…

递归算法与分治思想

递归算法 直接或间接的调用自身的算法称为递归函数,采用栈结构,先调用的最后返回。 主要形式就是先纵后横,一个分支走到底,再退回一个到兄弟节点,依次回退。 列出递归的三种形式:切蛋糕、递推公式、等价转换。 递归要素: 明确递归得到结果是什么提取重复的逻辑,缩小…

数据库第五次实验

目录 1 创建数据表 2 创建多个用户 ​​​​​​​3 用户的授权 ​​​​​​​4 用户权限的回收 ​​​​​​​5 角色的创建与授权 ​​​​​​​6 回收角色的权利 ​​​​​​​7 审计的设置 1 创建数据表 SQL语句&#xff1a; use experimentfive; create table…

2024年开工,煮熟的鸭子飞了咋办

去年是我居家创业的第一个年头&#xff0c;业绩总体来说不及预期&#xff08;上班的收入&#xff09;&#xff0c;仅仅满足日常开支&#xff0c;没有任何的盈余。 去年有点项目没完成收尾&#xff0c;所以初四我就选择开工了&#xff0c;就图一个大吉大利。年前积压的客户需求…

【uCore 操作系统】1. 应用程序与基本执行环境

文章目录 【 1. 代码框架简述 】1.1 OS 是怎么跑起来的&#xff1f;1.1.1 qemu 的作用1.1.2 rustsbi.bin 的作用 1.2 qemu 是怎么跑起来的&#xff1f;1.3 OS 文件夹1.3.1 kernel.ld1.3.2 entry.S1.3.3 main.c1.3.4 sbi.c 1.4 bootloader 文件夹 【 2. makefile 和 qemu 】2.1 …

【SpringBoot】项目启动增加自定义Banner

SpringBoot项目启动增加自定义Banner 前言 最近有个老哥推荐我给博客启动的时候加上自定义Banner&#xff0c;开始我还不太明白他说的是那部分&#xff0c;后面给我发了这样一个&#xff0c;瞬间就懂了~ // _ooOoo_ …

C++入门篇——命名空间

在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存 在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c; 以避免命名冲突或名字污染&#xff0c;namespace关键…

数字经济政策 | ZF工作报告-60个文本词频

根据各省政府工作报告&#xff0c;参考金灿阳(2022)和陶长琪(2022)&#xff0c;借助Python软件&#xff0c;统计数字经济相关的关键词词频&#xff0c;分别记为数字经济政策词频A、数字经济政策词频B A文献参考 B文献参考 年度趋势 一、数据介绍 数据名称&#xff1a; 政府工…

Spring Boot java -jar --spring.profiles.active=dev 失效问题

之前动态部署修改配置文件的情况不多&#xff0c;所以也没注意过&#xff0c;这个问题今天困扰了好久&#xff0c;经过多方查询后得到了解决办法 直接上代码 <profiles><profile><!-- 本地开发环境 --><id>dev</id><properties><profi…

债券专题二:可转债估值-二叉树模型

1. 模型背景 由于可转债自身的属性较多&#xff0c;因此对其定价的难度也会加大&#xff0c;在诸多影响因素中&#xff0c;未来的股价占比最高。由于股价的不可预测性&#xff0c;导致了可转债的定价在实际交易中作用非常有限。随着可转债发行数量和规模的增大&#xff0c;越…

2.18 C++ day6

思维导图 以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲…

C++初阶(十三) 模板

一、非类型模板参数 模板参数分类类型形参与非类型形参。类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当成常量…

基于微信小程序的健身房私教预约系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

嵌入式调试工具之GDB

在单片机开发中&#xff0c;我们可以通过集成式的IDE 来进行调试&#xff0c;比如 MDK、IAR 等。 GDB 工具是 GNU 项目调试器&#xff0c;基于命令行使用。和其他的调试器一样&#xff0c;可使用 GDB工具单步运行程序、单步执行、跳入/跳出函数、设置断点、查看变量等等&#…

2023我患上了AI焦虑

2023我患上了AI焦虑 来自&#xff1a;宝玉 原文链接&#xff1a;https://baoyu.io/blog/ai/i-am-suffering-from-ai-anxiety-in-2023 2023 年对我来说是神奇的一年&#xff0c;我意外的从一个程序员变成了一个 AI 资讯届的“网红”&#xff0c;到年底的时候我在 X 平台的阅读量…

IT行业高含金量证书全解析:开启职业生涯新篇章

在快速发展的IT行业&#xff0c;持续学习和专业认证是提升个人竞争力的重要途径。全球范围内存在着众多的IT认证&#xff0c;它们不仅能够验证你的技术能力&#xff0c;还能在求职和职业晋升中起到关键作用。 本篇博客将深入探讨IT行业中部分高含金量的证书&#xff0c;包括中…

最长子串和回文子串相关的算法题解

这里写目录标题 一、3. 无重复字符的最长子串二、5. 最长回文子串三、647. 回文子串四、516. 最长回文子序列 一、3. 无重复字符的最长子串 中等 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释:…

MyBatis核心配置文件详解

MyBatis核心配置文件详解 一、Environments标签1.Environment标签详解&#xff08;1&#xff09;如何创建对应环境的 SqlSessionFactory对象 2.transactionManager标签详解3.dataSource标签详解&#xff08;1&#xff09;UNPOOLED&#xff08;2&#xff09;POOLED&#xff08;3…

线性回归-使用ClickHouse机器学习函数

本文字数&#xff1a;5923&#xff1b;估计阅读时间&#xff1a;15 分钟 作者&#xff1a;Ensemble 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 这原本是转发的ensemble analytics的文章。 【https://ensembleanalytics.io/blog/l…

Java面试第一站:计算机网络基础知识

该系列会持续更新&#xff0c;关注我&#xff0c;第一时间获取我的最新动态哟 Java面试中&#xff0c;经常会问到跟计算机网络知识相关的考点&#xff0c;有的小伙伴不是很明白。考察网络知识有什么意义&#xff1f; 因为编程的时候&#xff0c;多数的情况下是不用我们来编写 …