驱动开发-day10

驱动代码:

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
struct cdev* cdev;
unsigned int major = 500;
unsigned int minor = 0;
dev_t devno;
struct class* cls;
struct device* dev;

struct resource* res;
unsigned int irqno;
struct gpio_desc* gpiono;

unsigned int number;
// 定义等待队列头
wait_queue_head_t wq_head;
unsigned int condition = 0;

ssize_t mycdev_read(struct file* file, char* ubuf, size_t size, loff_t* lof)
{
    int ret;
    // 将进程切换到休眠状态
    wait_event_interruptible(wq_head, condition);

    if (size > sizeof(number)) {
        size = sizeof(number);
    }

    ret = copy_to_user(ubuf, &number, size);
    if (ret) {
        printk("copy_to_user filed\n");
        return -EIO;
    }
    condition = 0; // 下次硬件的数据没有准备好
    return size;
}
irqreturn_t myirq_led_handler(int irqno, void* dev_id)
{

    gpiod_set_value(gpiono, !gpiod_get_value(gpiono));
    number = gpiod_get_value(gpiono);
    condition = 1; // 数据准备就绪
    // 唤醒休眠的进程
    wake_up_interruptible(&wq_head);

    return IRQ_HANDLED;
}

struct file_operations fops = {

    .read = mycdev_read,

};
int pdrv_probe(struct platform_device* pdev)
{

    int ret, i;
    // 初始化等待队列头
    init_waitqueue_head(&wq_head);
    // 分配字符设备驱动对象空间
    cdev = cdev_alloc();
    if (cdev == NULL) {
        printk("申请字符设备驱动空间失败\n");
        ret = -EFAULT;
        goto out1;
    }
    // 字符设备驱动对象部分初始化
    cdev_init(cdev, &fops);
    // 静态申请设备号
    if (major > 0) {

        ret = register_chrdev_region(MKDEV(major, minor), 3, "mykey");
        if (ret) {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    } else { // 动态申请设备号
        ret = alloc_chrdev_region(&devno, minor, 3, "mykey");
        if (ret) {
            printk("动态指定设备号失败\n");
            goto out2;
        }
        major = MAJOR(devno);
        minor = MINOR(devno);
    }
    // 注册字符设备驱动对象
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret) {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    // 向上提交目录
    cls = class_create(THIS_MODULE, "mykey");
    if (IS_ERR(cls)) {
        printk("向上提交目录失败\n");
        ret = -PTR_ERR(cls);
        goto out4;
    }
    printk("向上提交目录成功\n");
    // 向上提交设备节点

    for (i = 0; i < 3; i++) {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mykey%d", i);
        if (IS_ERR(dev)) {
            printk("向上提交节点信息失败\n");
            ret = -PTR_ERR(dev);
            goto out5;
        }
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // printk("向上提交设备节点信息成功\n");

    // 获取设备信息
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == NULL) {
        printk("获取资源失败\n");
        return -ENXIO;
    }
    printk("获取资源信息成功 %x\n", res->start);
    irqno = platform_get_irq(pdev, 0);
    if (irqno < 0) {
        printk("获取中断资源失败\n");
        return irqno;
    }
    printk("中断类型资源为%d\n", irqno);
    // 获取gpio信息
    gpiono = gpiod_get_from_of_node(pdev->dev.of_node, "led1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono)) {
        printk("解析GPIO信息失败\n");
        return -PTR_ERR(gpiono);
    }

    // 注册中断
    ret = request_irq(irqno, myirq_led_handler, IRQF_TRIGGER_FALLING, "key1", NULL);
    if (ret) {
        printk("注册失败\n");
        return ret;
    }
    return 0;
out5:

    // 销毁提交的设备信息
    device_destroy(cls, MKDEV(major, minor));

    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)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 灭灯
    gpiod_set_value(gpiono, 0);
    // 释放gpio信息
    free_irq(irqno, NULL);
    gpiod_put(gpiono);
    // 销毁设备信息
    int i;
    for (i = 0; i < 3; i++) {
        device_destroy(cls, MKDEV(major, i));
    }
    // 销毁目录
    class_destroy(cls);
    // 注销对象
    cdev_del(cdev);
    // 释放设备号
    unregister_chrdev_region(MKDEV(major, minor), 3);
    // 释放对象空间
    kfree(cdev);
    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 <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const* argv[])
{
    int fd;

    unsigned int number;
    // 打开LED
    fd = open("/dev/mykey0", 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;
}

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

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

相关文章

OpenCV 入门教程:轮廓特征和轮廓匹配

OpenCV 入门教程&#xff1a;轮廓特征和轮廓匹配 导语一、轮廓特征二、轮廓匹配三、示例应用3.1 目标识别3.2 形状分析 总结 导语 轮廓特征和轮廓匹配是图像处理中用于描述和比较轮廓的技术。通过提取轮廓的形状、面积、周长等特征&#xff0c;并进行比较和匹配&#xff0c;我…

Python+Requests+Excel接口测试实战

1、EXCEL文件接口保存方式&#xff0c;如图。 2、然后就是读取EXCEL文件中的数据方法&#xff0c;如下&#xff1a; 1 import xlrd2 3 4 class readExcel(object):5 def __init__(self, path):6 self.path path7 8 property9 def getSheet(self): 10 …

flutter开发实战-Running Gradle task ‘assembleDebug‘ 的解决方法

flutter开发实战-Running Gradle task ‘assembleDebug‘ 的解决方法 使用Android studio经常出现Running Gradle task ‘assembleDebug‘问题&#xff0c;记录一下解决方法。 一、在Android目录下更改build.gradle 将repositories中的google(), mavenCentral() repositori…

从钢铁行业数字化管控平台的智能进化,看超自动化能力边界

文/王吉伟 钢铁行业的数字化转型&#xff0c;历来都是值得探讨的热点话题。 2022年&#xff0c;我国粗钢产量10.13亿吨&#xff0c;占据了全球钢铁供给市场的半壁江山。 这组数据可谓非常抢眼&#xff0c;但仍旧难掩诸多企业的各种经营问题。 钢铁生产过程工序众多&#xf…

计算机网络-网络层上篇

目录 一、网络层概述 二、网络层提供的两种服务 &#xff08;一&#xff09;面向连接的虚电路服务 &#xff08;二&#xff09;无连接的数据报服务 &#xff08;三&#xff09;虚电路服务与数据报服务的比较 三、IPv4地址及其应用 &#xff08;一&#xff09;IPv4地址概…

python中的生成器(generator)

一、生成器 生成器是 Python 中非常有用的一种数据类型&#xff0c;它可以让你在 Python 中更加高效地处理大量数据。生成器可以让你一次生成一个值&#xff0c;而不是一次生成一个序列&#xff0c;这样可以节省内存并提高性能 二、实现generator的两种方式 python中的gener…

SuperMap iClient3D for Cesium最短路径分析

作者&#xff1a;Mei 目录 前言实现思路实现步骤1、构建二维网络数据集1.1拓扑检查1.2线拓扑数据集处理1.3构建二维网络数据集 2、发布网络分析服务3、实现代码 前言 在交通、消防业务场景中&#xff0c;如果某地发生火灾或者交通事故&#xff0c;需要快速规划出最短抢救路线&a…

flask计算pin码

目录 Flask计算pin码 <1> 概念 什么是pin码&#xff1f; pin码生成条件&#xff1f; 读取相关文件绕过过滤 <2> 源码分析 werkzeug 1.0.x版本 计算PIN的源码 werkzeug 2.0.x版本 计算PIN的源码 <3> 计算生成pin的脚本 CTF中 flask-pin的应用 <1…

volatile原理剖析和实例讲解

一、是什么 volatile是Java的一个关键字&#xff0c;是Java提供的一种轻量级的同步机制&#xff0c; 二、能做什么 保证了不同线程对这个变量进行操作时的可见性&#xff0c;有序性。 三、可见性 可见性主要是指一个线程修改了共享变量的值&#xff0c;另一个线程可以看见…

RPC 框架架构设计

RPC 框架架构设计 RPC 又称远程过程调用&#xff08;Remote Procedure Call&#xff09;&#xff0c;用于解决分布式系统中服务之间的调用问题。通俗地讲&#xff0c;就是开发者能够像调用本地方法一样调用远程的服务。下面我们通过一幅图来说说 RPC 框架的基本架构。 RPC 框架…

Python_与redis数据库交互

目录 redis模块的使用 连接方式 连接池 操作 设置值 获取值 管道 事务 源码等资料获取方法 python可以使用redis模块来跟redis交互 redis模块的使用 安装模块: pip3 install redis 导入模块&#xff1a;import redis 连接方式 严格连接模式&#xff1a;rredis.St…

40.RocketMQ之高频面试题大全

消息中间件如何选型 RabbitMQ erlang开发&#xff0c;对消息堆积的支持并不好&#xff0c;当大量消息积压的时候&#xff0c;会导致 RabbitMQ 的性能急剧下降。每秒钟可以处理几万到十几万条消息。 RocketMQ java开发&#xff0c;面向互联网集群化功能丰富&#xff0c;对在线业…

Win10安全中心怎么关闭?Win10安全中心关闭方法

Win10安全中心怎么关闭&#xff1f;关闭Win10的安全中心可以帮助用户自定义系统的安全和防护设置&#xff0c;但有些用户不知道怎么操作才能关闭安全中心&#xff0c;首先用户需要打开Win10电脑的设置选项&#xff0c;接着打开安全中心&#xff0c;然后关掉安全中心的实时保护、…

SQL力扣练习(六)

目录 1. 部门工资前三高的所有员工(185) 题解一(dense_rank()窗口函数&#xff09; 题解二&#xff08;自定义函数&#xff09; 2.删除重复的电子邮箱(196) 题解一 题解二&#xff08;官方解析&#xff09; 3.上升的温度(197) 解法一&#xff08;DATEDIFF()&#xff09;…

非主流币波段策略

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

探究Vue源码:mustache模板引擎(5) 对比rollup与webpack,在本地搭建webpack环境

好 从本文开始 我们就来手写一下mustache这个库 他是模板引擎的一个祖先 将模板字符串编译成一个dom字符串 就是它的思想&#xff0c;这也是一个具有跨时代意义的思想 这里的话 我们还是搭一个 webpack 的项目环境 这里值得一提的是 mustache 他官方是通过rollup来进行打包的 …

【Docker】Docker的部署含服务和应用、多租环境、Linux内核的详细介绍

前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 &#x1f4d5;作者简介&#xff1a;热…

速通matplotlib库

速通matplotlib库 前言 ​ 最近在复习之前学习过的知识点&#xff0c;因此想到把学过的总结一下&#xff0c;方便后面再次复习&#xff0c;所以有了这个系列。 说明 ​ 由于标题写的是“速通”&#xff0c;因此我的想法是可以让大家看完这篇文章&#xff0c;可以上手matplotlib…

爬虫正常用哪种代理比较好?

目录 爬虫使用哪种代理IP 爬虫使用代理IP时需要考虑什么 爬虫怎么使用代理IP 爬虫使用代理IP示例代码 爬虫使用哪种代理IP 在使用代理IP进行爬虫时&#xff0c;以下几种类型的代理被认为是比较好的选择&#xff1a; 1. 高匿名代理&#xff1a;高匿名代理隐藏了真实的IP地址…

简要介绍 | 边缘计算:原理,研究现状与未来展望

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对边缘计算进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 边缘计算&#xff1a;原理&#xff0c;研究现状与未来展望 What is Edge Computing? | Moving Intelligence to the Edge 一、背景介…