关于 exynos 4412 按键中断 异步通知

以下是驱动测试代码:

//内核的驱动代码

#include <linux/init.h>

#include <linux/module.h> //for module_init moudule_exit

#include <linux/fs.h> //for MKDEV register_chrdev_region

#include <linux/cdev.h> //字符设备头文件

#include <linux/device.h>

#include <asm/io.h> //for ioremap

#include <linux/platform_device.h> //for 平台设备

#include <linux/of.h>

#include <linux/signal.h>

#include <linux/interrupt.h>

#define LED_MA 500 //主设备号(那一类设备)

//某些主设备号已经静态地分配给了大部分公用设备。见Documentation/devices.txt 。 这里我们常使用250

#define LED_MI 2 //次设备号(这类设备当中的具体哪个设备)

//目标:把字符设备改造为平台设备

//1. 把硬件信息,分离出去,放到设备树

//#define LED3CON 0X11000C20

//#define LED3DAT 0x11000c24

struct resource *led_res_con;

struct resource *led_res_dat;

struct resource *key1_res; //devices source pointer

struct fasync_struct *async_queue; /* 异步结构体指针,用于读 */

struct cdev led; //定义一个字符设备

#define LED_MAGIC ‘L‘ //幻数,类似加密,避免误操作

#define LED_ON _IOW(LED_MAGIC, 1, int)

#define LED_OFF _IOW(LED_MAGIC,2,int)

unsigned int *led3_con;

unsigned int *led3_dat;

int led_open (struct inode *inode, struct file *file)

{

led3_con = ioremap((phys_addr_t)led_res_con,1); //把硬件的物理地址转换为内核的虚拟地址

if(led3_con == NULL){

printk("led3_con ioremap fail\n");

return -1;

}

led3_dat = ioremap((phys_addr_t)led_res_dat,1);

if(led3_dat == NULL){

printk("led3_dat ioremap fail\n");

return -1;

}

writel((readl(led3_con) & (~0xf)) | 1,led3_con);//led3 and key2 had use same register;

writel(1,led3_dat);

printk("led_open ok\n");

return 0;

}

int led_release(struct inode *inode, struct file *file)

{

free_irq(key1_res->start, NULL);

printk("remove OK\n");

printk("led_release ok\n");

return 0;

}

//实现自定义的个性化操作

long led_ioctl(struct file *file, unsigned int cmd, unsigned long args)

{

switch(cmd) //解析ioctl 命令

{

case LED_ON: //点亮灯

printk("led on cmd=%d\n",cmd);

writel(1,led3_dat);

break;

case LED_OFF: //灭灯

printk("led off cmd=%d\n",cmd);

writel(0,led3_dat);

break;

default:

printk("ioctl cmd no found\n");

break;

}

printk("led_ioctl end\n");

return 0;

}

irqreturn_t key_interrupt(int irqno, void *devid)

{

kill_fasync(&async_queue, SIGIO, POLL_IN); //发送SIGIO 异步通知信号

printk("irqno = %d\n", irqno);

return IRQ_HANDLED;

}

int key_fasync (int fd,struct file *filp,int mode)

{

return fasync_helper(fd,filp,mode,&async_queue);//处理标志的变更

}

//3.实现设备的文件操作

struct file_operations fops={ //设备的文件操作

.owner = THIS_MODULE,

.open = led_open,

.release = led_release,

.unlocked_ioctl = led_ioctl,

.fasync = key_fasync,

};

int led_init(struct platform_device *pdev) //把找到的平台设备的信息传进来

{

int ret;

dev_t dev_id= MKDEV(LED_MA, LED_MI); //把主次设备号合并生成设备ID

//1.注册设备号

ret =register_chrdev_region(dev_id,1,"test_led");

if(ret<0){

printk("regiser led fail\n ");

return -1;

}

//2.初始化字符设备

cdev_init(&led,&fops); //字符设备初始化

ret =cdev_add(&led,dev_id,1); //添加字符设备到系统中

if(ret<0){

printk("cdev add led fail\n ");

return -1;

}

led_res_con = pdev->resource[0].start;

led_res_dat = pdev->resource[1].start;

printk("led init go 1\n");

/*****************************************************/

key1_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

if (key1_res == NULL) {

printk("No resource !\n");

return -ENODEV;

}

ret = request_irq(key1_res->start, //硬件中断号 对应exynos4412-test4412.dts中test4412-key interrupts = <1 2>中的1

key_interrupt, //中断处理函数

key1_res->flags, //中断标志 IRQF_DISABLED 在表示中断处理时屏蔽掉其它所有中断

"key2", //中断名称 在cat /proc/interrupts 克看到

NULL);

if (ret < 0) {

printk("failed request irq: irqno = irq_res->start");

return ret;

}

printk("key irq init ok\n");

/*********************************************************/

return 0; //返回值为零表示运行成功 ,负值表示失败

}

