驱动 day10 作业

news2024/11/26 11:39:44

要求:platform驱动实现
在这里插入图片描述
现象:
在这里插入图片描述
test.c应用程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
int main(int argc, char const *argv[])
{
	int fd;
	char buf[10]={0};		
	fd = open("/dev/myplatform",O_RDWR);
	if(fd < 0)
	{
		printf("打开设备文件失败\n");
		exit(-1);
	}  
	while(1)
	{
		memset(buf,0,sizeof(buf));
		read(fd,buf,sizeof(buf));
		printf("buf[0]=%d\n",buf[0]);
	}  
	close(fd);
	return 0;
}

job.c驱动程序

#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/io.h>
#include<linux/of.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/uaccess.h>
#include<linux/mod_devicetable.h>
#include<linux/platform_device.h>

struct cdev *cdev;//字符设备驱动对象空间首地址
unsigned int major=200;//主设备号
unsigned int minor=0;//次设备号的起始值
dev_t devno;//设备号变量
char kbuf[128]={0};
struct class *cls;//存放向上提交目录的返回值
struct device *dev;//存放向上提交设备节点信息结构体
struct device_node *dnode;//设备数节点信息结构体
struct gpio_desc *gpiono;//GPIO信息结构体
char number = 0;
unsigned int irqno;//获取中断号
wait_queue_head_t wq_head;//定义一个等待队列头
unsigned int condition=0;
struct resource *res;//存放设备信息的数组首地址
unsigned int irqno;//软中断号
/*myplatform{
        compatible = "hqyj,myplatform";
        reg=<0X12345678 0X400>;
        interrupt-parent=<&gpiof>;
        interrupts=<9 0>;   //9表示引用中断父节点时的索引信息  0表示默认设置
        led1=<&gpioe 10 0>;
};*/
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)
{
	//size参数是用户期待读到的字节长度
    int ret;
    //把内核的数据再拷贝给进程
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
	kbuf[0] = 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("数据从内核向用户拷贝失败\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	condition = 0;
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{   
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    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 =
{
    .read = mycdev_read,
	.open = mycdev_open,
	.write = mycdev_write,
	.release = mycdev_close,
};

//中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{
    printk("key1 interrupt\n");
	number = !number;
	condition = 1;
	gpiod_set_value(gpiono,!gpiod_get_value(gpiono));
	wake_up_interruptible(&wq_head);
    return IRQ_HANDLED; 
}
//probe函数,匹配设备成功执行
int pdrv_probe(struct platform_device *pdev)
{
	int ret;
	//初始化等待队列头
	init_waitqueue_head(&wq_head);
    //1.分配字符设备驱动对象空间  cdev_alloc
    cdev = cdev_alloc();
    if (!cdev) {
        printk(KERN_ALERT "cdev_alloc failed\n");
        return -ENOMEM;
    }
    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),1,"myplatform");
        if(ret)
        {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    }
    else//动态申请设备号
    {
        ret=alloc_chrdev_region(&devno,minor,1,"myplatform");
        if(ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major=MAJOR(devno);//根据设备号得到主设备号
        minor=MINOR(devno);//根据设备号得到次设备号
    }
    printk("申请设备号成功\n");
    //4.注册字符设备驱动对象  cdev_add()
    ret=cdev_add(cdev,MKDEV(major,minor),1);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    //5.向上提交目录
    cls=class_create(THIS_MODULE,"myplatform");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret=-PTR_ERR(cls);
		goto out4;
	}
	printk("向上提交目录成功\n");
	//6.向上提交设备节点
	dev=device_create(cls,NULL,MKDEV(major,minor),NULL,"myplatform");
	if(IS_ERR(dev))
	{
		printk("向上提交节点信息失败\n");
		ret=-PTR_ERR(dev);
		goto out5;
	}
	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);
	//pdev->dev.of_node  设备树匹配之后会把设备树节点结构体首地址赋值给dev的of_node成员
    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_handler,IRQF_TRIGGER_FALLING,"myplatform",NULL);
    if(ret)
    {
        printk("注册驱动失败\n");
        return ret;
    }
    printk("中断注册成功\n");
	return 0;
out5:
	//销毁上面提交的设备信息
	device_destroy(cls,MKDEV(major,minor));
	class_destroy(cls);
out4:
	cdev_del(cdev);
out3:
    unregister_chrdev_region(MKDEV(major,minor),1);
