驱动 - 20230829

news2025/1/12 3:03:38

练习

基于platform实现
在这里插入图片描述
在根节点下,增加设备树

	myplatform {
		compatible="hqyj,myplatform";
		interrupts-extended=<&gpiof 9 0>, <&gpiof 7 0>, <&gpiof 8 0>;
		led1-gpio=<&gpioe 10 0>;
		reg=<0x12345678 59>;
	};

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>

// 中断
struct device_node *dnode;
unsigned int key_irqno;
struct gpio_desc *gpiono;
// 字符设备驱动
int major;
// 自动创建设备节点
struct class *cls;
struct device *dev;

struct resource *res;

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

// 封装操作方法
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)
{
    int ret;
    char kbuf[128] = {0};
    sprintf(kbuf, "number = %d", number);
    if (file->f_flags & O_NONBLOCK)
    {
        // 非阻塞
        return -EINVAL;
    }
    else
    {
        // 阻塞
        ret = wait_event_interruptible(wq_head, condition);
        if (ret < 0)
        {
            printk("receive signal.... \n");
            return ret;
        }
    }
    // 拷贝数据到用户空间
    ret = copy_to_user(ubuf, kbuf, size);
    if (ret)
    {
        printk("copy_to_user err \n");
        return -EIO;
    }

    // condition清零
    condition = 0;
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    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,
    .release = mycdev_close,
};

irqreturn_t key_handler(int irq, void *dev)
{
    if (number == 0)
    {
        number = 1;
    }
    else
    {
        number = 0;
    }
    gpiod_set_value(gpiono, number);
    condition = 1;
    wake_up_interruptible(&wq_head);

    return IRQ_HANDLED;
}

// 封装probe函数和remove函数
int pdrv_probe(struct platform_device *pdev)
{
    printk("pdrv_probe --------------------------- \n");
    int ret;

    /**
     * 1. 注册设备驱动
     */
    major = register_chrdev(0, "mychrdev", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败 \n");
        return major;
    }
    printk("字符设备驱动注册成功\n");

    /**
     * 2. 自动创建设备节点
     */
    // 向上提交目录信息
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls))
    {
        printk("向上提交目录信息失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录信息成功\n");

    // 向上提交设备信息
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mycdev0");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点失败\n");
        return -PTR_ERR(cls);
    }

    // 3. 初始化等待队列头
    init_waitqueue_head(&wq_head);

    // 获取MEM类型的资源
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == NULL)
    {
        printk("获取MEM类型资源失败\n");
        return -ENXIO;
    }

    /**
     * 中断
     */
    // 获取软中断号
    key_irqno = platform_get_irq(pdev, 0);
    if (key_irqno < 0) {
        printk("获取软中断号失败 \n");
        return -ENXIO;
    }
    printk("获取软中断号成功 \n");

    // 注册中断
    ret = request_irq(key_irqno, key_handler, IRQF_TRIGGER_FALLING, "key1", NULL);
    if (ret < 0)
    {
        printk("注册中断失败\n");
        return -1;
    }
    printk("注册中断成功\n");

    /**
     * LED灯
     */
    // 获取gpio编号
    gpiono=gpiod_get_from_of_node(pdev->dev.of_node,"led1-gpio",0,GPIOD_OUT_HIGH,NULL);
    if(IS_ERR(gpiono))
    {
        printk("解析gpio信息失败\n");
        return -PTR_ERR(gpiono);
    }
    printk("解析gpio编号成功\n");

    return 0;
}
int pdrv_remove(struct platform_device *pdev)
{
    free_irq(key_irqno, NULL);
    gpiod_set_value(gpiono, 0);
    gpiod_put(gpiono);

    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, "mychrdev");
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 构建设备树匹配表
struct of_device_id oftable[] = {
    {
        .compatible="hqyj,myplatform",
    },
    {},
};

// 分配驱动信息对象并初始化
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <pthread.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/epoll.h>