void led_exit(void)

{

dev_t dev_id= MKDEV(LED_MA, LED_MI);

cdev_del(&led); //删除设备

unregister_chrdev_region(dev_id, 1); //取消注册

printk("led exit go\n");

}

//2.把内核模块的入口,改为platform_driver的入口

//module_init(led_init);

//module_exit(led_exit);

static const struct of_device_id machled[] = {

{ .compatible = "test,led3"}, //必须和设备树里的设备名字一样

{},

};

MODULE_DEVICE_TABLE(of, machled);

struct platform_driver led_platform_driver = {

.driver = {

.name = "test_led",

.owner = THIS_MODULE,

.of_match_table = of_match_ptr(machled),

},

.probe = led_init,

.remove = led_exit,

};

module_platform_driver(led_platform_driver); //声明led_platform_driver为平台设备驱动的加载入口

MODULE_LICENSE("Dual BSD/GPL");

接下来是测试代码:

#include <stdio.h>
#include <fcntl.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/ioctl.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/stat.h>

#define LED_MAGIC ‘L‘

//#define LED_ON 1

//#define LED_OFF 2

#define LED_ON _IOW(LED_MAGIC, 1, int)

#define LED_OFF _IOW(LED_MAGIC,2,int)

int flag = 0;

void input_handler (int signum)

{

printf("receive a signal from globalfifo, signalnum : %d\n",signum);

flag = 1;

}

int main(int argc, char **argv)

{

int fd = open("/dev/led", O_RDWR);

if (fd < 0) {

printf("open /dev/led fail\n");

return -1;

}

int oflags;

signal(SIGIO, input_handler); //让input_handler()处理SIGIO信号

fcntl(fd, F_SETOWN, getpid()); //设置设备文件的所有者为本进程

oflags = fcntl(fd, F_GETFL); // 会调用 驱动中的 .fasync

fcntl(fd, F_SETFL, oflags | FASYNC); //FASYNC 设置支持异步通知模式

while(1)

{

sleep(100);

if (flag)

{

ioctl(fd, LED_OFF); //ioctl 实现设备的个性化操作(可自定义命令)

printf("LED_OFF\n"); //注意要加\n 否则打印信息可能没有

flag = 0;

}

}

}

最后测试下来还是有一些小问题,后续再看;

原文地址:https://www.cnblogs.com/fanjuntao/p/11169525.html

时间: 2024-08-06 18:51:03

关于 exynos 4412 按键中断 异步通知的相关文章

按键驱动异步通知

在此以前,我们都是让应用程序主动去读按键的状态,有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧.这种情况在linux里的专业术语就叫异步通知. 在按键的例子中异步通知可以理解为:当按键按下时,驱动程序会提醒(即触发)应用程序(通过信号signal来实现). 举一个例子:进程之间发信号 原来我们常用  kill 这个命令 : kill       -9    pid   kill这个命令就是一个发信号 发送者  :   kill 接收者  :   pid 信

入门级的按键驱动——按键驱动笔记之poll机制-异步通知-同步互斥阻塞-定时器防抖

文章对应视频的第12课,第5.6.7.8节. 在这之前还有查询方式的驱动编写,中断方式的驱动编写,这篇文章中暂时没有这些类容.但这篇文章是以这些为基础写的,前面的内容有空补上. 按键驱动——按下按键,打印键值: 目录 概要 poll机制 异步通知 同步互斥阻塞 定时器防抖 概要: 查询方式: 12-3 缺点:占用CPU99%的资源.中断方式:12-4 缺点:调用read函数后如果没有按键按下,该函数永远不会结束,一直在等待按键按下. 优点:使用到了休眠机制,占用cpu资源极少.poll机制: 1

