以下是驱动测试代码:

//内核的驱动代码

#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;

}

}

}

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

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

  1. Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知(转)

    信号  ( signal ) 机制是 UNIX 系统中最为古老的进程间通信机制,很多条件可以产生一个信号. 信号的产生: 1,当用户按下某些按键时,产生信号. 2,硬件异常产生信号:除数为 0 ,无效 ...

  2. 嵌入式Linux驱动学习之路(十三)按键驱动-异步通知

    之前的按键方式: 查询: 极度占用CPU资源 中断: 在读的时候产生休眠,在没有信号的时候永远不会返回. poll机制: 在中断的基础上加上超时时间. 异步通知就是通过信号来传送. 首先在应用程序中有 ...

  3. Linux学习 :按键信号 之 异步通知

    一.异步通知概念: 异步通知是指:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态,类似于中断的概念,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进 ...

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

    文章对应视频的第12课,第5.6.7.8节. 在这之前还有查询方式的驱动编写,中断方式的驱动编写,这篇文章中暂时没有这些类容.但这篇文章是以这些为基础写的,前面的内容有空补上. 按键驱动——按下按键, ...

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

    转自:http://blog.csdn.net/kingdragonfly120/article/details/10858647 版权声明:本文为博主原创文章,未经博主允许不得转载. 当Linux内 ...

  6. liunx驱动----异步通知

    查询:消耗资源 中断:read 一直要去读 poll :指定起始时间 异步通知 signal 测试程序 include <stdio.h> include <signal.h> ...

  7. Linux驱动之异步通知的应用

    前面的按键驱动方式都是应用程序通过主动查询的方式获得按键值的: 1.查询方式 2.中断方式 3.poll机制 下面介绍第四种按键驱动的方式 4.异步通知:它可以做到应用程序不用随时去查询按键的状态,而 ...

  8. Linux之异步通知20160702

    异步通知,主要说的是使用信号的方式,同时使用信号也是实现进程之间通信的一种方式. 多的不说,我们直接看代码: 首先应用程序的: #include <sys/types.h> #includ ...

  9. linux驱动的异步通知(kill_fasync,fasync)---- 驱动程序向应用程序发送信号

    应用程序 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include < ...

随机推荐

  1. 洛谷 P1144 最短路计数 题解

    P1144 最短路计数 题目描述 给出一个\(N\)个顶点\(M\)条边的无向无权图,顶点编号为\(1-N\).问从顶点\(1\)开始,到其他每个点的最短路有几条. 输入格式 第一行包含\(2\)个正 ...

  2. .NET总结--ASP.NET工作原理

    前言 前前后后写了不少关于某些技术啥的博客,一直在追新求深,而真正使用上的时候才发现了解的太少太少了,从事.net开发三年有余了不是它不行了而是我坚持不住了,如今不得不向生活低头,这个系列作为三年技术 ...

  3. linux高性能服务器编程 (四) --TCP/IP通信案例

    第四章 TCP/IP通信案例 HTTP代理服务器的大致工作原理        在HTTP通信链上,客户端和服务器之间通常存在某些中转代理服务器.它们提供对目标资源的中转访问.一个HTTP请求可能被多个 ...

  4. 使用helm进行kubernetes包管理

    1. 安装helm package https://github.com/helm/helm/blob/master/LICENSE 2. 将 helm 配置到环境变量 3. 使用helm的前提是安装 ...

  5. Cross-channel Communication Networks

    Cross-channel Communication Networks 2019-12-13 14:17:18 Paper: https://papers.nips.cc/paper/8411-cr ...

  6. Metasploit使用内网跳板, 扫描局域网主机

    最近,拿到一台内网机器, 苦于无法使用nmap扫描改主机的内网, 所以才有此文 在跳板机子获取一定权限后,需要积极的向内网主机权限发展,获取指定的目标信息,探查系统漏洞,借助msf已经得到的meter ...

  7. 【MySQL】Mysql模糊查询like提速优化

    一般情况下like模糊查询的写法为(field已建立索引): SELECT `column` FROM `table` WHERE `field` like '%keyword%'; 上面的语句用ex ...

  8. 如何用 Go 实现热重启

    热重启 热重启(Zero Downtime),指新老进程无缝切换,在替换过程中可保持对 client 的服务. 原理 父进程监听重启信号 在收到重启信号后,父进程调用 fork ,同时传递 socke ...

  9. 【转载】 tf.Print() (------------ tensorflow中的print函数)

    原文地址: https://blog.csdn.net/weixin_36670529/article/details/100191674 ------------------------------ ...

  10. Java学习-058-Jsoup爬虫获取中国所有的三级行政区划数据(三),处理二级编码缺失

    通过查看数据可知,直辖市或者某些三级行政区域没有对应的二级区域,为方便后续的地址使用,可自定义缺失的二级地址. 如下示例自定义的二级行政区域的名称为一级区域的名称,对应的源码如下所示: 将此段源码添加 ...