驱动 day9 作业

news2024/12/26 23:21:43

要求:
在这里插入图片描述
现象
在这里插入图片描述
按下key1 led1灯的状态取反,number的值取反,然后应用程序打印从内核读到的number的值

应用程序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/myled",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>
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;
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;
	//将进程切换为可中断的休眠状态
	wait_event_interruptible(wq_head,condition);

    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; 
}
static int __init mycdev_init(void)
{
	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,"myled");
        if(ret)
        {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    }
    else//动态申请设备号
    {
        ret=alloc_chrdev_region(&devno,minor,1,"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),1);
    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.向上提交设备节点
	dev=device_create(cls,NULL,MKDEV(major,minor),NULL,"myled");
	if(IS_ERR(dev))
	{
		printk("向上提交节点信息失败\n");
		ret=-PTR_ERR(dev);
		goto out5;
	}
	printk("向上提交设备节点信息成功\n");
	//解析led灯的设备树节点
	dnode=of_find_node_by_path("/myleds");
	if(dnode==NULL)
	{
		printk("解析设备树节点失败\n");
		return -ENXIO;
	}
	printk("解析设备树节点成功\n");
	//根据设备树节点解析led1 gpio结构体并向内核注册
	gpiono=gpiod_get_from_of_node(dnode,"led1",0,GPIOD_OUT_LOW,NULL); 
	if(IS_ERR(gpiono))
	{
		printk("申请gpio失败\n");
		return -PTR_ERR(gpiono);
	}
    //解析key设备树节点
    dnode=of_find_node_by_name(NULL,"mykeys");
    if(dnode==NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("设备树节点解析成功\n");
	//获取软中断号
    irqno=irq_of_parse_and_map(dnode,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:
	//销毁上面提交的设备信息
	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;
}
static void __exit mycdev_exit(void)
{
 	//注销中断
    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);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

Bash 有效电话号码

193 有效电话号码 给定一个包含电话号码列表&#xff08;一行一个电话号码&#xff09;的文本文件 file.txt&#xff0c;写一个单行 bash 脚本输出所有有效的电话号码。 你可以假设一个有效的电话号码必须满足以下两种格式&#xff1a; (xxx) xxx-xxxx 或 xxx-xxx-xxxx。&…

三维重建以及神经渲染中的学习(三)

三维重建以及神经渲染中的学习 公众号AI知识物语 本文内容为参加过去一次暑期课程学习时的笔记&#xff0c;浅浅记录下。 三维图形可控生成&#xff1a; 1&#xff1a;学习一个图形生成模型 2&#xff1a;具有可控三维变量&#xff1a;1物体形状&#xff1b;2物体位置&…

ScannerException: while scanning for the next token found character ‘@‘ 问题解决

问题描述 后端项目启动的时候报ScannerException: while scanning for the next token found character ‘‘ 异常&#xff0c;自己有些疑问&#xff0c;项目前一会都还可以&#xff0c;到报错的过程中&#xff0c;项目都没有动过。 解决办法 重新刷新项目就解决了。

RxSwift 使用方式

背景 最近项目业务&#xff0c;所有模块已经支持Swift混编开发&#xff0c;正在逐步使用Swift 方式进行开发新业务&#xff0c;以及逐步替换老业务方式进行发展&#xff0c;所以使用一些较为成熟的Swift 的三方库&#xff0c;成为必要性&#xff0c;经过调研发现RxSwift 在使用…

HarmonyOS/OpenHarmony应用开发-程序包多HAP机制(上)

一、多HAP机制设计目标 方便开发者模块化的管理应用&#xff0c;好的应用一般都是模块化管理&#xff0c;模块之间属于松耦合关系。多HAP方便了开发者将业务划分成多个模块&#xff0c;每个模块放到独立的HAP中。例如支付类应用&#xff0c;有统一的主界面&#xff0c;主界面管…

命令注入(Command Injection)安全漏洞(SQL注入、LDAP注入、OS命令注入、XPath注入、JavaScript注入)

文章目录 命令注入&#xff08;Command Injection&#xff09;发生场景示例防范手段其他类型命令注入漏洞1. SQL注入&#xff08;SQL Injection&#xff09;2. LDAP注入&#xff08;LDAP Injection&#xff09;3. OS命令注入&#xff08;OS Command Injection&#xff09;4. XP…

VectorCAST对外部函数打桩和查看覆盖率

一、对外部函数打桩 在单元测试中&#xff0c;如果要调用到外部函数调用的时候&#xff0c;就要对外部函数进行打桩。 对外部函数进行打桩的目的&#xff0c;一方面是为了验证外部函数接口的正确性&#xff0c;另一方面是对外部函数打桩 之后就可以自定义外部函数返回值。 对…

Unity5.4.1打砖块游戏Breakout_Game_Starter_Kit

Unity5.4.1打砖块游戏Breakout_Game_Starter_Kit 童年的回忆 项目地址&#xff1a;https://download.csdn.net/download/Highning0007/88042779

vue 使用 npm run dev命令后 自动打开浏览器为谷歌

文章目录 需求分析 需求 vue 启动后&#xff0c;想要其自动打开指定浏览器&#xff08;谷歌&#xff09;并设置要打开的IP地址和端口号 分析 package.json 打开package.json文件加上 --open chrome index.js 打开index.js文件&#xff0c;将浏览器设置为自动打开

【力扣刷题 | 第十七天】

目录 前言&#xff1a; 55. 跳跃游戏 - 力扣&#xff08;LeetCode&#xff09; 45. 跳跃游戏 II - 力扣&#xff08;LeetCode&#xff09; 总结&#xff1a; 前言&#xff1a; 今天两道类型都是贪心算法&#xff0c;希望可以有所收获 55. 跳跃游戏 - 力扣&#xff08;LeetC…

入门车载以太网

前言 近些年来,随着为了让汽车更加安全、智能、环保等,一系列的高级辅助驾驶功能喷涌而出。未来满足这些需求,就对传统的电子电器架构带来了严峻的考验,需要越来越多的电子部件参与信息交互,导致对网络传输速率,稳定性,负载率等方面都提出了更为严格的挑战。 除此以外…

哪些职位需要CISP证书?快进来看看你需不需要

CISP是目前中国最主流的信息行业的证书&#xff0c;也是业界公认的最专业的信息安全技术和管理资格培训。无论是政府部门、金融、电力、交通能源、IT等相关行业&#xff0c;都可以看到CISP证书的持有人。现在持证的人数日趋上升&#xff0c;成为一个必备证书。CISP知识体系是国…

【JavaEE】HTTP协议和抓包工具的使用

目录 1、HTTP的概述和抓包工具的使用 1.1、HTTP是什么 1.2、了解HTTP协议的工作过程 1.3、抓包工具的使用 1.3.1、抓包工具在HTTP传输时的工作原理 1.3.2、Fiddler抓包工具的下载和使用 2、HTTP协议格式 2.1、HTTP 请求格式 2.1.1.基本格式 2.1.2、了解HTTP请求包中的…

有趣的命令——————用随机密码新建20个用户,并输出密码

vim test.sh 输入以下内容&#xff1a;for i in seq 10douseradd user$ipassecho $RANDOM | md5sum |cut -c 1-6echo "$pass" | passwd --stdin "user$i"echo -e "账户&#xff1a;user$i\n 密码&#xff1a;$pass" >> /root/passwddone例…

Layui关于如何添加连接数据库的选项卡(三)

目录 1.实现效果&#xff1a; 2.思路&#xff1a; 3.PermissionDao类&#xff08;增加属性&#xff09; 4.主页&#xff1a;jsp 5.简洁风格修改选项卡的样式&#xff1a; 6.关于style中的属性设置使用 7.关于Element 组件介绍&#xff1a; 8. Layui 中的页面进行更新和…

如何解决git中拉取或提交代码出现的ssl证书问题?

问题描述 执行命令的时候&#xff0c;出现"…certificate problem…"报错&#xff0c;一般在执行"git push“ (推送分支) 或者 “git clone”(克隆仓库)时出现&#xff0c;原因时因为SSL安全验证问题&#xff0c;不能获取到本地的的证书。那么如何解决这个问题…

Linus再发飙:这就是一堆垃圾!

Linux 6.3 内核的合并窗口已开启&#xff0c;Linus Torvalds 也收到了大量的 PR&#xff0c;目前总体看来正在有序进行。但 Linus 对部分合并请求的日志信息非常不满&#xff1a;“我之前就已经说过&#xff0c;很显然现在我需要再重复一次&#xff0c;如果你懒得解释为什么会存…

【UE4 C++】根据指定路径生成静态网格体

在上一篇博客中&#xff08;【UE C】蓝图调用C函数&#xff09;&#xff0c;我们用C创建了一个蓝图函数库&#xff0c;本篇文章在这个蓝图函数库基础上增加一个方法&#xff0c;该方法只需输入一个文件目录路径&#xff0c;就可在场景中生成该目录下得所有静态网格体。&#xf…

Kafka学习笔记(高级篇)

目录 高级功能 高效读写 涉及技术 ZooKeeper 自定义拦截器 监控 延迟消费 一些改进手段 高级功能 高效读写 涉及技术 高吞吐量&#xff1a;Kafka 每秒可以处理数百万消息。这是因为 Kafka 消息的处理是以批处理&#xff08;Batching&#xff09;的方式来完成的&…

python+unittest+requests+HTMLRunner搭建接口测试框架,执行用例请求多个不同请求方式的接口

问题描述&#xff1a; 搭建接口测试框架&#xff0c;执行用例请求多个不同请求方式的接口 实现步骤&#xff1a; ① 创建配置文件config.ini&#xff0c;写入部分公用参数&#xff0c;如接口的基本url、测试报告文件路径、测试数据文件路径等配置项 1 [DATABASE] 2 data_addre…