驱动开发 作业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;
}
相关推荐
cxr8283 天前
SPARC方法论在Claude Code基于规则驱动开发中的应用
人工智能·驱动开发·claude·智能体
sukalot3 天前
window显示驱动开发—显示适配器的子设备
驱动开发
Evan_ZGYF丶3 天前
【RK3576】【Android14】如何在Android14下单独编译kernel-6.1?
linux·驱动开发·android14·rk3576
sukalot4 天前
window显示驱动开发—视频呈现网络简介
驱动开发
sukalot5 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)
驱动开发
zwhSunday5 天前
Linux驱动开发(1)概念、环境与代码框架
linux·运维·驱动开发
sukalot5 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(三)
驱动开发
sukalot5 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(一)
驱动开发
cxr8287 天前
基于Claude Code的 规范驱动开发(SDD)指南
人工智能·hive·驱动开发·敏捷流程·智能体
zwhSunday7 天前
Linux驱动开发(2)进一步理解驱动
linux·驱动开发