out2:
    kfree(cdev);
out1:
    return ret;
}
//remove 设备和驱动分离时执行
int pdrv_remove(struct platform_device *pdev)
{
 	//注销中断
    free_irq(irqno,NULL);
	//灭灯,注销gpio信息
	gpiod_set_value(gpiono,0);
	gpiod_put(gpiono);

	//1.销毁设备信息  device_destroy
	device_destroy(cls,MKDEV(major,minor));
	//2.销毁目录  class_destroy
    class_destroy(cls);
    //3.注销对象  cdev_del()
    cdev_del(cdev);
    //4.释放设备号   unregister_chrdev_region()
    unregister_chrdev_region(MKDEV(major,minor),1);
    //5.释放对象空间  kfree()
    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="11111",
		.of_match_table=oftable,
	},
};

module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

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

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

相关文章

Edge浏览器和Google浏览器占用内存情况

最近发现适用edge浏览器看视频时&#xff0c;或者打开多个网页&#xff0c;电脑就会变得非常卡顿&#xff0c;打开任务管理器发现内存占用较多&#xff0c;网上也有人说edge浏览器确实占用内存较多。但是给出的解决方案是更新windows系统&#xff0c;这个方法显然不能接受&…

Modbus tcp转ETHERCAT网关modbus tcp功能码

远创智控YC-ECT-TCP网关能够连接到Modbus tcp总线和ETHERCAT总线中&#xff0c;实现两种不同协议设备之间的通讯。这个网关能够大大提高工业生产的效率和生产效益&#xff0c;让生产变得更加智能化。远创智控YC-ECT-TCP 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主…

渗透专题丨Vulnhub-Tr0ll2靶机打靶

确认目标机IP&#xff1a;192.168.38.140 进行端口扫描&#xff1a; 查看一下版本&#xff1a; 没有查到关键信息&#xff0c;以80端口作为突破&#xff1a; 拿到提示信息&#xff1a; 接下来尝试ftp登录&#xff0c;根据提示信息&#xff1a; 登录之后&#xff0c;拿到lmao.z…

线性电源,开关电源

稳压器是如何工作的&#xff1f; 稳压器是这样一种电路&#xff1a;无论输入电压或负载条件如何变化&#xff0c;它都能产生并保持固定的输出电压。 稳压器&#xff08;VR&#xff09;将来自电源的电压保持在其他电气组件相容的范围之内。它最常用于DC / DC电源转换&#xff…

基于亚博K210开发板——串口中断以及开启双核任务

文章目录 开发板实验目的实验准备硬件原理图软件对应SDK对应的头文件 uart.huart.h接口函数高速通用异步收发传输器(UARTHS)对应的头文件 uarths.huarths.h接口函数板级对应的头文件 bsp.hbsp.h接口函数 实验代码实验结果效果 开发板 亚博K210开发板 实验目的 本实验配置串…

vue3中的excel表导出功能(选中导出或导出所有,也可支持vue2)

1.安装模块 npm install xlsx file-saver -S 2.文件导入 import * as XLSX from "xlsx"; import FileSaver from "file-saver" 3.整体代码(可选中导出或导出所有) <template><div><el-button type"warning" click"down&quo…

apt-get install命令

在Linux系统中&#xff0c;apt-get命令默认安装包的位置是在/usr目录下。具体来说&#xff0c;安装的可执行文件会存储在/usr/bin目录下&#xff0c;而库文件会存储在/usr/lib目录下。同时&#xff0c;相应的配置文件和文档等也会存储在/usr/share目录下。 举例&#xff0c;ap…

【计算机系统概论Yale.patt】第三章

文章目录 3.数字逻辑3.1 MOS管3.1.1 p型MOS晶体管3.1.2 n型MOS晶体管 3.2 逻辑门3.2.1 非门——反相器3.2.2 或非门、或门或非门或门 3.2.3 与非门、与门3.2.4 逻辑门符号表示逻辑门的数电表达式摩根定律 3.3 逻辑结构3.3.1 组合逻辑译码器多路复用器全加器可编程逻辑阵列 3.3.…

20230713-------通过platform实现阻塞IO来驱动按键控制LED灯的亮灭

