2023.08.01 驱动开发day8

驱动层

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#define LED_ON  _IO('l', 1)
#define LED_OFF _IO('l', 0)

struct class *cls;
struct device *dev;
struct device_node *dev_irq, *dev_led;
unsigned int major;
unsigned int irqno1, irqno2, irqno3;
struct gpio_desc *gpiono1, *gpiono2, *gpiono3;

//中断处理函数
irqreturn_t myirq_handler(int irq, void *dev)
{
    if(irq == irqno1) {
		gpiod_set_value(gpiono1, !gpiod_get_value(gpiono1));
	}
	else if(irq == irqno2) {
		gpiod_set_value(gpiono2, !gpiod_get_value(gpiono2));
	}
	else if(irq == irqno3) {
		gpiod_set_value(gpiono3, !gpiod_get_value(gpiono3));
	}
    return IRQ_HANDLED;
}

int mycdev_open(struct inode *inode, struct file *file)
{
    int a = inode->i_rdev;  //获取当前设备文件对应的设备号
    file->private_data = (void *)MINOR(a);  //将次设备号保存到当前文件的file结构中
    return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned int a = (unsigned int)file->private_data;
    switch(a)
    {
        case 0:
            switch(cmd)
            {
                case LED_ON:
                    gpiod_set_value(gpiono1, 1);
                    break;
                case LED_OFF:
                    gpiod_set_value(gpiono1, 0);
                    break;
            }
            break;   
        case 1:
            switch(cmd)
            {
                case LED_ON:
                    gpiod_set_value(gpiono2, 1);
                    break;
                case LED_OFF:
                    gpiod_set_value(gpiono2, 0);
                    break;
            }
            break; 
        case 2:
            switch(cmd)
            {
                case LED_ON:
                    gpiod_set_value(gpiono3, 1);
                    break;
                case LED_OFF:
                    gpiod_set_value(gpiono3, 0);
                    break;
            }
            break;                          
    }
    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .unlocked_ioctl = mycdev_ioctl,
};

static int __init mycdev_init(void)
{
    // 注册字符设备驱动
    major = register_chrdev(0, "mychrdev", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        return major;
    }
    printk("注册字符设备驱动成功major=%d\n", major);

    // 向上提交目录
    cls = class_create(THIS_MODULE, "myled");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录信息成功\n");
    
    // 向上提交设备节点信息
    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");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点成功\n");
	
	int ret;
    //解析设备树节点
    dev_irq = of_find_node_by_path("/myirq");
    if(dev_irq == NULL)
    {
        printk("解析irq设备树节点失败\n");
        return -EFAULT;
    }
	dev_led = of_find_node_by_path("/leds");
    if(dev_led == NULL)
	{
        printk("解析led设备树节点失败\n");
        return -EIO;
    }
    printk("解析设备树节点成功\n");

    // 申请gpio_desc对象并设置输出为低电平
    gpiono1 = gpiod_get_from_of_node(dev_led, "led1-gpios", 0, GPIOD_OUT_LOW, NULL);
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
	gpiono2 = gpiod_get_from_of_node(dev_led, "led2-gpios", 0, GPIOD_OUT_LOW, NULL);
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
	gpiono3 = gpiod_get_from_of_node(dev_led, "led3-gpios", 0, GPIOD_OUT_LOW, NULL);
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
    printk("申请gpio对象成功\n");

    //根据设备树节点解析出软中断号s
    irqno1 = irq_of_parse_and_map(dev_irq, 0); //按键1索引号为0
    if(!irqno1)
    {
        printk("解析软中断号失败\n");
        return -ENXIO;
    }
	irqno2 = irq_of_parse_and_map(dev_irq, 1);
    if(!irqno2)
    {
        printk("解析软中断号失败\n");
        return -ENXIO;
    }
	irqno3 = irq_of_parse_and_map(dev_irq, 2);
    if(!irqno3)
    {
        printk("解析软中断号失败\n");
        return -ENXIO;
    }
    printk("解析软中断号成功 irqno123=%d,%d,%d\n",irqno1,irqno2,irqno3);

    //注册中断
    ret = request_irq(irqno1, myirq_handler, IRQF_TRIGGER_FALLING, "key1", NULL);
    if(ret)
    {
        printk("注册中断失败\n");
        return ret;
    }
	ret = request_irq(irqno2, myirq_handler, IRQF_TRIGGER_FALLING, "key2", NULL);
    if(ret)
    {
        printk("注册中断失败\n");
        return ret;
    }
	ret = request_irq(irqno3, myirq_handler, IRQF_TRIGGER_FALLING, "key3", NULL);
    if(ret)
    {
        printk("注册中断失败\n");
        return ret;
    }
    printk("注册中断成功\n");
    return 0;
}

