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

5.Linux按键驱动-fasync异步通知

在这里插入图片描述
1.使用流程
在这里插入图片描述
在这里插入图片描述

2.应用程序思路
2.1绑定信号和信号处理函数

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

在这里插入图片描述
在这里插入图片描述当应用程序收到SIGIO信号的时候, sig_func函数就会被调用,调用read函数读取按键的值。

2.2APP把自己的pid告诉驱动程序。

在这里插入图片描述

在这里插入图片描述
注意:

这里一定要使能异步通知,不然驱动中的
gpio_fasync不会设置button中的fa_file成员。

其次会导致kill_fasync不知道应用程序的PID,不知道将信号发送给哪一个进程。

在这里插入图片描述
在这里插入图片描述

3.驱动程序思路
在这里插入图片描述
在这里插入图片描述

4.程序
应用:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>

static int fd;

/* 信号处理函数 */
static void sig_func(int sig)
{
	int val;
	int num;
	read(fd,&val,4);
	num  = val >>8;
	printf("get button: %d val = %d\n", num, val - num *(1 << 8));
}

int main(int argc, char** argv)
{
	
	int val;
	int num;
	struct pollfd fds[1];
	int timeout_ms = 5000;
	int ret;
	int flags;
	/* 判断输入值是否合法 */
	if(argc != 2)
	{
		printf("Usage ./button_app /dev/devname\n");
		return -1;
	}

	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
	{
		printf("open err\n");
	}
	else
	{
		printf("open success\n");
	}

	/* 初始化文件监听描述符 */
	fds[0].fd     = fd;
	fds[0].events = POLLIN;

	/*绑定SIGIO和sig_func */
	signal(SIGIO, sig_func);
	
	/* APP把自己的pid告诉驱动 */
	fcntl(fd, F_SETOWN, getpid());/* APP把自己的pid告诉驱动程序 */
	flags = fcntl(fd,F_GETFL);/* 获得标志位 */
	fcntl(fd, F_SETFL, flags | FASYNC);/* 使能异步通知 */
	//printf("设置了FASYNC\n");
	while(1)
	{
		printf("www.100ask.net \n");
		sleep(2);
	}
	
	/*while(1)
	{
		ret = poll(fds, 1, timeout_ms);
		if((ret == 1) && (fds[0].revents == POLLIN))
		{
			read(fd, &val, 4);
			num  = val >>8;
			printf("get button: %d val = %d\n", num, val - num *(1 << 8));
		}
		else
		{
			printf("timeout\n");
		}
	}*/
	close(fd);
	return 0;
}

驱动:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>


/* 定义结构体来描述gpio */
struct gpio_key{
	int gpio;
	struct gpio_desc* gpiod;
	int flag;
	int irq;
};

/* 定义全局变量来存储设备树中的所有gpio节点信息 */
static struct gpio_key* gpio_keys_100ask;

/* 字符设备的主设备号 */
static unsigned int major = 0;
static struct class *gpio_class;
//static int g_key = 0;

/* 定义等待队列 */
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
struct fasync_struct * button_fasync;




/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;

#define NEXT_POS(x) ((x+1) % BUF_LEN)

int is_key_buf_empty(void)
{
	return (r == w);
}

int is_key_buf_full(void)
{
	return (r == NEXT_POS(w));
}

void put_key(int key)
{
	if (!is_key_buf_full())
	{
		g_keys[w] = key;
		w = NEXT_POS(w);
	}
}

int get_key(void)
{
	int key = 0;
	if (!is_key_buf_empty())
	{
		key = g_keys[r];
		r = NEXT_POS(r);
	}
	return key;
}

static ssize_t gpio_read(struct file *fp, char __user *buf, size_t size, loff_t * offset)
{
	int err;
	int key;
	wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());
	key = get_key();
	//err = copy_to_user(buf, &g_key, 4);
	err = copy_to_user(buf, &key, 4);
	//g_key = 0;
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 4;
}

static unsigned int gpio_poll(struct file *fp, struct poll_table_struct *wait)
{
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	poll_wait(fp, &gpio_key_wait, wait);
	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}

static int gpio_fasync(int fd , struct file *file, int on)
{
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
	{
		return 0;
	}
	else
	{
		return -EIO;
	}
}




static const struct file_operations gpio_fops = {
	.owner = THIS_MODULE,
	.read  = gpio_read,
	.poll  = gpio_poll,
	.fasync = gpio_fasync,
};