int main(int argc, const char* argv[])
{
    int fd;
	char buf[128];

    if ((fd = open("/dev/mycdev0", O_RDWR)) == -1) {
        perror("open error");
        exit(EXIT_FAILURE);
    }

    while (1) {
		bzero(buf, sizeof(buf));
        read(fd, buf, sizeof(buf));
        printf("status = %s\n", buf);
    }
    close(fd);
    return 0;
}


效果展示
在这里插入图片描述

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

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

相关文章

windows环境下QuestaSim软件的使用

文章目录 前言一、QuestaSim使用方法1、编译vlog2、映射vmap3、仿真vism4、ifndef和define&#xff08;常用&#xff09;5、QuestaSim的仿真界面6、完整QuestaSim仿真——TCL脚本 前言 2023.8.29 一、QuestaSim使用方法 1、编译vlog vlog&#xff1a;questasim的编译命令 -s…

利用逻辑回归判断病人肺部是否发生病变

大家好&#xff0c;我是带我去滑雪&#xff01; 判断肺部是否发生病变可以及早发现疾病、指导治疗和监测疾病进展&#xff0c;以及预防和促进肺部健康&#xff0c;定期进行肺部评估和检查对于保护肺健康、预防疾病和提高生活质量至关重要。本期将利用相关医学临床数据结合逻辑回…

【科研论文配图绘制】task6直方图绘制

【科研论文配图绘制】task6直方图绘制 task6 主要掌握直方图的绘制技巧&#xff0c;了解直方图含义&#xff0c;清楚统计指标的添加方式 1.直方图 直方图是一种用于表示数据分布和离散情况的统计图形&#xff0c;它的外观和柱形图相近&#xff0c;但它所 表达的含义和柱形图…

Elasticsearch 面试题

Elasticsearch 面试题 1.为什么要使用 Elasticsearch? 系统中的数据&#xff0c;随着业务的发展&#xff0c;时间的推移&#xff0c;将会非常多&#xff0c;而业务中往往采用模糊查询进行数据的搜索&#xff0c;而模糊查询会导致查询引擎放弃索引&#xff0c;导致系统查询数…

python 半正矢公式计算两GPS坐标距离

如题&#xff0c;直接上代码吧&#xff0c;需要的拿走。 # haversine公式计算两经纬度点距离 import math import os from DebugInfo.DebugInfo import *_earthR: int 6371393class __距离类:__m: floatdef __init__(self,m: float 0):self.__m mpropertydef km(self) ->…

【第四阶段】kotlin语言的set集合

1.set集合定义&#xff0c;不允许重复元素打印 package Stage4fun main() {//set集合定义&#xff0c;不允许重复元素打印// val set : Set<String> setOf<String>("java","kotlin","c","java","c")val set s…

C语言_分支和循环语句(2)

文章目录 前言一、for 循环1.1语法1.2 for 语句的循环控制变量1.3 一些 for 循环的变种 二、do ... while()循环2.1 do 语句的语法2.2 do ... while 循环中的 break 和 continue2.3 练习1 **- 计算n的阶乘**2. - **在一个有序数组中查找具体的某个数字 n** 二分查找算法&#x…

BES A2DP音乐与HFP通话默认音量配置

我V hezkz17进数字音频系统研究开发交流答疑群(课题组) 1 2

浅谈 Android Binder 监控方案

在 Android 应用开发中&#xff0c;Binder 可以说是使用最为普遍的 IPC 机制了。我们考虑监控 Binder 这一 IPC 机制&#xff0c;一般是出于以下两个目的&#xff1a; 卡顿优化&#xff1a;IPC 流程完整链路较长&#xff0c;且依赖于其他进程&#xff0c;耗时不可控&#xff0…

linux开启端口

