驱动开发 作业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;
}
相关推荐
路溪非溪2 小时前
Linux下蓝牙框架的数据流
linux·arm开发·驱动开发
钛态3 小时前
Flutter for OpenHarmony:mockito 单元测试的替身演员,轻松模拟复杂依赖(测试驱动开发必备) 深度解析与鸿蒙适配指南
服务器·驱动开发·安全·flutter·华为·单元测试·harmonyos
人生苦短,菜的抠脚11 小时前
RK628 Linux 内核驱动开发指南
linux·驱动开发
路溪非溪13 小时前
Linux下wifi子系统的数据流
linux·arm开发·驱动开发
阿昭L15 小时前
NT驱动程序和WDM驱动程序
驱动开发·windows内核
Freak嵌入式16 小时前
效率升级!uPyPi 支持 GitHub URL 直传,驱动发布一步到位
驱动开发
weiyvyy2 天前
嵌入式硬件接口开发的流程
人工智能·驱动开发·单片机·嵌入式硬件·硬件架构·硬件工程
weiyvyy2 天前
嵌入式硬件接口开发的核心原则
驱动开发·单片机·嵌入式硬件·fpga开发·硬件架构·硬件工程
春日见2 天前
自动驾驶的四个演进阶段
开发语言·人工智能·驱动开发·matlab·docker·计算机外设
索西引擎2 天前
Spec-Driven Development(SDD,规格驱动开发)
驱动开发·ai coding