static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key* gpio_key = dev_id;
	int val;
	int key;
	val = gpio_get_value(gpio_key->gpio);
	//printk("key %d %d\n", gpio_key->gpio, val);
	//g_key = (gpio_key->gpio << 8) | val;
	key = (gpio_key->gpio << 8) | val;
	
	put_key(key);
	wake_up_interruptible(&gpio_key_wait);

	/* 发信号 */
	kill_fasync(&button_fasync, SIGIO, POLL_IN);
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return IRQ_HANDLED;
}

static int gpio_probe(struct platform_device *pdev)
{
	int count, i;
	struct device_node *node;
	int err;

	node = pdev->dev.of_node;
	count = of_gpio_count(node);
	if (!count)
	{
		printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}
	
	/* 申请资源 */
	gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
	if (!gpio_keys_100ask)
	{
		printk("kzalloc error\n");
		return -1;
	}

	/* 获得资源 */
	for (i = 0; i < count; i++)
	{
		gpio_keys_100ask[i].gpio = of_get_gpio(node, i);
		if (gpio_keys_100ask[i].gpio < 0)
		{
			printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
			return -1;
		}
		gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
		gpio_keys_100ask[i].irq   = gpio_to_irq(gpio_keys_100ask[i].gpio);

		/* 申请中断 */
		err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "test1_gpio_keys_100ask", &gpio_keys_100ask[i]);
		if (err) 
		{
			printk("request_irq err\n");
		}
	}

	/* 注册字符设备 */
	major = register_chrdev(major, "100ask_key", &gpio_fops);
	if(major < 0)
	{
		printk("register_chrdev err'\n");
		return -1;
	}

	/* 注册类 */
	gpio_class = class_create(THIS_MODULE, "100ask_key_class");

	/* 注册设备 */
	device_create(gpio_class, NULL, MKDEV(major,0), NULL, "100ask_key_button");
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int gpio_remove(struct platform_device *pdev)
{
	int count, i;
	struct device_node *node;

	node = pdev->dev.of_node;
	count = of_gpio_count(node);
	device_destroy(gpio_class, MKDEV(major,0));
	class_destroy(gpio_class);
	unregister_chrdev(major, "100ask_key");

	for (i = 0; i < count; i++)
	{
		free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
	}
	kfree(gpio_keys_100ask);
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}


/*
* 在设备树中添加的节点的compatible属性为:"test1_100ask,test1_gpio_key"
*/
static const struct of_device_id gpio_key_of_match[] = {
	{.compatible = "test1_100ask,test1_gpio_key"},
	{/* 这里必须要有一个空项,表示结束 */}
};

static struct platform_driver gpio_driver = {
	.driver = {
		.name	= "test1_gpio_keys_100ask",
		.of_match_table = gpio_key_of_match,
	},
	.probe	= gpio_probe,
	.remove = gpio_remove,
};

/* 基于platform总线来实现这个程序 */
static int gpio_init(void)  
{
	int ret;

	ret = platform_driver_register(&gpio_driver);
	if (ret != 0)
	{
		printk("platform_driver_register err\n");
		return -1;
	}
	else
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	}
	return ret;
}

static void gpio_exit(void)
{
	platform_driver_unregister(&gpio_driver);
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
}

module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");


http://www.kler.cn/news/367467.html

相关文章:

  • 传奇开服教程之新GOM引擎登录器配置教程
  • 哪些CRM系统适合医疗行业?主流10款产品全解析
  • MyBatis 配置详解
  • Java后端面试题:Java基础篇
  • 探秘 MySQL 数据类型的艺术:性能与存储的精妙平衡
  • Uni-App-03
  • 微信支付Java+uniapp微信小程序
  • Netty简单应用
  • C语言教程——数组(2)
  • UML之用例图详解
  • Linux 常用命令总汇
  • 二、Spring的执行流程
  • 【webpack学习】
  • w003基于Springboot的图书个性化推荐系统的设计与实现
  • Padavan开启IPV6
  • 在css中使用js变量(待整理)
  • cc2530 Basic RF 讲解 和点灯讲解(1_1)
  • tkinter包中包含的colorchooser模块简介
  • 卷积神经网络:卷积层,池化层,全连接层
  • springboot2.6.15升级至3.3.4,Spring Framework升级至6.1.14
  • GIT使用list
  • Java - Maven中pom文件的filtering作用
  • TDengine数据库整合MyBatis实现SpringBoot项目CRUD
  • 标准版增加订单导出的字段
  • Go encoding/json库
  • 数字后端零基础入门系列 | Innovus零基础LAB学习Day6