当前位置: 首页 > news >正文

驱动 - 20230829

练习

基于platform实现
在这里插入图片描述
在根节点下,增加设备树

	myplatform {compatible="hqyj,myplatform";interrupts-extended=<&gpiof 9 0>, <&gpiof 7 0>, <&gpiof 8 0>;led1-gpio=<&gpioe 10 0>;reg=<0x12345678 59>;};

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>// 中断
struct device_node *dnode;
unsigned int key_irqno;
struct gpio_desc *gpiono;
// 字符设备驱动
int major;
// 自动创建设备节点
struct class *cls;
struct device *dev;struct resource *res;int number = 0;
unsigned int condition = 0;
wait_queue_head_t wq_head; // 等待队列头// 封装操作方法
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)
{int ret;char kbuf[128] = {0};sprintf(kbuf, "number = %d", 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("copy_to_user err \n");return -EIO;}// condition清零condition = 0;return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{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 = {.open = mycdev_open,.read = mycdev_read,.write = mycdev_write,.release = mycdev_close,
};irqreturn_t key_handler(int irq, void *dev)
{if (number == 0){number = 1;}else{number = 0;}gpiod_set_value(gpiono, number);condition = 1;wake_up_interruptible(&wq_head);return IRQ_HANDLED;
}// 封装probe函数和remove函数
int pdrv_probe(struct platform_device *pdev)
{printk("pdrv_probe --------------------------- \n");int ret;/*** 1. 注册设备驱动*/major = register_chrdev(0, "mychrdev", &fops);if (major < 0){printk("字符设备驱动注册失败 \n");return major;}printk("字符设备驱动注册成功\n");/*** 2. 自动创建设备节点*/// 向上提交目录信息cls = class_create(THIS_MODULE, "mycdev");if (IS_ERR(cls)){printk("向上提交目录信息失败\n");return -PTR_ERR(cls);}printk("向上提交目录信息成功\n");// 向上提交设备信息dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mycdev0");if (IS_ERR(dev)){printk("向上提交设备节点失败\n");return -PTR_ERR(cls);}// 3. 初始化等待队列头init_waitqueue_head(&wq_head);// 获取MEM类型的资源res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL){printk("获取MEM类型资源失败\n");return -ENXIO;}/*** 中断*/// 获取软中断号key_irqno = platform_get_irq(pdev, 0);if (key_irqno < 0) {printk("获取软中断号失败 \n");return -ENXIO;}printk("获取软中断号成功 \n");// 注册中断ret = request_irq(key_irqno, key_handler, IRQF_TRIGGER_FALLING, "key1", NULL);if (ret < 0){printk("注册中断失败\n");return -1;}printk("注册中断成功\n");/*** LED灯*/// 获取gpio编号gpiono=gpiod_get_from_of_node(pdev->dev.of_node,"led1-gpio",0,GPIOD_OUT_HIGH,NULL);if(IS_ERR(gpiono)){printk("解析gpio信息失败\n");return -PTR_ERR(gpiono);}printk("解析gpio编号成功\n");return 0;
}
int pdrv_remove(struct platform_device *pdev)
{free_irq(key_irqno, NULL);gpiod_set_value(gpiono, 0);gpiod_put(gpiono);device_destroy(cls, MKDEV(major, 0));class_destroy(cls);unregister_chrdev(major, "mychrdev");printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}// 构建设备树匹配表
struct of_device_id oftable[] = {{.compatible="hqyj,myplatform",},{},
};// 分配驱动信息对象并初始化
struct platform_driver pdrv = {.probe = pdrv_probe,.remove = pdrv_remove,.driver = {.name="aaaaa",.of_match_table = oftable,},
};module_platform_driver(pdrv);MODULE_LICENSE("GPL");

应用层代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <pthread.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/epoll.h>int main(int argc, const char* argv[])
{int fd;char buf[128];if ((fd = open("/dev/mycdev0", O_RDWR)) == -1) {perror("open error");exit(EXIT_FAILURE);}while (1) {bzero(buf, sizeof(buf));read(fd, buf, sizeof(buf));printf("status = %s\n", buf);}close(fd);return 0;
}

效果展示
在这里插入图片描述

http://www.lryc.cn/news/145345.html

相关文章:

  • 数组(个人学习笔记黑马学习)
  • layui表格事件分析实例
  • Android NDK JNI与Java的相互调用
  • 装备制造企业如何执行精益管理?
  • PHP8中自定义函数-PHP8知识详解
  • 虚拟化技术:云计算发展的核心驱动力
  • 光伏+旅游景区
  • 手搓文本向量数据库(自然语言搜索生成模型)
  • EVO大赛是什么
  • linux中使用clash代理
  • Kafka3.0.0版本——Follower故障处理细节原理
  • 13.redis集群、主从复制、哨兵
  • linux字符串处理
  • Nginx入门——Nginx的docker版本和windows版本安装和使用 代理的概念 负载分配策略
  • Zebec Protocol:模块化 L3 链 Nautilus Chain,深度拓展流支付体系
  • Oracle-rolling upgrade升级19c
  • Spring IOC详解
  • Unity——DOTween插件使用方法简介
  • 数据库——Redis 单线程模型详解
  • leetcode 567. 字符串的排列(滑动窗口-java)
  • Git —— 分支重命名操作
  • JavaIO流
  • FlinkSql 如何实现数据去重?
  • 机器学习概念
  • 【数据结构】排序(插入、选择、交换、归并) -- 详解
  • 游戏中的图片打包流程,免费的png打包plist工具,一款把若干资源图片拼接为一张大图的免费工具
  • Springboot实现ENC加密
  • nginx 托管vue项目配置
  • Vue3中如何进行封装?—组件之间的传值
  • 实训笔记8.25