驱动day6

 驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
struct cdev *cdev;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
unsigned int major=500;
unsigned int minor=0;//次设备号的起始值
dev_t devno;
struct class *cls;
struct device *dev;
char kbuf[128]={0};
static int number=0;
unsigned int irqno;
struct resource *res;
struct device_node *dnodel;
//定义等待队列头
wait_queue_head_t wq_head;
unsigned int condition=0;
//中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{   number=!number;printk("key1 interrupt\n");gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1)); condition=1;//表示硬件数据就绪wake_up_interruptible(&wq_head);//唤醒休眠的进程return IRQ_HANDLED;
}
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)
{int ret;if(sizeof(number)<size)size=sizeof(number);wait_event_interruptible(wq_head,condition);//将进程切换为休眠ret=copy_to_user(ubuf,&number,size);if(ret){printk("copy_to_user filed\n");return -EIO;}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);condition=0;//表示下一次硬件数据没有准备好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,.release = mycdev_close,
};int pdrv_probe(struct platform_device *pdev) 
{   int ret,i;/****************************************************///初始化等待队列头init_waitqueue_head(&wq_head);//1.分配字符设备驱动对象空间  cdev_alloccdev=cdev_alloc();if(cdev==NULL){printk("申请字符设备驱动对象空间失败\n");ret=-EFAULT;goto out1;}printk("字符设备驱动对象申请成功\n");//2.字符设备驱动对象部分初始化  cdev_initcdev_init(cdev,&fops);//3.申请设备号  register_chrdev_region/alloc_chrdev_regionif(major>0)//静态申请设备号{ret=register_chrdev_region(MKDEV(major,minor),3,"myled");if(ret){printk("静态指定设备号失败\n");goto out2;}}else//动态申请设备号{ret=alloc_chrdev_region(&devno,minor,3,"myled");if(ret){printk("动态申请设备号失败\n");goto out2;}major=MAJOR(devno);//根据设备号得到主设备号minor=MINOR(devno);//根据设备号得到次设备号}printk("申请设备号成功\n");//4.注册字符设备驱动对象  cdev_add()ret=cdev_add(cdev,MKDEV(major,minor),3);if(ret){printk("注册字符设备驱动对象失败\n");goto out3;}printk("注册字符设备驱动对象成功\n");//5.向上提交目录cls=class_create(THIS_MODULE,"myled");if(IS_ERR(cls)){printk("向上提交目录失败\n");ret=-PTR_ERR(cls);goto out4;}printk("向上提交目录成功\n");//6.向上提交设备节点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");/********************************************************///获取gpio信息//pdev->dev.of_node  设备树匹配之后会把设备树节点结构体首地址赋值给dev的of_node成员gpiono1=gpiod_get_from_of_node(pdev->dev.of_node,"led1",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono1)){printk("解析GPIO信息失败\n");return -PTR_ERR(gpiono1);} //获取软中断号  irqno=platform_get_irq(pdev,0);if(irqno<0){printk("获取中断资源失败\n");return irqno;}printk("中断类型资源为%d\n",irqno);//注册中断ret=request_irq(irqno,myirq_handler,IRQF_TRIGGER_FALLING,"key1",NULL);if(ret){printk("注册驱动失败\n");return ret;}printk("key1中断注册成功\n");printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);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;}
//remove 设备和驱动分离时执行
int pdrv_remove(struct platform_device *pdev)
{   //1.销毁设备信息  device_destroyint i;for(i=0;i<3;i++){device_destroy(cls,MKDEV(major,i));}//2.销毁目录  class_destroyclass_destroy(cls);//3.注销对象  cdev_del()cdev_del(cdev);//4.释放设备号   unregister_chrdev_region()unregister_chrdev_region(MKDEV(major,minor),3);//5.释放对象空间  kfree()kfree(cdev);//注销中断free_irq(irqno,NULL);//释放gpio编号gpiod_put(gpiono1);printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
struct of_device_id oftable[]={{.compatible="hqyj,myplatform",}, {.compatible="hqyj,myplatform1",}, {},
};
struct platform_driver pdrv={.probe=pdrv_probe,.remove=pdrv_remove,.driver={.name="aaaaa", .of_match_table=oftable,//设置设备树匹配},   
};
//一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

应用程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
unsigned int number;
int main(int argc, char const *argv[])
{char buf[128] = {0};int fd = open("/dev/myled0", O_RDWR);if (fd < 0){printf("打开设备文件失败\n");exit(-1);}while (1){read(fd, &number, sizeof(number));printf("number:%d\n",number);}close(fd);return 0;
}

实验现象

 

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

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

相关文章

LayUI 实现二级导航栏

目录 实现步骤&#xff1a; 1. 分析数据库 2. 构建数据源 2.1 编写实体类 2.2 编写节点实体类 2.3 构建BuildTree节点结构方法类 2.4 编写dao类 2.5 编写数据Acntion控制类 3. 前台准备 3.1 配置mvc.xml文件 3.2 页面编写 3.3 运行效果 实现步骤&#xff1a; 1. 分…

Linux系统使用(超详细)

目录 Linux操作系统简介 Linux和windows区别 Linux常见命令 Linux目录结构 Linux命令提示符 常用命令 ls cd pwd touch cat echo mkdir rm cp mv vim vim的基本使用 grep netstat Linux面试题 Linux操作系统简介 Linux操作系统是和windows操作系统是并列…

在线试用Stable Diffusion生成可爱的图片

文章目录 一、 Stable Diffusion 模型在线使用地址&#xff1a;二、模型相关版本和参数配置&#xff1a;三、图片生成提示词与反向提示词&#xff1a;提示词1提示词2提示词3提示词4提示词5 一、 Stable Diffusion 模型在线使用地址&#xff1a; https://inscode.csdn.net/insc…

centos7 环境下部署 nacos单机模式

1、官网下载 nacos 官网地址&#xff1a;home 去github上下载nacos-server。我下载的是 nacos-server-1.4.1.tar.gz 2、安装 nacos 下载完成后&#xff0c;将安装包上传到 centos 创建 nacos 目录&#xff08;安装位置任意&#xff09; mkdir -p /usr/local/nacos解压 nac…

实战打靶集锦-021-glasgowsmile

提示&#xff1a;本文记录了博主的一次曲折的打靶经历。 目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 手工访问4.2 目录枚举4.3 手工探查4.4 搜索EXP4.5 joomlascan4.6 用户猜测与密码爆破4.7 构建反弹shell 5. 提权5.1 优化shell5.2 枚举系统信息5.3 探查/etc/pass…

第24章:事务基础知识

一、数据库事务Transactions 1.为什么要使用事务 事务可以让数据库保持一致性&#xff0c;通过事务的机制恢复到某个时间点&#xff0c;即使系统崩溃数据库修改的数据不会丢失。 2.存储引擎支持事务的情况 命令: show engines; 只有InnoDB支持事务 3.事务基本概念 事务&a…

【Distributed】分布式ELK日志文件分析系统(一)

文章目录 一、ELK 概述1. 为什么要使用 ELK2. 完整日志系统基本特征3. ELK 简介3.1 ElasticSearch&#xff08;ES&#xff09;3.2 Kiabana3.3 Logstash3.4 其它组件Filebeat缓存/消息队列Fluentd 4. ELK 的工作原理5. Linux 系统内核日志消息的优先级别 二、 部署 ELK 集群服务…

JAVA开发(JAVA视频监控接口相关)

一、背景 最近在做视频监控接口相关的开发&#xff0c;需要调用视频的接口获取直播地址&#xff0c;回放地址&#xff0c;然后集成到web里查看。 二、涉及的接口 1、获取卡口的id 2、通过卡口id获取通道&#xff08;设备的id&#xff09; 3、通过设备的id获取到直播地址 4…

密码学入门——HMAC

文章目录 一、什么是HMAC二、HMAC的步骤 一、什么是HMAC HMAC是一种使用单向散列函数来构造消息认证码的方法(RFC2104)&#xff0c;其中 HMAC的H就是Hash的意思。 HMAC 中所使用的单向散列函数并不仅限于一种&#xff0c;任何高强度的单向散列函数都可以被用于HMAC&#xff0…

Java028——Runtime 类

一、Runtime 类介绍 Runtime 类是JDK 提供的运行时类&#xff0c;该类为 Java 程序提供了与当前运行环境相连接的一个通道,Java 程序可以利用该类对当前的运行环境执行一些简单的操作。 二、Runtime 对象的创建 Runtime 类对象不能使用 new 关键字创建&#xff0c;只能通过 …

jmeter 终端命令执行jmx文件 生成jtl日志文件

终端命令执行jmx文件 生成jtl日志文件&#xff0c; 步骤如下&#xff1a; 步骤1&#xff1a;终端进入jmx文件目录 步骤2&#xff1a;执行命令&#xff1a;jmeter -n -t ****.jmx -l ****.jtl -n 以cli模式&#xff08;命令行运行模式&#xff09;运行jmeter -t 需要运行的…

OnlyHome三代金属智能手环|健康、科技齐实现

近年来,人们越来越追求生活的品质与趣味,生活中的一点点小确幸、小惊喜最能让人感受到深深地愉悦。这不,Only&Home三代金属智能手环也带来了惊喜,有了它,健康、科技两手抓,享受生活更自由。 Only&Home三代金属智能手环给人的第一印象是它超高的颜值,延用了二代手环奢华…