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

platform(驱动层+应用层)实现终端和中断开关点灯

设备树文件添加

myplatform{compatible="hqyj,myplatform";interrupt-parent=<&gpiof>;interrupts=<8 0>,<7 0>,<9 0>;led1-gpio=<&gpioe 10 0>;led2-gpio=<&gpiof 10 0>;led3-gpio=<&gpioe 8 0>;reg=<0x12345678 0x400>;};

应用层

#include<stdio.h>
#include<stdlib.h>
#include<string.h>#include<fcntl.h>
#include<unistd.h>#include<sys/types.h>
#include<sys/stat.h>
#include<sys/ioctl.h>#include"head.h"int main(int argc, char const *argv[])
{int fd;int devc;//设备的编号char buf[128];printf("选择需要打开的设备文件(led)>>");//配置需要打开的设备文件scanf("%d",&devc);sprintf(buf,"/dev/myled%d",devc);printf("路径为:%s",buf);fd=open(buf,O_RDWR);if (fd<0){printf("文件打开失败\n");return -1;}printf("设备文件打开成功\n");int a,b;//输入的值while (1){out:printf("选择需要打开的灯led 1 led 2 led 3>>");scanf("%d",&a);printf("选择要实现的功能 0 关 1开>>");scanf("%d",&b);switch (b){case 0:ioctl(fd,LED_OFF,a);  break;case 1:ioctl(fd,LED_ON,a);  break;default:printf("输入错误请重新输入\n");goto out;break;}}return 0;
}

头文件

