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");

现象演示

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

锂电池SOC估计 | PyTorch实现基于Basisformer模型的锂电池SOC估计

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 PyTorch实现基于Basisformer模型的锂电池SOC估计 锂电池SOC估计&#xff0c;全新【Basisformer】时间序列预测 1.采用自适应监督自监督对比学习方法学习时序特征&#xff1b; 2.通过双向交叉注意力机制计算历史序列和…

从源码学习static的使用

从源码学习static的使用 前言 ​ static意味静态的&#xff0c;在Java中&#xff0c;主要用来修饰类级别的变量或方法等&#xff0c;被修饰的内容&#xff0c;表示随着类的加载而加载&#xff0c;而不是具体的实例级别。 ​ 具体到static的使用场景&#xff0c;主要有以下用…

java 并发的三大特性

CPU 三级缓存架构 为平衡CPU与主存的处理速度问题&#xff0c;提出在CPU中设置多级缓存机制。 当CPU要读取一个数据时&#xff0c;首先从一级缓存中查找&#xff0c;如果没有找到再从二级缓存中查找&#xff0c;如果还是没有就从三级缓存或内存中查找。 每个核心都含有一套L…

高频面试题整理(一)

文章目录 平台无关性如何实现&#xff1f;JVM如何加载 .class文件&#xff1f;什么是反射?谈谈ClassLoader谈谈类的双亲委派机制类的加载方式Java的内存模型?JVM内存模型-jdk8程序计数器&#xff1a;Java虚拟机栈局部变量表和操作数栈&#xff1a; Java内存模型中堆和栈的区别…

vector 用法

C++数组是继承C语言的,C++标准库中的vector封装了动态数组,是一个模板类(vector<int>,<>里面可以是各种类型。 定义方式: vector<元素类型> 对象名(长度); (注:vector还有个好处就是,数组定义时长度那里不能包含变量,但是vector定义时长度那里可…

家政小程序有哪些功能 怎么制作

随着人们生活节奏的加快&#xff0c;家政服务变得越来越受到人们的青睐。为了提升家政服务的便捷性和高效性&#xff0c;家政小程序成为了越来越受欢迎的选择。下面具体介绍家政小程序有哪些功能&#xff0c;如何制作。 1. 展示家政服务 在小程序中&#xff0c;上传所有的家政…

C语言中的字体背景颜色汇总

客官请看效果 客官请看代码 #include <stdio.h> #include <stdlib.h> #include <windows.h>int main() {int i;for (i 0; i < 254; i) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), i); // 设置当前文本颜色为循环变量对应的颜色printf(…

Git+py+ipynb Usage

0.default config ssh-keygen -t rsa #之后一路回车,当前目录.ssh/下产生公私钥 cat ~/.ssh/id_rsa.pub #复制公钥到账号 git config --global user.email account_email git config --global user.name account_namebug of ipynb TqdmWarning: IProgress not found. Please …

移动端自动化常用的元素定位工具 介绍

在移动端自动化测试和开发中&#xff0c;元素定位是非常关键的一步。以下是一些常用的工具和技术来帮助开发者或测试工程师在移动设备上定位元素&#xff1a; 1. **UiAutomator**: - **UiAutomator** 是 Android 官方提供的自动化测试框架。它可以用来编写测试脚本&…

【电子通识】为什么单片机芯片上会有多组VDD电源?

在单片机芯片规格书中&#xff0c;我们经常能看到多个组VDD的设计&#xff0c;如下红框所示管脚都是VDD管脚。 为什么需要这样设计&#xff1f;只设置一个VDD管脚&#xff0c;把其他的VDD管脚让出来多做几个IO或是其他复用功能不好吗&#xff1f;接下来我们从单片机内部的电路结…

微信小程序商城-兜点零食

微信小程序商城 【微信小程序商城-兜点零食】 小程序采用uniappvue开发&#xff0c;后台djangopython开发&#xff0c;模块化方便二次开发 1、具备商城完整功能&#xff0c;包括在线下单、支付、订单跟踪、物流查询&#xff1b; 2、具备社交化分享功能&#xff0c;为用户提供分…

【Java程序设计】【C00290】基于Springboot的网上书城管理系统(有论文)

基于Springboot的网上书城管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的网上书城管理系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;在系统首页可以查看首…

【数据结构】时间复杂度(加法乘法规则、渐近时间复杂度、循环时间复杂度总结

2.2 时间复杂度 什么是时间复杂度&#xff1f; 评估算法时间开销 T ( n ) O ( f ( n ) ) T(n)O(f(n)) T(n)O(f(n)) 在实际求解中&#xff0c;只留表达式中最高阶的部分&#xff0c;丢弃其他部分。 如何求解&#xff1f; 求解步骤 1.找到一个最深层的基本操作&#xff1b; 2.分…

yolov8添加注意力机制模块-CBAM

修改 在tasks.py&#xff08;路径&#xff1a;ultralytics-main/ultralytics-main - attention/ultralytics/nn/tasks.py&#xff09;文件中&#xff0c;引入CBAM模块。因为yolov8源码中已经包含CBAM模块&#xff0c;在conv.py文件中&#xff08;路径&#xff1a;ultralytics-…

【README 小技巧】在项目README.md 中展示github点赞数量

在项目README.md 中展示github点赞数量 [![Star History Chart](https://api.star-history.com/svg?reposwujiawei1207537021/wu-lazy-cloud-network&typeDate)](https://star-history.com/#wujiawei1207537021/wu-lazy-cloud-network&Date)效果

【微服务】mybatis typehandler使用详解

目录 一、前言 二、TypeHandler简介 2.1 什么是TypeHandler 2.1.1 TypeHandler特点 2.2 TypeHandler原理 2.3 mybatis自带的TypeHandler 三、环境准备 3.1 准备一张数据表 3.2 搭建一个springboot工程 3.2.1 基础依赖如下 3.2.2 核心配置文件 3.2.3 测试接口 四、T…

java面向对象高级

一、静态 static读作静态&#xff0c;可以用来修饰成员变量&#xff0c;也能修饰成员方法。我们先来学习static修饰成员变量。 1.1 static修饰成员变量 Java中的成员变量按照有无static修饰分为两种&#xff1a;类变量、实例变量。它们的区别如下图所示&#xff1a; 由于静态…

通过底层原理理解Java是值传递还是引用传递?

本文学习目标或者巩固的知识点 参数传递方式 值传递引用传递指针传递 彻底理解Java的值传递和引用传递 从底层的角度分析值传递会发生复制行为 Java的参数传递例子 快手的一面面试曾经问到过此类题目&#xff0c;所以记下此篇加深印象。 问&#xff1a;求下面main方法中的输…

常用状态码

状态码 用于响应中的&#xff0c;表示响应的结果如何 1、200 OK 运行成功 2、404 Not Found 访问的资源没有找到&#xff08;url的路径&#xff09; 3、403 Forbidden 请求资源没有权限访问 4、405 Method Not Allowed 你的服务器只支持GET请求&#xff0c;但是你发了个PO…

基于springboot+vue的校园社团信息管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…