static void __exit mycdev_exit(void)
{
    //注销中断
    free_irq(irqno1, NULL);
	free_irq(irqno2, NULL);
	free_irq(irqno3, NULL);
	//灭灯
	gpiod_set_value(gpiono1, 0);
	gpiod_set_value(gpiono2, 0);
	gpiod_set_value(gpiono3, 0);
	//释放gpio编号
	gpiod_put(gpiono1);
	gpiod_put(gpiono2);
	gpiod_put(gpiono3);
	//销毁节点信息
	int i;
	for (i = 0; i < 3; i++)
	{
		device_destroy(cls, MKDEV(major, i));
	}
	//销毁目录信息
	class_destroy(cls);
	//注销字符设备驱动
	unregister_chrdev(major, "mycdev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

应用层 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define LED_ON  _IO('l', 1)
#define LED_OFF _IO('l', 0)

int main(int argc,const char * argv[])
{
    int sel;
    int fd1 = open("/dev/myled0", O_RDWR);
    if(fd1 < 0)
    {
        perror("open");
        printf("%s : %s : %d\n", __FILE__, __func__, __LINE__);
        return -1;
    }
    int fd2 = open("/dev/myled1", O_RDWR);
    if(fd2 < 0)
    {
        perror("open");
        printf("%s : %s : %d\n", __FILE__, __func__, __LINE__);
        return -1;
    }
    int fd3 = open("/dev/myled2", O_RDWR);
    if(fd3 < 0)
    {
        perror("open");
        printf("%s : %s : %d\n", __FILE__, __func__, __LINE__);
        return -1;
    }

    while(1)
    {
        printf("1> LED1 ON\n");
        printf("2> LED1 OFF\n");
        printf("3> LED2 ON\n");
        printf("4> LED2 OFF\n");
        printf("5> LED3 ON\n");
        printf("6> LED3 OFF\n");
        printf("请选择功能>>>");
        scanf("%d", &sel);
        getchar();
        switch(sel)
        {
            case 1:
                ioctl(fd1, LED_ON); 
                break;
            case 2:
                ioctl(fd1, LED_OFF);
                break;
            case 3:
                ioctl(fd2, LED_ON); 
                break;
            case 4:
                ioctl(fd2, LED_OFF);
                break;
            case 5:
                ioctl(fd3, LED_ON); 
                break;
            case 6:
                ioctl(fd3, LED_OFF);
                break;
        }
    }
    close(fd1);
    close(fd2);
    close(fd3);
    return 0;
}

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

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

相关文章

NVM保姆级安装配置

nvm安装配置 1、NVM简介2、NVM安装三、NVM使用四、NVM常用命令 1、NVM简介 在项目开发过程中&#xff0c;使用到vue框架技术&#xff0c;需要安装node下载项目依赖&#xff0c;但经常会遇到node版本不匹配而导致无法正常下载&#xff0c;重新安装node却又很麻烦。为解决以上问…

Docker 网络模型使用详解 (1)Dockers网络基础

目录 环境准备 Dockers 网络基础 1.端口映射 查看随机映射端口范围 -p可以指定映射到本地端口 映射指定地址和指定端口 映射指定地址 宿主机端口随机分配 指定传输协议 端口暴露 容器互联 自定义网络 现在把container7加入到demo_net中 在启动一个容器加入到demo_net…

Linux进程(二)

文章目录 进程&#xff08;二&#xff09;Linux的进程状态R &#xff08;running&#xff09;运行态S &#xff08;sleeping&#xff09;阻塞状态D &#xff08;disk sleep&#xff09;深度睡眠T&#xff08;stopped&#xff09;状态X&#xff08;dead&#xff09;状态Z&#x…

数据结构 二叉树(C语言实现)

绪论 雄关漫道真如铁&#xff0c;而今迈步从头越。 本章将开始学习二叉树&#xff08;全文共一万两千字&#xff09;&#xff0c;二叉树相较于前面的数据结构来说难度会有许多的攀升&#xff0c;但只要跟着本篇博客深入的学习也可以基本的掌握基础二叉树。 话不多说安全带系好&…

关于 Ubuntu 长按 shift 无效, 按 Esc 直接进入 grub 改密码的解决方法

本次长按shift没有反应&#xff0c;直接进入了系统界面&#xff0c;所以改用长按Esc键&#xff0c;步骤如下&#xff1a; 1. 长按esc&#xff0c;进入grub>提示 2.输入grub>normal &#xff0c;回车 3.上一步回车后&#xff0c;继续敲击Esc &#xff0c;出现grub界面 …

HCIP---OSPF的优化

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.汇总&#xff1a; 目的&#xff1a;减少骨干区域的LSA的更新量 作用&#xff1a;OSPF的…

可缝合神经网络

文章目录 Stitchable Neural Networks摘要本文方法实验结果 Stitchable Neural Networks 摘要 包含大量强大的预训练模型族(如ResNet/DeiT)的model zoo已经达到了前所未有的范围&#xff0c;这对深度学习的成功有重要贡献。由于每个模型族都由具有不同尺度的预训练模型(例如&…

Linux 匿名页的生命周期

目录 匿名页的生成 匿名页生成时的状态 do_anonymous_page缺页中断源码 从匿名页加入Inactive lru引出 一个非常重要内核patch 匿名页何时回收 本文以Linux5.9源码讲述 匿名页的生成 用户空间malloc/mmap(非映射文件时&#xff09;来分配内存&#xff0c;在内核空间发生…

Docker实战-关于Docker镜像的相关操作(二)

导语   之前的分享中&#xff0c;我们介绍了关于Docker镜像的查询操作相关的内容&#xff0c;下面我们继续来介绍删除清理、导入导出、创建镜像等操作。 如何删除和清理镜像&#xff1f; 使用标签删除镜像 可以使用docker rmi 或者是 docker image rm 命令来删除镜像&#x…

Spring源码之XML文件中Bean标签的解析1

读取XML文件&#xff0c;创建对象 xml文件里包含Bean的信息&#xff0c;为了避免多次IO&#xff0c;需要一次性读取xml文件中所有bean信息&#xff0c;加入到Spring工厂。 读取配置文件 new ClassPathResource("applicationContext.xml")ClassPathResource是Sprin…

微信小程序nodejs+vue+uniapp高校食堂线上预约点餐系统

本次设计任务是要设计一个食堂线上预约点餐系统&#xff0c;通过这个系统能够满足管理员及学生的食堂线上预约点餐分享功能。系统的主要包括首页、个人中心、学生管理、菜品分类管理、菜品管理、关于我们管理、意见反馈、系统管理、订单管理等功能。 开发语言 node.js 框架&am…

Flink之RedisSink

在Flink开发中经常会有将数据写入到redis的需求,但是Flink官方并没有对应的扩展包,这个时候需要我们自己编译对应的jar资源,这个时候就用到了bahir,barhir是apahce的开源项目,是专门给spark和flink提供扩展包使用的,bahir官网,这篇文章就介绍下如何自己编译RedisSink扩展包. 下…

Prometheus服务器、Prometheus被监控端、Grafana、Prometheus服务器、Prometheus被监控端、Grafana

day03 day03Prometheus概述部署Prometheus服务器环境说明&#xff1a;配置时间安装Prometheus服务器添加被监控端部署通用的监控exporterGrafana概述部署Grafana展示node1的监控信息监控MySQL数据库配置MySQL配置mysql exporter配置mysql exporter配置prometheus监控mysql自动…

spring security + oauth2 使用RedisTokenStore 以json格式存储

1.项目架构 2.自己对 TokenStore 的 redis实现 package com.enterprise.auth.config;import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis…

Spring Boot、Spring Cloud、Spring Alibaba 版本对照关系及稳定兼容版本

Spring Boot、Spring Cloud、Spring Alibaba 版本对照关系及稳定兼容版本 引言 在 Java 生态系统中&#xff0c;Spring Boot、Spring Cloud 和 Spring Alibaba 是非常流行的框架&#xff0c;它们提供了丰富的功能和优雅的解决方案。然而&#xff0c;随着不断的发展和更新&…

如何建立含有逻辑删除字段的唯一索引

业务场景 在实际工作当中&#xff0c;遇到一个场景&#xff0c;就是在用户注册时&#xff0c;名字要全局唯一&#xff0c;当然&#xff0c;我们是可以对用户进行删除的&#xff0c;你会怎么去做&#xff1f; 分析 一般来说&#xff0c;我们可以在用户注册请求时&#xff0c…

基于时空RBF神经网络的混沌时间序列预测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【阵列信号处理】空间匹配滤波器、锥形/非锥形最佳波束成形器、样本矩阵反演 (SMI) 研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

chrome扩展在popup、background、content之间通信解决传输文件问题

文章目录 背景介绍案例介绍代码示例popup页面&#xff0c;上传文件页面popup页面&#xff0c;js上传代码&#xff0c;file文件转base64background监听消息&#xff0c;base64转file文件&#xff0c;axios上传 附-转base64后直接下载 背景介绍 示例扩展API版本MV2。 以弹…

3d 地球与卫星绕地飞行

1 创建场景 2 创建相机 3 创建地球模型 4 创建卫星中心 5 创建卫星圆环及卫星 6 创建控制器 7 创建渲染器 <template><div class"home3dMap" id"home3dMap"></div> </template><script> import * as THREE from three impo…