#ifndef __HEAD_H__
#define __HEAD_H__#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/gpio.h>
#include<linux/of.h>
#include<linux/of_gpio.h>#include"head.h"#include <linux/platform_device.h>void pdev_release(struct device *dev)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
}
struct resource res[]={[0]={.start=0x50006000,//起始地址.end=0x50006000+0x400,//终止地址.name="pe_mem",//名字.flags=IORESOURCE_MEM	,//标志位地址空间},[1]={.start=71,.end=71,.name="key1_irq",.flags=IORESOURCE_IRQ,},[2]={.start=72,.end=72,.name="key2_irq",.flags=IORESOURCE_IRQ,},[3]={.start=73,.end=73,.name="key3_irq",.flags=IORESOURCE_IRQ,},
};
//设备结构体
struct platform_device pdev={.name="aaaaa",.id=PLATFORM_DEVID_AUTO,.dev={.release=pdev_release,},.num_resources=ARRAY_SIZE(res),.resource=res,
};
static int __init mycdev_init(void)
{platform_device_register(&pdev);return 0;
}
static void __exit mycdev_exit(void)
{platform_device_unregister(&pdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

驱动层

#include <linux/init.h>
#include <linux/module.h>#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/gpio.h>#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>#include <linux/interrupt.h>
#include"head.h"struct resource *res;
unsigned int irq_no[3];int major;
char kbuf[128]={0};struct class *cls;
struct device *dev_c;struct device_node *dnode;struct gpio_desc *lednode1;
struct gpio_desc *lednode2;
struct gpio_desc *lednode3;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)
{switch (cmd){case LED_OFF:switch (arg){case 1:gpiod_set_value(lednode1,0);break;case 2:gpiod_set_value(lednode2,0);break;case 3:gpiod_set_value(lednode3,0);break;}break;case LED_ON:switch (arg){case 1:gpiod_set_value(lednode1,1);break;case 2:gpiod_set_value(lednode2,1);break;case 3:gpiod_set_value(lednode3,1);break;}break;default: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,.read=mycdev_read,.write=mycdev_write,.unlocked_ioctl=mycdev_ioctl,.release=mycdev_close,
};irqreturn_t myirq_handle(int irq,void *dev)
{switch ((unsigned int)dev){case 0://反转电平gpiod_set_value(lednode1,!gpiod_get_value(lednode1));//防止其他灯亮gpiod_set_value(lednode2,0);gpiod_set_value(lednode3,0);break;case 1://反转电平gpiod_set_value(lednode2,!gpiod_get_value(lednode2));//防止其他灯亮gpiod_set_value(lednode1,0);gpiod_set_value(lednode3,0);break;case 2://反转电平gpiod_set_value(lednode3,!gpiod_get_value(lednode3));//防止其他灯亮gpiod_set_value(lednode1,0);gpiod_set_value(lednode2,0);break;default:break;}return IRQ_HANDLED;}int pdrv_probe(struct platform_device *dev)
{printk("%s:%s:%d",__FILE__,__func__,__LINE__);//字符设备驱动注册major=register_chrdev(0,"mychrdev",&fops);if(major<0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n",major);//向上提交目录cls=class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");int i;for(i=0;i<3;i++){dev_c=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);//制作字符设备文件if(IS_ERR(dev_c)){printk("向上提交设备节点失败\n");return -PTR_ERR(dev_c);}}printk("向上提交设备节点成功\n");res=platform_get_resource(dev,IORESOURCE_MEM,0);if(res==NULL){printk("获取MEM类型资源失败\n");return -EFAULT;}  printk("MEM类型资源为%x\n",res->start);//获取中断类型的资源for ( i = 0; i < 3; i++){irq_no[i]=platform_get_irq(dev,i);if (irq_no[i]<0){printk("获取中断类型资源失败\n");return irq_no[i];}printk("获取中断类型资源值为%d\n",irq_no[i]);}//解析LED1的gpio编号lednode1=gpiod_get_from_of_node(dev->dev.of_node,"led1-gpio",0,GPIOD_OUT_LOW,NULL);if (lednode1==NULL){printk("解析gpio编号失败\n");return -ENXIO;}lednode2=gpiod_get_from_of_node(dev->dev.of_node,"led2-gpio",0,GPIOD_OUT_LOW,NULL);if (lednode2==NULL){printk("解析gpio编号失败\n");return -ENXIO;}lednode3=gpiod_get_from_of_node(dev->dev.of_node,"led3-gpio",0,GPIOD_OUT_LOW,NULL);if (lednode3==NULL){printk("解析gpio编号失败\n");return -ENXIO;}printk("解析gpio-led编号成功\n");for ( i = 0; i < 3; i++){irq_no[i]=irq_of_parse_and_map(dev->dev.of_node,i);if(!irq_no[i]){printk("解析软中断失败\n");return -ENXIO;}printk("解析%d 软中断成功\n",i+1);int ret=request_irq(irq_no[i],myirq_handle,IRQF_TRIGGER_FALLING,"key",(void*)i); if(ret){printk("注册按键请求中断失败\n");return ret;}}printk("注册按键请求中断成功\n");return 0;
}int pdrv_remove(struct platform_device *dev)
{gpiod_set_value(lednode1,0);gpiod_put(lednode1);gpiod_set_value(lednode2,0);gpiod_put(lednode2);gpiod_set_value(lednode3,0);gpiod_put(lednode3);int i;
for ( i = 0; i < 3; i++)
{free_irq(irq_no[i],(void*)i);device_destroy(cls,MKDEV(major,i));
}//销毁目录class_destroy(cls);//注销字符设备驱动unregister_chrdev(major,"mychrdev");printk("%s:%s:%d",__FILE__,__func__,__LINE__);return 0;
}struct of_device_id oftable[]=
{{.compatible="hqyj,myplatform",},{/*end node*/},//防止数组越界
};struct platform_driver pdrv={.probe=pdrv_probe,.remove=pdrv_remove,.driver={.name="bbbbb",.of_match_table=oftable,//设置设备树匹配},};module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

现象演示

http://www.lryc.cn/news/305755.html

相关文章:

  • 黑马JavaWeb开发跟学(一)Web前端开发HTML、CSS基础
  • Nest.js权限管理系统开发(四)Swagger API接入
  • (全注解开发)学习Spring-MVC的第三天
  • 设计模式学习笔记 - 面向对象 - 7.为什么要多用组合少用继承?如何决定该用组合还是继承?
  • RocketMQ生产环境常见问题分析与总结
  • 前端打包工具的发展历程、思路(grunt,gulp,webpack,vite)
  • 利用Python将文件夹下多个txt文本写入到同一个excel中(每一个文件占一行)
  • 通过Colab部署Google最新发布的Gemma模型
  • spring中@validate注解使用
  • 停车场管理(C语言)
  • 探索无限:Sora与AI视频模型的技术革命 - 开创未来视觉艺术的新篇章
  • 375FPS! 谷歌提出MaskConver“重校正用于全景分割的纯卷积模型
  • leetcode初级算法(python)- 数组
  • 重新定义音乐创作:ChatGPT与未来音乐产业的融合
  • 人工智能绘画的时代下到底是谁在主导,是人类的想象力,还是AI的创造力?
  • [HTML]Web前端开发技术29(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页
  • 文本编辑器markdown语法
  • 【C++】类和对象之拷贝构造函数篇
  • Mybatisplus 传参参数为自定义sql, 使用条件构造器作为参数
  • C#与VisionPro联合开发——TCP/IP通信
  • spring Boot快速入门
  • FPGA SERDESE2 (SDR收发仿真)
  • Java异常体系结构核心解析-Throwable
  • Android MediaRecorder 相关
  • Spring中关于事务的一些方方面面
  • LiveQing视频点播流媒体RTMP推流服务功能-支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务
  • LabVIEW串口通信的激光器模块智能控制
  • 全球最受欢迎的DAWFL Studio 21.2.3.4004 中文破解版强悍来袭
  • 【uni-app】常用组件和 API
  • 基于springboot+vue的安康旅游网站(前后端分离)