驱动day5

news2024/10/7 6:50:22

 驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/of.h>
#include<linux/of_irq.h>
#include<linux/interrupt.h>
#include<linux/of_gpio.h>
#include<linux/gpio.h>
struct cdev *cdev;
struct gpio_desc *gpiono1;
unsigned int major=500;
unsigned int minor=0;//次设备号的起始值
dev_t devno;
struct class *cls;
struct device *dev;
char kbuf[128]={0};
static int number=0;
unsigned int irqno;
struct device_node *dnodel;
//定义等待队列头
wait_queue_head_t wq_head;
unsigned int condition=0;
//中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{   
 
    number=!number;
    printk("key1 interrupt\n");
    gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1)); 
    condition=1;//表示硬件数据就绪
    wake_up_interruptible(&wq_head);//唤醒休眠的进程
    return IRQ_HANDLED;
}
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;
    if(sizeof(number)<size)
        size=sizeof(number);
    wait_event_interruptible(wq_head,condition);//将进程切换为休眠
    
    ret=copy_to_user(ubuf,&number,size);
    if(ret)
    {
        printk("copy_to_user filed\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    condition=0;//表示下一次硬件数据没有准备好
    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,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    int ret,i;
    //初始化等待队列头
    init_waitqueue_head(&wq_head);
    //1.分配字符设备驱动对象空间  cdev_alloc
    cdev=cdev_alloc();
    if(cdev==NULL)
    {
        printk("申请字符设备驱动对象空间失败\n");
        ret=-EFAULT;
        goto out1;
    }
    printk("字符设备驱动对象申请成功\n");
    //2.字符设备驱动对象部分初始化  cdev_init
    cdev_init(cdev,&fops);
    //3.申请设备号  register_chrdev_region/alloc_chrdev_region
    if(major>0)//静态申请设备号
    {
        ret=register_chrdev_region(MKDEV(major,minor),3,"myled");
        if(ret)
        {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    }
    else//动态申请设备号
    {
        ret=alloc_chrdev_region(&devno,minor,3,"myled");
         if(ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major=MAJOR(devno);//根据设备号得到主设备号
        minor=MINOR(devno);//根据设备号得到次设备号
    }
    printk("申请设备号成功\n");
    //4.注册字符设备驱动对象  cdev_add()
    ret=cdev_add(cdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    //5.向上提交目录
    cls=class_create(THIS_MODULE,"myled");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret=-PTR_ERR(cls);
        goto out4;
    }
    printk("向上提交目录成功\n");
    //6.向上提交设备节点
    for(i=0;i<3;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交节点信息失败\n");
            ret=-PTR_ERR(dev);
            goto out5;
        }
    }
    printk("向上提交设备节点信息成功\n");
    //解析led灯key的设备树节点
    dnodel=of_find_node_by_path("/mylandks");
    if(dnodel==NULL)
    {
    printk("解析设备树节点失败\n");
    return -ENXIO;
    }
    printk("解析设备树节点成功\n");
    //根据设备树节点解析led1 gpio结构体并向内核注册
    gpiono1=gpiod_get_from_of_node(dnodel,"led1",0,GPIOD_OUT_LOW,NULL); 
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio失败\n");
        return -PTR_ERR(gpiono1);
    }  
    //获取软中断号
    irqno=irq_of_parse_and_map(dnodel,0);
    if(!irqno)
    {
        printk("软中断号获取失败\n");
        return -ENOMEM;
    }
    printk("软中断号获取成功irqno=%d\n",irqno);
    //注册中断
    ret=request_irq(irqno,myirq_handler,IRQF_TRIGGER_FALLING,"key1",NULL);
    if(ret)
    {
        printk("注册驱动失败\n");
        return ret;
    }
    printk("key1中断注册成功\n");
    return 0;
out5:
    for(--i;i>=0;i--)
    {
        //销毁上面提交的设备信息
        device_destroy(cls,MKDEV(major,i));
    }
    class_destroy(cls);
out4:
    cdev_del(cdev);
out3:
    unregister_chrdev_region(MKDEV(major,minor),3);
out2:
    kfree(cdev);
out1:
    return ret;
}
static void __exit mycdev_exit(void)
{
    //1.销毁设备信息  device_destroy
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2.销毁目录  class_destroy
    class_destroy(cls);
    //3.注销对象  cdev_del()
    cdev_del(cdev);
    //4.释放设备号   unregister_chrdev_region()
    unregister_chrdev_region(MKDEV(major,minor),3);
    //5.释放对象空间  kfree()
    kfree(cdev);
    //注销中断
    free_irq(irqno,NULL);
    //释放gpio编号
    gpiod_put(gpiono1);

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

测试程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
unsigned int number;
int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int fd = open("/dev/myled0", 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;
}

实验现象

 

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

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

相关文章

11.4.2:DotImage SDK 基于web的扫描功能 cRACK

包含&#xff1a; DDotImage Document ImagingPDF Reader w/ Text ExtractionWingScan with eVRSOffice ReaderDotPDFBarcode Reading and WritingOCR Engines DotImage SDK WingScan 亮点&#xff0c;&#xff0c;WEB WingScan附带了一个简单的HTML5/JavaScript文档查看器…

Postgresql优化器如何使用列统计信息?

对pg_statistic表的查询都是走syscache的&#xff0c;要找到所有使用列统计信息地方&#xff0c;遍历系统表索引即可 enum SysCacheIdentifier {...STATEXTDATASTXOID,STATEXTNAMENSP,STATEXTOID,STATRELATTINH,... }下面是最常用的STATRELATTINH索引场景&#xff0c;即 Sear…

小奇猫物语之产品经理篇(2)

小奇猫物语之产品经理篇&#xff08;2&#xff09; 喵喵提示&#xff1a;小奇的产品经理篇&#xff08;2&#xff09;来咯&#xff0c;预告一下&#xff0c;前面几篇主要是讲产品经理的思维模式以及怎样去从一个学生思维转变成一个能带领一个项目的产品经理思维&#xff0c;所…

DolphinDB 与通联数据达成合作,构建快捷高效的一站式行情数据服务

在此前发布的多篇教程中&#xff0c;我们为大家展示了 DolphinDB 如何为因子投研、实时计算等业务场景加速&#xff0c;并进行了手把手教学&#xff0c;比如&#xff1a; 对接极速行情&#xff0c;真的很简单…… 又比如&#xff1a; 自己动手&#xff0c;搭一套行情回放系统…

Vue 路由跳转

文章目录 前言路由基础子路由路由传参query 传参 path静态传参动态传参 params 传参 name 编程式路由利用JS实现路由跳转 router 路由守卫 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; views里面放的是视图子组件&#xff08;首页、商家列表、商品列…

MySQL(九):MySQL语法-高级

MySQL语法-高级 LIMITLIKEASCREATE UNIQUE INDEX、DROP INDEXCREATE VIEW、DROP VIEWGROUP BYHAVINGMYSQL - JOININNER JOIN、JOINLEFT JOIN、LEFT OUTER JOINRIGHT JOIN、RIGHT OUTER JOINLEFT JOIN ... WHERE ...RIIGHT JOIN ... WHERE ... TRUNCATE TABLEINSERT INTO 表1 (列…

信创电子档案管理单机版系统之档案利用的功能介绍

专久智能信创电子档案管理单机版系统的档案利用&#xff0c;包括对电子档案的网上利用和对档案实体的借阅两种方式&#xff0c;用户对档案的利用都是通过 WEB 方式的档案网站实现的。 用户可以根据系统赋予的权限对电子档案目录进行检索查询&#xff0c;找到所需的档案目录&…

图像分类——图像增强方法

目录 常用的图像增强方法tf.image进行图像增强翻转和裁剪颜色变换 使用ImageDataGenerator(进行图像增强) 常用的图像增强方法 tf.image进行图像增强 离线实现 import tensorflow as tf import matplotlib.pyplot as plt import numpy as npcatplt.imread(./cat.jpg) plt.ims…

【后端面经-架构】RabbitMQ简介

【后端面经-架构】RabbitMQ简介 1. MQ介绍2. RabbitMQ2.1 简介2.2 架构&#xff1a;组件解释2.3 特点2.4 优缺点 面试模拟参考资料 1. MQ介绍 MQ&#xff08;Message Queue&#xff09;用于在应用程序之间相互通信&#xff0c;在消息中发送数据进行通信&#xff0c;而不需要特…

数据结构(王卓版)——算法分析

一个好算法如何衡量&#xff1a; 分析算法时间复杂度的方法&#xff1a; 复杂算法的计算规则&#xff1a; 空间复杂度

【深度学习】基于BRET的高级主题检测

一、说明 使用BERT&#xff0c;UMAP和HDBSCAN捕获文档主题&#xff0c;紧随最先进的BERTopic架构&#xff08;transformer编码器&#xff09;。 主题检测是一项 NLP 任务&#xff0c;旨在从文本文档语料库中提取全局“主题”。例如&#xff0c;如果正在查看书籍描述的数据集&am…

fatal: unable to access ‘http://xxxx‘: Empty reply from server

当你遇到 “fatal: unable to access ‘http://xxxx’: Empty reply from server” 的错误信息时&#xff0c;通常表示 Git 客户端无法连接到指定的服务器或仓库。 以下是一些可能导致该错误的原因以及一些排除故障的步骤&#xff1a; 错误的 URL&#xff1a;确保你提供的 URL…

linux 服务器之间传输文件的方式

情景&#xff1a;有时迁移项目&#xff0c;一般人就想到需要在服务器下载到win本地电脑上面&#xff0c;再上传到目的服务器&#xff0c;这样若是文件大&#xff0c;下载的速度都足够让你歇一天了。遇到这问题&#xff0c;怎么解决呢&#xff1f; 方法1&#xff1a;scp 【优点…

数据结构---手撕图解双向循环链表

文章目录 写在前面双向循环链表的构造布局带有哨兵位的布局 链表的构建链表的销毁链表的输出链表的尾插链表的尾删链表的头插链表的头删链表的查找链表的插入链表的删除 写在前面 在前面学完单链表后&#xff0c;我们思考这样一个问题&#xff0c;单链表和顺序表比起来&#x…

RK3588平台开发系列讲解(Camera篇)V4L2 视频采集步骤

文章目录 一、V4L2 视频采集步骤1.1、查询设备能力1.2、设置采集参数1.3、请求帧缓冲1.4、映射帧缓冲1.5、启动视频采集1.6、停止视频采集沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解V4L2 视频采集步骤。 一、V4L2 视频采集步骤 V4L2 视频采集的常用…

28. 在O(1)时间删除链表结点

链接&#xff1a; 链接 题目&#xff1a; 给定单向链表的一个节点指针&#xff0c;定义一个函数在O(1)时间删除该结点。 假设链表一定存在&#xff0c;并且该节点一定不是尾节点。 数据范围 链表长度 [1,500][1,500]。 样例 输入&#xff1a;链表 1->4->6->8删掉节点&…

指针和数组笔试题解析(最详细解析,没有之一)

指针和数组笔试题解析&#xff08;最详细解析&#xff0c;没有之一&#xff09; 前言1. 一维数组和指针相关笔试题2. 字符数组和指针相关笔试题2.1 题型一&#xff1a;2.2 题型二&#xff1a;2.3 题型三&#xff1a;2.4 题型四&#xff1a; 3. 指针和字符串相关面试题3.1 题型一…

华为云CodeArts Check代码检查插件3大版本使用指南

华为云CodeArts Check是自主研发的代码检查服务。为用户提供代码风格、通用质量与网络安全风险等丰富的检查能力&#xff0c;提供全面质量报告、便捷的问题闭环处理帮助企业有效管控代码质量&#xff0c;助力企业成功。 本插件致力于守护开发人员代码质量&#xff0c;成为开发…

【低代码专题方案】使用iPaaS平台下发数据,快捷集成MDM类型系统

01 场景背景 伴随着企业信息化建设日趋完善化、体系化&#xff0c;使用的应用系统越来越多&#xff0c;业务发展中沉淀了大量数据。主数据作为数据治理中枢&#xff0c;保存大量标准数据库&#xff0c;如何把庞大的数据下发到各个业务系统成了很棘手的问题。 传统的数据下发方…

英国大学生用AI写论文拿到1等成绩!ChatGPT写论文教程+提示词分享

今年期末季与往年的一大不同就是有了“哆啦C梦”——ChatGPT。过于高效智能的它&#xff0c;上线初期就引起了学术界关于“学术不端”的热烈讨论… 目录 01.用AI写论文获1等成绩 02.如何用ChatGPT辅助学习/写作 01.迅速get知识点 02.辅助理解内容 03.辅助起草论文大纲 0…