9.按键之使用异步通知

之前学的应用层都是: 1)查询方式:一直读 2)中断方式.同样一直读,直到中断进程唤醒 3)poll机制:一直在poll函数中睡眠,一定时间读一次 以上3种,我们都是让应用程序主动去读,本节我们学习异步通知,它的作用就是当驱动层有数据时,主动告诉应用程序,然后应用程序再来读, 这样,应用程序就可以干其它的事情,不必一直读 比如:kill -9 pid ,其实就是通过发信号杀死进程,kill发数据9给指定id号进程 1.怎么来收信号? 通过signal函数来实现获取信号,先来看看以下例子: 头函数

按键驱动程序(异步通知)

此驱动程序之前的按键驱动程序(中断方式)上加以优化.用到异步通知.对于内核来讲,既然用户想得到的是按键后的状态,那么自然不必时时都要read状态.当它检测到中断发生变主动通知用户,用户再来读.这样,用户空间.内核就可以着手干点其它的事情,而不必忙等按键按下或释放.那么就先从应用程序上面看. 怎么设置相关联到"异步通知"呢?flag = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, flag|FASYNC);这样的两句就可以将文件描述符fd与异步通知关联,到

字符设备驱动(七)按键异步通知

目录 按键驱动方式对比 进程间发信号 目标 如何让驱动通知应用 程序编写 驱动程序 应用程序 完整代码如下 测试 title: 字符设备驱动(七)按键异步通知 tags: linux date: 2018-11-24 16:39:47 toc: true --- 按键驱动方式对比 查询:耗资源 中断: 没有超时机制,当没有中断作为生产者,read函数一直休眠 poll机制,加入超时机制 上述三种都是app主动去获取按键,使用异步通知的形式可以使按键发生后,通知app去读取 进程间发信号 以前使用

Linux内核中断引入用户空间(异步通知机制)【转】

转自:http://blog.csdn.net/kingdragonfly120/article/details/10858647 版权声明:本文为博主原创文章,未经博主允许不得转载. 当Linux内核空间发生中断后怎么使用户空间的应用程序运行相应的函数呢,当芯片有数据到来时内核会产生一个中断,但是怎样通知应用程序来取数据,以前这个问题一直困扰我很长时间,后来发现linux中有异步通知机制,在用户程序中用signal注册一个响应SIGIO信号的回调函数,然后在驱动程序中向该进程发出SIGIO信号

异步通知

目录 更新记录 1.异步通知概念 2.异步通知机制 2.1 从应用程序的角度考虑 2.2 从驱动程序的角度考虑 2.3 小结 3.案列 参考 更新记录 version status description date author V1.0 C Create Document 2019.1.13 John Wan status: C―― Create, A-- Add, M-- Modify, D-- Delete. 注:内核版本 3.0.15 1.异步通知概念 ??异步通知:一旦设备就绪,则主动

字符设备驱动程序之异步通知(韦大仙)

读取按键的方法: (1)查询的方式:极度耗费资源 (2)中断的方式:如果没有按键按下,read函数会一直的等待 (3)poll机制的引入:可以指定超时时间 上述三种方式有一个共同点:应用程序主动的去查询. 问题:有没有一种方式当有按键按下时,驱动程序通知应用程序去读取.这就是本节所说的异步通知,该方式用信号的方式来实现的. 进程间发信号,例如: kill  -9  PID kill这个程序是发送者,进程号为PID的进程为接受者,9就是发送的信号.接下来引入signal函数: signal 函数是

字符设备驱动程序之异步通知

异步通知: 驱动程序的所谓异步通知,就是说并不是应用程序来对驱动程序操作的,而是驱动程序查询到有事件发生或者有数据发生变化的时候通知应用程序.角色发生了变化,应用程序由主动改为被动执行. 比如按键驱动: 1.有不断进行查询引脚状态的,CPU资源消耗非常的打: 2.有中断操作的,发生按键事件后采取执行相关事件处理函数,需要应用程序不断执行read函数,使得不能去干其它事情: 3.poll机制,改善了中断方式操作,在应用程序上当没有事件发生时,会跳去read函数继续执行其它的任务,知道有事件发生才返