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

news2025/4/8 5:28:58

设备树文件添加

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.coloradmin.cn/o/1470110.html

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

相关文章

什么是抖音视频下载软件|视频批量下载|爬虫工具

抖音视频抓取软件是一款方便用户获取抖音平台上视频内容的工具。它具备以下主要功能&#xff1a; 批量视频提取&#xff1a;用户可以输入关键词&#xff0c;软件将自动搜索抖音平台上与关键词相关的视频&#xff0c;并将它们列出供用户选择和下载。用户可以随时停止搜索和下载过…

测试C#使用PuppeteerSharp将网页生成PDF文件

微信公众号“DotNet开发跳槽”、“dotNET跨平台”、“DotNet”发布了几篇将网页生成图片或pdf文件的文章&#xff08;参考文献2-5&#xff09;&#xff0c;其中介绍了使用puppeteer-sharp、Select.HtmlToPdf、iTextSharp等多种方式实现html转图片或pdf&#xff0c;正好最近有类…

2024年危险化学品经营单位主要负责人证考试题库及危险化学品经营单位主要负责人试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年危险化学品经营单位主要负责人证考试题库及危险化学品经营单位主要负责人试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特…

Linux之部署前后端分离项目

Nginx配置安装 1.安装依赖 我们这里安装的依赖是有4个的 [rootlocalhost opt]# yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 2.上传解压安装包 [rootlocalhost opt]# tar -xvf nginx-1.13.7.tar.gz -C /usr/local/java/3.安装Nginx &#xff0…

接口测试实战--自动化测试流程

一、项目前期准备 常见项目软件架构: springMvc:tomcat里运行war包(在webapps目录下) springboot:java -jar xx.jar -xms(**) 运行参数 springCloud:k8s部署,使用kubectl create -f xx.yaml 接口自动化测试介入需越早越好,只要api定义好就可以编写自动化脚本; 某个…

域名系统与IP地址分配

域名 域名的概述 域名是一个逻辑的概念&#xff0c;它不反映主机的物理地点 域名结构 由于数字形式的IP地址难以记忆和理解&#xff0c;为此人们采用英文符号来表示IP地址&#xff0c;这就产生了域名&#xff0c;域名长度不超过255各字符&#xff0c;每一层域名长度不超过6…

C语言中的函数设计与调用优化

大家好&#xff0c;今天给大家介绍C语言中的函数设计与调用优化&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 一、引言 在C语言中&#xff0c;函数是代码组织的基本单元&…

常用状态码

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

OD(11)之Mermaid时间线图(Timeline diagram)使用详解

OD(11)之Mermaid时间线图(Timeline diagram)使用详解 Author: Once Day Date: 2024年2月25日 漫漫长路才刚刚开始… 全系列文章可参考专栏: Mermiad使用指南_Once_day的博客-CSDN博客 参考文章: 关于 Mermaid | Mermaid 中文网 (nodejs.cn)Mermaid | Diagramming and char…

YOLO如何训练自己的模型

目录 步骤 一、打标签 二、数据集 三、跑train代码出模型 四、跑detect代码出结果 五、详细操作 步骤 一、打标签 &#xff08;1&#xff09;在终端 pip install labelimg &#xff08;2&#xff09;在终端输入labelimg打开 如何打标签&#xff1a; 推荐文章&#xf…

(每日持续更新)jdk api之ObjectOutputStream基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

vue2和vue3对比(语法层面)

阅读文章你将收获&#xff1a; 1 了解不使用组件化工具时&#xff0c;vue在html是如何使用的 2 知道vue2的生命周期函数有哪些 3 知道如何在组件化开发中使用vue 4 大致了解了vue2和vue3在使用上什么不同 最后&#xff1a;vue2和vue3除了下面我列出的有差异化的地方&…

Langchain-Chatchat部署总结

项目地址&#xff1a; https://github.com/chatchat-space/Langchain-Chatchat 整体安装比较方便&#xff0c;在阿里云购买云主机&#xff0c;购买的国外站点机器&#xff0c; 该项目运行最佳坏境为 Linux Ubuntu 22.04.5Python 版本 3.11.7CUDA 版本: 12.1torch2.1.2 使…

SpringBoot Admin 详解

SpringBoot Admin 详解 一、Actuator 详解1.Actuator原生端点1.1 监控检查端点&#xff1a;health1.2 应用信息端点&#xff1a;info1.3 http调用记录端点&#xff1a;httptrace1.4 堆栈信息端点&#xff1a;heapdump1.5 线程信息端点&#xff1a;threaddump1.6 获取全量Bean的…

找游戏 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 小扇和小船今天又玩起来了数字游戏&#xff0c; 小船给小扇一个正整数 n&#xff08;1 ≤ n ≤ 1e9&#xff09;&#xff0c;小扇需要找到一个比 n 大的数字 m&a…

PMP项目管理考试要注意些什么?

PMP考试和PMP备考过程中应该注意哪些问题&#xff1f; PMP备考完成后就要迎接实战考试了&#xff0c;考试前千万不要有多余的想法&#xff0c;顺其自然就行了&#xff0c;我想大家各种紧张、各种忧虑的原因大抵是因为考试成本考&#xff0c;担心考不过&#xff0c;其实只要你在…

【并发】CAS原子操作

1. 定义 CAS是Compare And Swap的缩写&#xff0c;直译就是比较并交换。CAS是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令&#xff0c;这个指令会对内存中的共享数据做原子的读写操作。其作用是让CPU比较内存中某个值是否和预期的值相同&#xff0c;如果相…

Linux——缓冲区封装系统文件操作

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、FILE二、封装系统接口实现文件操作1、text.c2、mystdio.c3、mystdio.h 一、FILE 因为IO相…

基于粒子群算法优化BP神经网络的黄酮含量预测,基于pso-bp的黄酮水平预测,基于bp神经网络的黄酮预测

目录 摘要 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数, BP神经网络的传递函数 粒子群算法的原理及步骤 基于粒子群算法优化BP神经网络的黄酮含量预测,基于pso-bp的黄酮水平预测,基于bp神经网络的黄酮预测 matlab代码…

【线程池项目(三)】线程池CACHED模式的实现

在上一篇【线程池项目&#xff08;二&#xff09;】线程池FIXED模式的实现 中我们了解到到线程池fixed模式的大致实现原理&#xff0c;但对于一个比较完整的项目来说&#xff0c;我们还需要考虑到可能会发生的各种情况&#xff0c;比如用户提交的任务数可能在某一时刻急剧增加&…