竞争的关键驱动的异步通知

竞争的关键驱动的异步通知

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

       转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/24326603

       说起异步通知,简单点的理解就是:曾经都是应用程序主动看按键是否按下云云的。

这回应用程序架子大了。说老子才不去呢。

把任务给了驱动。

然后驱动发现按键按下。屁颠屁颠的去通知应用程序。

一.驱动代码

      假设你看了前几篇文章。这个代码对你来说是很easy的,所修改的东西很的少。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>


static struct class *fifthdrv_class;
static struct class_device	*fifthdrv_class_dev;

//volatile unsigned long *gpfcon;
//volatile unsigned long *gpfdat;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1。fifth_drv_read将它清0 */
static volatile int ev_press = 0;

static struct fasync_struct *button_async;  //定义一个结构


struct pin_desc{                  //定义结构体
	unsigned int pin;
	unsigned int key_val;
};


/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;

/*
 * K1,K2,K3,K4相应GPG0,GPG3,GPG5,GPG6
 */

struct pin_desc pins_desc[4] = {     //定义一个结构体数组
	{S3C2410_GPG0, 0x01},
	{S3C2410_GPG3, 0x02},
	{S3C2410_GPG5, 0x03},
	{S3C2410_GPG6, 0x04},
};


/*
  * 确定按键值
  */
static irqreturn_t buttons_irq(int irq, void *dev_id)          //參数中断号,和ID
{
	struct pin_desc * pindesc = (struct pin_desc *)dev_id;    //?

定义一个结构体指针使他的初值为ID unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); //系统函数独处引脚值(GPF0) if (pinval) { /* 松开 */ key_val = 0x80 | pindesc->key_val; } else { /* 按下 */ key_val = pindesc->key_val; } ev_press = 1; /* 表示中断发生了 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ kill_fasync (&button_async, SIGIO, POLL_IN); //发送信号 return IRQ_RETVAL(IRQ_HANDLED);}static int fifth_drv_open(struct inode *inode, struct file *file){ /* GPG0。GPG3,GPG5。GPG6为中断引脚: EINT8,EINT11,EINT13,EINT14 */ request_irq(IRQ_EINT8, buttons_irq, IRQT_BOTHEDGE, "K1", &pins_desc[0]); request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "K2", &pins_desc[1]); request_irq(IRQ_EINT13, buttons_irq, IRQT_BOTHEDGE, "K3", &pins_desc[2]); request_irq(IRQ_EINT14, buttons_irq, IRQT_BOTHEDGE, "K4", &pins_desc[3]); return 0;}ssize_t fifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos){ if (size != 1) return -EINVAL; /* 假设没有按键动作, 休眠 */ wait_event_interruptible(button_waitq, ev_press); /* 假设有按键动作, 返回键值 */ copy_to_user(buf, &key_val, 1); ev_press = 0; return 1;}int fifth_drv_close(struct inode *inode, struct file *file) //出链,禁止中断{ free_irq(IRQ_EINT8, &pins_desc[0]); free_irq(IRQ_EINT11, &pins_desc[1]); free_irq(IRQ_EINT13, &pins_desc[2]); free_irq(IRQ_EINT14, &pins_desc[3]); return 0;}static unsigned fifth_drv_poll(struct file *file, poll_table *wait){ unsigned int mask = 0; poll_wait(file, &button_waitq, wait); // 不会立即休眠,仅仅是把进程挂到队列里面去 if (ev_press) //推断是否有数据返回。有的话进行赋值,没有的话休眠 mask |= POLLIN | POLLRDNORM; //返回位掩码, 它描写叙述哪个操作可立即被实现。