目录 1.查看防火墙状态 1.1 开启防火墙 1.2 再次查看防火墙状态 2.开启指定端口 3. 重启防火墙 4.重新加载防火墙 5.查看已经开启的端口 1.查看防火墙状态 firewall-cmd --state 如果返回的是 not running&#xff0c;那么需要先开启防火墙&#xff0c; 1.1 开启防火…

MATLAB中符号变量的使用方法解析

简介 MATLAB中常常使用符号变量&#xff0c;这里定义符号变量的函数是syms 使用方法如下 syms x y z 其中&#xff0c;x、y、z 是符号变量&#xff0c;可以是任意字母、数字或下划线组合而成的字符串。 举例1&#xff1a; 代码 以下是一个简单的例子&#xff0c;演示如何…

省级智慧农业大数据平台项目规划建设方案[195页Word]

导读&#xff1a;原文《省级智慧农业大数据平台项目规划建设方案[195页Word]》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 1 农业大数据平台项目概述 1.1 建设…

Ant Design组件动态嵌套表单制作

使用Ant Design组件我们需要使用Form.List对表单进行操作 1.首先将Form.List放入form组件中&#xff0c;并name命名&#xff0c; 2.设置一个命名为数组&#xff0c;添加编辑和删除事件 3.以刚刚设置的数组设置map循环&#xff0c;可以在循环的的括号可以设置对嵌套表单控制 4.…

周赛360(脑经急转弯、贪心、树上倍增)

文章目录 周赛360[2833. 距离原点最远的点](https://leetcode.cn/problems/furthest-point-from-origin/)脑经急转弯 [2834. 找出美丽数组的最小和](https://leetcode.cn/problems/find-the-minimum-possible-sum-of-a-beautiful-array/)贪心 [2835. 使子序列的和等于目标的最少…

【网络】多路转接——五种IO模型 | select

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 五种IO模型 | select &#x1f367;五种IO模型&#x1f367;select&#x1f9c1;认识接口&#x1f9c1…

爬虫逆向实战(二十七)--某某招标投标网站招标公告

一、数据接口分析 主页地址&#xff1a;某网站 1、抓包 通过抓包可以发现数据接口是page 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现&#xff0c;请求参数是一整个密文 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 通…

Linux(实操篇三)

Linux实操篇 Linux(实操篇三)1. 常用基本命令1.7 搜索查找类1.7.1 find查找文件或目录1.7.2 locate快速定位文件路径1.7.3 grep过滤查找及"|"管道符 1.8 压缩和解压类1.8.1 gzip/gunzip压缩1.8.2 zip/unzip压缩1.8.3 tar打包 1.9 磁盘查看和分区类1.9.1 du查看文件和…

小米面试题——不用加减乘除计算两数之和

前言 &#xff08;1&#xff09;刷B站看到一个面试题&#xff0c;不用加减乘除计算两数之和。 &#xff08;2&#xff09;当时我看到这个题目&#xff0c;第一反应就是感觉这是一个数电题目。不过需要采用C语言的方式编写出来。 &#xff08;3&#xff09;不过看到大佬的代码之…

【Python】PySpark 数据输入 ① ( RDD 简介 | RDD 中的数据存储与计算 | Python 容器数据转 RDD 对象 | 文件文件转 RDD 对象 )

文章目录 一、RDD 简介1、RDD 概念2、RDD 中的数据存储与计算 二、Python 容器数据转 RDD 对象1、RDD 转换2、转换 RDD 对象相关 API3、代码示例 - Python 容器转 RDD 对象 ( 列表 )4、代码示例 - Python 容器转 RDD 对象 ( 列表 / 元组 / 集合 / 字典 / 字符串 ) 三、文件文件…

C#基础知识点记录

目录 课程一、C#基础1.C#编译环境、基础语法2.Winform-后续未学完 课程二、Timothy C#底层讲解一、类成员0常量1字段2属性3索引器5方法5.1值参数&#xff08;创建副本&#xff0c;方法内对值的操作&#xff0c;不会影响原来变量的值&#xff09;5.2引用参数&#xff08;传的是地…