驱动开发 作业5

题目

使用驱动代码实现如下要求:

  1. 使用驱动通过阻塞 io 模型读取 number 变量的值
  2. number 是内核驱动中的一个变量
  3. number 的值随着按键按下而改变(按键中断)
    • 例如 number = 0 按下按键 number = 1,再次按下按键 number = 0
  4. 在按下按键的时候需要同时将 led1 的状态取反>
  5. 驱动中需要编写字符设备驱动
  6. 驱动中需要自动创建设备节点
  7. 在这个驱动需要的所有设备信息放在设备树的同一个节点中

Repo

设备树文件

c 复制代码
/dts-v1/;

#include "stm32mp157.dtsi"
#include "stm32mp15xa.dtsi"
#include "stm32mp15-pinctrl.dtsi"
#include "stm32mp15xxac-pinctrl.dtsi"
#include "stm32mp15xx-fsmp1x.dtsi" 

/ {
  model = "HQYJ STM32MP157 FSMP1A Discovery Board";
  compatible = "st,stm32mp157a-dk1", "st,stm32mp157";

  aliases {
    serial0 = &uart4;
    serial5 = &usart3;
  };

  chosen {
    stdout-path = "serial0:115200n8";
  };

  reserved-memory {
    gpu_reserved: gpu@d4000000 {
                    reg = <0xd4000000 0x4000000>;
                    no-map;
                  };

    optee_memory: optee@0xde000000 {
                    reg = <0xde000000 0x02000000>;
                    no-map;
                  };
  };
  
  //自定义设备树 
  mynode@0x12345678{ 
		compatible = "hqyj,mynode"; 
    	astring="hello 23031"; 
		uint  =<0xaabbccdd 0x11223344>; 
    	binarry=[00 0c 29 7b f9 be]; 
    	mixed ="hello",[11 22],<0x12345678>; 
	 };

  mychrdev {
   led=<&gpioe 10 0>;    
   interrupt-parent=<&gpiof>;
   interrupts=<9 0>;
  };
};

驱动代码

c 复制代码
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>

int major;
struct class *cls;
struct device *dev;

int number = 0;
unsigned int condition = 0;
wait_queue_head_t wq_head;

// 所有的设备都在同一个节点下
struct device_node *dnode;
unsigned int irqno;
struct gpio_desc *gpiono;

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
	int ret;
	wait_event_interruptible(wq_head, condition);

	ret = copy_to_user(ubuf, &number, sizeof(number));
	if (ret) {
		printk("copy_to_user failed\n");
		return -EIO;
	}
	condition = 0;
	return 0;
}

struct file_operations fops = {
	.read = mycdev_read,
};

// 中断处理函数
irqreturn_t myirq_handler(int irq, void *dev_id)
{
	number = !number;
	gpiod_set_value(gpiono, number);
	printk("key pressed, number=%d\n", number);
	return IRQ_HANDLED;
}

static int __init mycdev_init(void)
{
	int ret;
	// 初始化等待队列头
	init_waitqueue_head(&wq_head);
	// 字符设备注册
	major = register_chrdev(0, "mycdev", &fops);
	if (major < 0) {
		printk("register_chrdev failed\n");
		return major;
	}
	// 向上提交目录
	cls = class_create(THIS_MODULE, "mycdev");
	if (IS_ERR(cls)) {
		printk("class_create failed\n");
		return -PTR_ERR(cls);
	}
	// 创建设备文件
	dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "led");
	if (IS_ERR(dev)) {
		printk("device_create failed\n");
		return -PTR_ERR(dev);
	}
	dev = device_create(cls, NULL, MKDEV(major, 1), NULL, "key");
	if (IS_ERR(dev)) {
		printk("device_create failed\n");
		return -PTR_ERR(dev);
	}
	dnode = of_find_node_by_path("/mychrdev");
	if (!dnode) {
		printk("of_find_node_by_path failed\n");
		return -ENXIO;
	}
	irqno = irq_of_parse_and_map(dnode, 0);
	if (!irqno) {
		printk("irq_of_parse_and_map failed\n");
		return -ENXIO;
	}
	ret = request_irq(irqno, myirq_handler, IRQF_TRIGGER_FALLING, "key",
			  NULL);
	if (ret) {
		printk("request_irq failed\n");
		return ret;
	}
	gpiono = gpiod_get_from_of_node(dnode, "led", 0, GPIOD_OUT_LOW, NULL);
	if (IS_ERR(gpiono)) {
		printk("gpiod_get_from_of_node failed\n");
		return -PTR_ERR(gpiono);
	}
	return 0;
}

static void __exit mycdev_exit(void)
{
	// 注销设备文件
	device_destroy(cls, MKDEV(major, 0));
	device_destroy(cls, MKDEV(major, 1));
	// 注销目录
	class_destroy(cls);
	// 注销字符设备
	unregister_chrdev(major, "mycdev");
	// 注销中断号
	free_irq(irqno, NULL);
	// 释放gpio
	gpiod_put(gpiono);
}

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

测试代码

c 复制代码
#include <stdlib.h>
#include <stdio.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 number;
	int fd = open("/dev/led", O_RDWR);
	if (fd < 0) {
		printf("打开设备文件失败\n");
		exit(-1);
	}
	while (1) {
		read(fd, &number, sizeof(number)); //读取数据
		printf("read:%d\n", number);
	}

	close(fd);
	return 0;
}
相关推荐
大江东去浪淘尽千古风流人物3 天前
【Micro-WL Robot】桌面级轮腿机器人全栈解析:LQR平衡控制、SimpleFOC驱动与五连杆腿部机构源码深度拆解
驱动开发·机器人·esp32·lqr·simplefoc·轮腿机器人·平衡控制
咖啡星人k4 天前
自然语言驱动开发(NLDD):全栈开发的新范式与实践指南
驱动开发
阿昭L4 天前
Windows键盘过滤
windows·驱动开发·windows内核·过滤驱动
hai3152475435 天前
# 矩阵算法·算子对齐工具 v6.1 — 技术规格与使用手册
java·开发语言·驱动开发·神经网络·spring·目标检测·矩阵
qq_411262425 天前
sdk不支持分配psarm如何办,能不能象S3一样支持
驱动开发
湉湉家的小虎子6 天前
【科普贴】浅谈UFS接口——偏硬件解析
驱动开发·嵌入式硬件·fpga开发·硬件工程
枳实-叶7 天前
【Linux驱动开发】第18天:I2C驱动深度解析
linux·运维·驱动开发
小此方7 天前
Re:Linux系统篇(二十五)进程篇·十:深度硬核!Linux 进程等待,从 task_struct 源码到位图状态解构
linux·运维·驱动开发
Gentle5867 天前
SENT&SPC协议中的CRC4校验
驱动开发
智者知已应修善业7 天前
【proteus设计文氏正弦波信号发生器】2023-5-9
驱动开发·经验分享·笔记·硬件架构·proteus·硬件工程