return mask;}static int fifth_drv_fasync (int fd, struct file *filp, int on) { printk("driver: fifth_drv_fasync\n"); //为了说明次函数被调用添加一条打印语句 return fasync_helper (fd, filp, on, &button_async); //初始化定义的结构体}static struct file_operations sencod_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自己主动创建的__this_module变量 */ .open = fifth_drv_open, .read = fifth_drv_read, .release = fifth_drv_close, .poll = fifth_drv_poll, .fasync = fifth_drv_fasync,};int major;static int fifth_drv_init(void){ major = register_chrdev(0, "fifth_drv", &sencod_drv_fops); fifthdrv_class = class_create(THIS_MODULE, "fifth_drv"); fifthdrv_class_dev = class_device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */// gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);// gpfdat = gpfcon + 1; return 0;}static void fifth_drv_exit(void){ unregister_chrdev(major, "fifth_drv"); class_device_unregister(fifthdrv_class_dev); class_destroy(fifthdrv_class);// iounmap(gpfcon); return 0;}module_init(fifth_drv_init);module_exit(fifth_drv_exit);MODULE_LICENSE("GPL");


二.应用程序代码

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


/* fifthdrvtest 
  */
int fd;

void my_signal_fun(int signum)    //信号处理函数
{
	unsigned char key_val;
	read(fd, &key_val, 1);       //读取按键值
	printf("key_val: 0x%x\n", key_val);  //打印
}

int main(int argc, char **argv)
{
	unsigned char key_val;
	int ret;
	int Oflags;

	signal(SIGIO, my_signal_fun); //注冊信号处理函数
	
	fd = open("/dev/buttons", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
	}

	fcntl(fd, F_SETOWN, getpid());      // 告诉内核,发给谁(通过PID)
	
	Oflags = fcntl(fd, F_GETFL); 
	
	fcntl(fd, F_SETFL, Oflags | FASYNC);  // 改变fasync标记,终于会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct


	while (1)
	{
		sleep(1000);
	}
	
	return 0;
}


三.分析

           1.应用程序

        首先来看看应用程序都干了些什么。应用程序首先注冊了信号处理函数(函数的处理主要写在这里)。然后打开驱动。主函数中while(1)中是个循环,一直睡眠。

其中断发生时候,驱动会把信号发给应用程序。应用程序在信号处理函数进行处理。fcntl(fd, F_SETOWN, getpid());

                                Oflags = fcntl(fd, F_GETFL);
                                fcntl(fd, F_SETFL, Oflags | FASYNC);
这三段代码是应用程序实现异步通知的机制所在。

用户程序必须运行 2 个步骤来使能来自输入文件的异步通知. 首先, 它们指定一个进程作为文件的拥有者. 当一个进程使用 fcntl 系统调用发出 F_SETOWN 命令, 这个拥有者进程的 ID 被保存在 filp->f_owner 给以后使用. 这一步对内核知道通知谁是必要的. 为了真正使能异步通知, 用户程序必须设置 FASYNC 标志在设备中, 通过 F_SETFL fcntl 命令.

在这 2 个调用已被运行后, 输入文件可请求递交一个 SIGIO 信号, 不管何时新数据到达. 信号被发送给存储于 filp->f_owner 中的进程(或者进程组, 假设值为负值).

(说的有点可能难以理解。没关系最后会用一张图给小伙伴们说明当中的道理)


           2.驱动程序

1. 当发出 F_SETOWN, 什么都没发生, 除了一个值被赋值给 filp->f_owner.(内核完毕的)

2.当 F_SETFL 被运行来打开 FASYNC, 驱动的 fasync 方法被调用.

static int fifth_drv_fasync (int fd, struct file *filp, int on)   
{
	printk("driver: fifth_drv_fasync\n");             //为了说明次函数被调用添加一条打印语句
	return fasync_helper (fd, filp, on, &button_async); //初始化定义的结构体
}

3. 当数据到达, 全部的注冊异步通知的进程必须被发出一个 SIGIO 信号.

kill_fasync (&button_async, SIGIO, POLL_IN);  

到这里应用程序就接收到信号了,运行对应的操作了。

       

           3.图片

竞争的关键驱动的异步通知

你发现怎么我按下一次出现了了好几个0x1啊。卖个关子,以下几篇会有讲诉。


竞争的关键驱动的异步通知


版权声明:本文博客原创文章,博客,未经同意,不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117546.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 保姆级-红米AC2100之breed不死后台刷写openwrt官方版&第三方改良版「建议收藏」

    保姆级-红米AC2100之breed不死后台刷写openwrt官方版&第三方改良版「建议收藏」刷机有风险!!!后果自负准备1.红米AC21002.基础的电脑操作breed不死后台第一步:环境准备进入小米路由器原始的管理页,miwifi.com或者192.168.31.1登录之后,检查固件版本第二步:降级这里必须降级,我们降到到2.0.7降级包地址链接提取码:tenk然后等几分钟连接上降级后的wifi,正常是redmi开头无密码连上后重新进入后台192.168.31.1自行设置向导,这里忽略然后检查一下系统版本是否降级成功第三步:写入breed此时注意浏览器

    2025年6月28日
    2
  • 如何解决eclipse中的中文乱码问题[通俗易懂]

    eclipse中文乱码都是因为字符编码与默认的编码不符合导致的,有很多的方法可以解决,不需要安装任何插件就可以搞定。针对不同的情况,需要使用不同的方案,下面就针对一些案例讲解如何解决乱码问题。解决乱码问题的主要思路是设置正确合适的编码,如果不知道目标文件原本的编码,可以进行一定的尝试,通常尝试下GBK和UTF-8这两个编码即可。方法1设置单个文件的字符编码,解决单个文件的乱码问题有时候不小心cop…

    2022年4月3日
    44
  • 基于51单片机控制步进电机正反转

    基于51单片机控制步进电机正反转基于51单片机控制步进电机正反转此次采用uln2003模块来链接步进电机;##步进电机工作原理步进电机是一种将电脉冲信号转换成相应角位移或线位移的电动机。每输入一个脉冲信号,转子就转动一个角度或前进一步,其输出的角位移或线位移与输入的脉冲数成正比,转速与脉冲频率成正比。步进电动机的结构形式和分类方法较多,一般按励磁方式分为磁阻式、永磁式和混磁式三种;按相数可分为单相、两相、三相和多相等形式。因此我们可以控制单片机I/O口的电平来控制步进电机,此次设计中采用四相单拍工作方式,在这种工作方式下,A、

    2022年5月31日
    72
  • Matlab中axis函数用法总结[通俗易懂]

    Matlab中axis函数用法总结[通俗易懂]axis主要是用来对坐标轴进行一定的缩放操作,其操作命令主要如下:1、axis([xminxmaxyminymax])设置当前坐标轴x轴和y轴的限制范围2、axis([xminxmaxyminymaxzminzmaxcmincmax])设置x,y,z轴的限制范围和色差范围。3、v=axis返回一个行向量,记录了坐标范围4、axis…

    2022年6月14日
    124
  • 原生android系统官网 source.android.com,存储  |  Android 开源项目  |  Android Open Source Project…「建议收藏」

    原生android系统官网 source.android.com,存储  |  Android 开源项目  |  Android Open Source Project…「建议收藏」Android一直在不断发展,可支持各种存储设备类型和功能。所有Android版本均支持配有传统存储(包括便携式存储和模拟存储)的设备。便携式存储是指物理介质(如SD卡或USB设备),用于进行临时数据传输/文件存储。物理介质可以随设备一起保留更长时间,但并非固定在设备上,可以移除。自Android1.0开始,SD卡已可用作便携式存储;Android6.0增加了对USB…

    2022年6月19日
    232
  • java- string转成 json[通俗易懂]

    java- string转成 json[通俗易懂]1,Stringoutput=FileUtils.ReadFile(url);System.out.println(output);JSONArrayjsonArray=JSONObject.parseArray(output);returnjsonArray;2,https://blog.csdn.net/javaQQ56148…

    2022年6月3日
    138

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号