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

Rk3568驱动开发_非阻塞IO_16

在这里插入图片描述

非阻塞IO就是当文件描述符不可读取的时候直接就跳过,进行其他任务

驱动代码:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
//#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <linux/poll.h>#define KEY_CNT			1		/* 设备号个数 	*/
#define KEY_NAME		"blockirqkey"	/* 名字 		*/enum key_status{KEY_PRESS = 0,  // 按下KEY_RELEASE,   // 松开KEY_KEEP,     // 保持
};struct key_dev{dev_t devid;                   // 设备号struct cdev cdev;             // cdevstruct class* class;         //  类struct device* device;      // 设备struct device_node* nd;     // 设备节点int key_gpio;             // gpio编号struct timer_list timer;  //int irq_num;             // 中断号atomic_t status;         // 按键状态wait_queue_head_t r_wait; // 读等待队列头
};static struct key_dev key;  // 设备static void key_timer_function(struct timer_list* arg){   // 定时器处理函数static int last_val = 0;int current_val;current_val = gpio_get_value(key.key_gpio); // 读取按键值if(1 == current_val && !last_val){  // 按下atomic_set(&key.status, KEY_PRESS);wake_up_interruptible(&key.r_wait);  // 唤醒r_wait队列头中的所有队列}else if(0 == current_val && last_val){ // 松开atomic_set(&key.status, KEY_RELEASE);wake_up_interruptible(&key.r_wait); // 唤醒}else atomic_set(&key.status, KEY_KEEP); // 状态保持last_val = current_val;}/*解析设备树*/
static int key_parse_dt(void){int ret;const char* str;key.nd = of_find_node_by_path("/key");if(key.nd == NULL){printk("key node not find \n");return -1;}ret = of_property_read_string(key.nd, "status", &str);if(ret < 0)return -1;if(strcmp(str, "okay"))return -1;ret = of_property_read_string(key.nd, "compatible", &str);if(ret < 0){printk("key: failed to get compatible property\n");return -1;}if(strcmp(str, "alientek,key")){printk("key: compatible match failed\n");return -1;}key.key_gpio = of_get_named_gpio(key.nd, "key-gpio", 0);if(key.key_gpio < 0){printk("cant get key-gpio");return -1;}key.irq_num = irq_of_parse_and_map(key.nd, 0); // 获取gpio对应中断号if(!key.irq_num){return -1;}printk("key-gpio num: %d\n", key.key_gpio);return 0;
}static irqreturn_t key_interrupt(int irq, void* dev_id){  // 中断处理函数mod_timer(&key.timer, jiffies + msecs_to_jiffies(15));return IRQ_HANDLED;
}static int key_gpio_init(void){int ret;unsigned long irq_flags;ret = gpio_request(key.key_gpio, "KEY0");if(ret){printk("failed to request key-gpio\n");return ret;}gpio_direction_input(key.key_gpio); // 输入模式irq_flags = irq_get_trigger_type(key.irq_num);if(irq_flags == IRQF_TRIGGER_NONE)irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;ret = request_irq(key.irq_num, key_interrupt, irq_flags, "key0_IRQ", NULL); // 申请中断if(ret){gpio_free(key.key_gpio);return ret;}return 0;
}static int key_open(struct inode* inode, struct file* filp){return 0;
}static ssize_t key_read(struct file* filp, char __user* buf, size_t cnt, loff_t* offt){int ret;// 加入队列,当有按键按下或松开动作发生才会被唤醒printk("read wait\n");if(filp->f_flags & O_NONBLOCK){  // 阻塞if(KEY_KEEP == atomic_read(&key.status))return -EAGAIN;}else{ // 非阻塞ret = wait_event_interruptible(key.r_wait, KEY_KEEP != atomic_read(&key.status));if(ret) return ret;}printk("read release\n");if(ret) return ret;// 发送数据给应用层序ret = copy_to_user(buf, &key.status, sizeof(int));atomic_set(&key.status, KEY_KEEP);return ret; 
}static ssize_t key_write(struct file* filp, const char __user* buf, size_t cnt, loff_t* offt){return 0;
}static int key_release(struct inode* inode, struct file* filp){return 0;
}static unsigned int key_poll(struct file *filp, struct poll_table_struct *wait){unsigned int mask = 0;poll_wait(filp, &key.r_wait, wait);if(KEY_KEEP != atomic_read(&key.status)) mask = POLLIN | POLLRDNORM;printk("mask: %d\n", mask);return mask;
}static struct file_operations key_fops = {.owner = THIS_MODULE,.open = key_open,.read = key_read,.write = key_write,.release = key_release,.poll = key_poll,
};static int __init mykey_init(void){int ret;// 初始化等待队列头init_waitqueue_head(&key.r_wait);timer_setup(&key.timer, key_timer_function, 0); // 初始化timer// 初始化按键状态atomic_set(&key.status, KEY_KEEP);ret = key_parse_dt(); // 设备树解析if(ret) return ret;ret = key_gpio_init(); // 中断初始化if(ret) return ret; /*注册字符设备驱动*/// 1、创建设备号  ret = alloc_chrdev_region(&key.devid, 0, KEY_CNT, KEY_NAME);  // 申请设备号if(ret < 0){printk("alloc_chrdev_region failed");goto free_gpio;}// 2.初始化cdevkey.cdev.owner = THIS_MODULE;cdev_init(&key.cdev, &key_fops);ret = cdev_add(&key.cdev, key.devid, KEY_CNT);if(ret < 0) goto del_unregister;// 创建类key.class = class_create(THIS_MODULE, KEY_NAME);if(IS_ERR(key.class)){goto del_cdev;}// 创建设备key.device = device_create(key.class, NULL, key.devid, NULL, KEY_NAME);if(IS_ERR(key.device)){goto destory_class;}return 0;destory_class:class_destroy(key.class);
del_cdev:cdev_del(&key.cdev);
del_unregister:unregister_chrdev_region(key.devid, KEY_CNT);
free_gpio:  free_irq(key.irq_num, NULL);gpio_free(key.key_gpio);return -1;
}static void __exit mykey_exit(void){// 注销字符设备驱动cdev_del(&key.cdev);  // 删除cdevunregister_chrdev_region(key.devid, KEY_CNT); // 注销设备号del_timer_sync(&key.timer); // 删除timerdevice_destroy(key.class, key.devid); // 注销设备class_destroy(key.class); // 注销类free_irq(key.irq_num, NULL); // 释放中断gpio_free(key.key_gpio); // 释放io
}module_init(mykey_init);
module_exit(mykey_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Narnat");

应用层:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <errno.h>int main(int argc, char* argv[]){int fd, ret;int key_val;fd_set readfds;struct timeval timout;if (argc != 2) {printf("input number error!\n");return -1;}fd = open(argv[1], O_RDONLY | O_NONBLOCK);if (fd < 0) {printf("open file error\n");return -1;}while (1) {FD_ZERO(&readfds);       // 每次循环重新初始化FD_SET(fd, &readfds);    // 重新设置文件描述符timout.tv_sec = 1;       // 设置超时为 100mstimout.tv_usec = 0;ret = select(fd + 1, &readfds, NULL, NULL, &timout);printf("ret: %d \n", ret);switch(ret) {case 0:  // 超时printf("case 0 (timeout)\n");break;case -1: // 错误perror("select error");break;default:if (FD_ISSET(fd, &readfds)) {ret = read(fd, &key_val, sizeof(int));if (ret < 0) {if (errno == EAGAIN) {printf("No data available (non-blocking)\n");} else {perror("read error");}continue;}if (0 == key_val) printf("key press\n");else if (key_val == 1) printf("key release\n");}break;}}close(fd);return 0;
}

poll_wait(filp, &key.r_wait, wait);用于将文件描述符加入队列,当文件描述符能用的时候,用于唤醒应用层的select函数,否则select函数,就一直处于阻塞状态,key_poll用于判断此文件描述符可不可用,根据return的值去判断文件描述符状态,如果可用,poll_wait会唤醒应用层select函数,去继续执行下面层序,否者根据需要,会选择等待和阻塞程序。应用层调用select函数,应用层会去调用驱动层poll函数实现接口。

效果:
在这里插入图片描述

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

相关文章:

  • Linux下SPI设备驱动开发
  • WPF实现加载初始页面后跳转到主界面并销毁初始页面资源
  • docker磁盘空间不足解决办法
  • Linux驱动15 --- buildroot杂项驱动开发方法
  • windows内核研究(驱动开发-多核同步之临界区和自旋锁)
  • 【Linux内核】Linux驱动开发
  • 智慧场景:定制开发开源AI智能名片S2B2C商城小程序赋能零售新体验
  • 莘默曹工-Cd Automation半导体调功器 RS2300-
  • Mac安装Typescript报错
  • 电脑声音修复?【图文详解】电脑没有声音?声音异常
  • 如何升级到macOS Tahoe:全面指南与实用步骤
  • node.js 为什么要装 express组件
  • Node.js的Transform 流
  • 深度学习-常用环境配置
  • Spring 对数组和集合类的自动注入
  • 机器学习初学者理论初解
  • Oracle 数据库共享池与大池调优指南
  • ElasticSearch:不停机更新索引类型(未验证)
  • Django基础(五)———模板结构
  • 中小型企业如何选择合适的WMS系统?
  • 如何用DispatcherTimer提高运行总时间的精确度
  • AI探索 | 基于 Node.js 开发 MCP 客户端+服务端及优秀项目分享
  • Node.js- node管理工具nvm
  • Spring @RequestBody注解详解与实践
  • Dockerfile 完全指南:从入门到精通
  • 西门子 S7-1500 信号模块硬件配置全解析:从选型到实战
  • (10)机器学习小白入门 YOLOv:YOLOv8-cls 模型评估实操
  • 使用 Tailwind CSS 控制元素在移动端不显示
  • 【LuckiBit】macOS/Linux 常用命令大全
  • Jenkins pipeline触发下游流水线