以下是驱动测试代码:

//内核的驱动代码

#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

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

  1. 按键中断异步通知实现

    大体上跟windows的消息处理机制差不多 app所要做的事情 1.绑定信号处理函数 2.通知驱动该程序的pid,好让驱动能够通过pid返回信号 3.设置异步标志位 驱动程序所要做的事情: 1.添加. ...

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

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

  3. linux. qt信号崩溃,【创龙AM4379 Cortex-A9试用体验】之I/O中断异步通知驱动程序+QT捕获Linux系统信号+测试信号通知...

    2.驱动程序 安装字符设备驱动程序开发流程开发. 2.1资源定义 定义按键I/O端口号.I/O中断号,以及字符设备的主设备号变量: #define GPIO_KEY1_PIN_NUM (3*32 + ...

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

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

  5. Exynos 4412 看门狗定时器中断

    如果想弄懂看门狗定时器中断,要掌握下面两个知识点: 1 懂寄存器 Cortex A9采用的是ARM官方规定的中断处理机制 有两大类寄存器决定了中断工作状态 1) exynos 4412 特有的寄存器( ...

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

    如果要实现:平时应用程序处于休眠状态,当按下按键时,驱动告诉应用程序由状态改变,需要读取按键状态了.那么就需要建立驱动和应用程序之间的通信. 应用函数中的某个函数怎么使用,需要包含哪些头文件,可以在服 ...

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

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

  8. 异步通知实验(信号)

    目录 异步通知 异步通知简介 驱动中的信号处理 应用程序对异步通知的处理 硬件原理图分析 实验程序编写 修改设备树文件 程序编写 编写测试APP 运行测试 编译驱动程序和测试APP 运行测试 在前面使 ...

  9. i.MX6ULL终结者Linux异步通知实验编写实验程序

    文章目录 1 驱动程序编写 2 应用测试程序 3 运行测试 1 驱动程序编写 本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/13_key_signal 驱动程序在key_po ...

  10. linux驱动开发学习笔记二十一:异步通知

    一.异步通知简介 我们首先来回顾一下"中断",中断是处理器提供的一种异步机制,我们配置好中断以后就可以让处理器去处理其他的事情了,当中断发生以后会触发我们事先设置好的中断服务函数, ...

最新文章

  1. 厦大计算机研究生和福大,考研:只知道厦门大学?福建还有这些211值得你了解...
  2. 世界欠他一个图灵奖! LSTM之父的深度学习“奇迹之年”
  3. Android使用AudioRecord录制pcm音频原始数据以及使用AudioTrack播放
  4. MIMIC 以太坊医疗项目开发(4)Axios
  5. vim编写代码时,文件末尾会多一个换行符的解决办法
  6. 04需求工程软件建模与分析阅读笔记之四
  7. 蜂鸟智游大数据:“人在囧途”的春运,航空公司们可操碎了心
  8. linux下编译为知笔记,为知笔记 Linux 版安装
  9. skynet.fork_Apache Ant 1.10.6发布–用于junitlauncher的fork模式以及新的jmod和链接任务
  10. 使用Python进行汽车黑客攻击:泄露GPS和OBDIICAN总线数据
  11. 1.4部署到IIS「深入浅出ASP.NET Core系列」
  12. 防计算机病毒的重点,计算机病毒防范技术重点措施(1).doc
  13. RTl8188EUS设置ap模式
  14. 家用带宽-路由器的选择
  15. 跨境电商shopee这个平台怎么样?百万shopee卖家笑了,不要再犹豫了
  16. 有点意思!用Python 一键群发soul消息找对象
  17. 详解1M宽带下载速度?1M等于多少kb?
  18. 宝宝培养 IOS APP 上线
  19. DeFCN debug记录(训练过程),以及对cvpods框架的分析
  20. springCloud-day04

热门文章

  1. WCF Data Services查询
  2. [WM]怎么让应用程序更省电
  3. 「代码随想录」213.打家劫舍II 【动态规划】力扣详解!
  4. 「leetcode」108. 构造二叉搜索树【递归】【迭代】详解!
  5. 2014 找工作总结
  6. Navicat Premium 15 for Mac(数据库管理工具)支持Big Sur
  7. My PaintBrush Pro for mac(专业的绘图画板)
  8. 开发工具Charles for Mac(信息抓取) v4.6.3b1
  9. 2019校招Android面试题解1.0
  10. 利用whistle调试移动端页面