需添加的设备树节点 myplatform{ compatible "hqyj,myplatform"; reg<0X12345678 0X400>; interrupt-parent<&gpiof>; interrupts<9 0>; //9表示引用中断父节点时的索引信息 0表示默认设置 led1<&gpioe 10 0>;pdev.c #include …

linux 安装pytorch3d的坑

事实上&#xff0c;只要按照官方文档的说明就可以完美安装。其中坑的地方在于conda的管理可能会导致下载的版本不符合你的要求&#xff08;例如下载成了cpu版本、下载的cuda版本&#xff09;而同样尝试使用源码编译以及其他方式下载库都会导致同样的问题&#xff0c;这里主要的…

【动手学深度学习】层和块

层和块 简单介绍 块&#xff1a;描述单个层&#xff0c;由多个层组成的组件或整个模型本身。使用块进行抽象的一个好处是可以将一些块组合成更大的组件&#xff0c;这一过程通常是递归的 简单入门 import torch from torch import nn from torch.nn import functional as F# …

【分布式系统案例课】计数服务之需求收集和总架构设计

面试题 对B站视频观看量进行实时的计数 技术问题是一个比较普遍的问题&#xff0c;比如对头条作者的粉丝或者是对获赞进行计数。或者是对企业的业务指标进行计数&#xff0c;例如注册登录下单数这些等。 需求澄清 问题一&#xff1a;用户点击观察视频之后&#xff0c;这个数量…

Gateway网关组件(在Spring Cloud整合Gateway(idea19版本))

Spring Cloud Gateway官网:Spring Cloud Gateway 局域网中就有网关这个概念&#xff0c;局域网接收数据或发送数据都要通过网关&#xff0c;比如使用VMware虚拟机软件搭建虚拟机集群的时候&#xff0c;往往我们需要选择IP段中的⼀个IP作为网关地址,网关可以对请求进行控制,提升…

Shell第三章——循环语句与函数

循环&#xff1a;重复执行一段代码的结构&#xff0c;通过循环可以在满足一定的条件之下多次执行相同的代码。 循环语句&#xff1a;包换循环体&#xff0c;代码的总结构&#xff0c;循环条件&#xff0c;当循环条件满足时&#xff0c;循环体的代码才会执行&#xff0c;条件不…

RabbitMQ-同步和异步通讯、安装和入门案例、SpringAMQP(5个消息发送接收Demo,jackson消息转换器)

文章目录 1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯 1.2.技术对比&#xff1a; 2.快速入门2.1.安装RabbitMQ2.2.RabbitMQ消息模型2.3.导入Demo工程2.4.入门案例2.4.1.publisher实现2.4.2.consumer实现 2.5.总结 3.SpringAMQP3.1.Basic Queue 简单队列模型3.1.1.…

【设计模式】23种设计模式——工厂模式(原理讲解+应用场景介绍+案例介绍+Java代码实现)

工厂模式 需求了解 看一个披萨的项目&#xff1a;要便于披萨种类的扩展&#xff0c;要便于维护 披萨的种类很多(比如 GreekPizz、CheesePizz 等)披萨的制作有 prepare&#xff08;准备材料&#xff09;,bake&#xff08;烘焙&#xff09;,cut&#xff08;切割&#xff09;,b…

Hive SQL 迁移 Flink SQL 在快手的实践

摘要&#xff1a;本文整理自快手数据架构工程师张芒&#xff0c;阿里云工程师刘大龙&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为四个部分&#xff1a; Flink 流批一体引擎 Flink Batch 生产实践 核心优化解读 未来规划 点击查看原文视频…

切换.net Framework 版本后,出现NuGet 包是使用不同于当前目标框架的目标框架安装的,可能需要重新安装

问题现象&#xff1a; 由于添加新的dll文件&#xff0c;依赖的.NET Framework版本与当前的不一致&#xff0c;在vs 中切换了目标框架版本后&#xff0c;运行程序&#xff0c;出现以下的warnning信息&#xff1a; 一些 NuGet 包是使用不同于当前目标框架的目标框架安装的&#…

springboot社区疫情防控平台

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven…

剑指offer68-I.二叉搜索树的最近公共祖先

把p的所有祖先找出来&#xff0c;把q的所有祖先找出来&#xff0c;因为是是搜索树&#xff0c;找出来的祖先都是排好序的&#xff0c;所以可以把找出来的祖先从后面往前面遍历&#xff0c;第一个相同的值的数就是最近的公共祖先&#xff0c;这是我一开始的想法,但是它最后报错了…