概述
目的:按下按键时驱动程序通知应用程序
1、大体框架:
1、应用程序:注册信号处理函数
2、驱动程序发送信号
3、应用程序通知驱动 PID
4、驱动程序发送如何发送信号
2、需要的操作:
为了使设备获得异步通知机制,驱动程序中涉及如下操作:
- 支持F_SETOWN 命令,能在这个命令处理中设置filp->f_owner为对应进程ID,这个工作已经由内核完成了。
- 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行,驱动中应该实现fasync()函数
- 在设备获得资源时,调用kill_fasync()函数激发相应的信号。
3、驱动程序编写:
1、在file_operations结构中添加:
.fasync = button_dev_fasync,
2、完成这个异步通知函数:
static int button_dev_fasync(int fd,struct file *filp,int on)
{
printk("button_dev_fasync
n");
return fasync_helper(fd,filp,on,&button_async);
}
初始化 button_async
3、驱动程序发送信号:
kill_fasync(&button_async,SIGIO,POLL_IN);
button_async的定义如下:
static struct fasync_struct *button_async;
4、驱动程序编写:
fcntl(fd, F_SETOWN,getpid());//告诉内核发给谁
/*改变FASYNC标志,最终会调用驱动的button_dev_fasync函数*/
Oflags = fcntl(fd,F_GETFL);//
fcntl(fd,F_SETFL,Oflags|FASYNC);//
Oflags = fcntl(fd,F_GETFL);//
fcntl(fd,F_SETFL,Oflags|FASYNC);//
这两个函数会调用驱动的button_dev_fasync函数,从而调用fasync_helper函数,初始化或者释放button_async结构体
5、完整驱动代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/irqs.h>//这个在/opt/EmbedSky/linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach 路径
#include <linux/interrupt.h>
#include <linux/poll.h>
MODULE_LICENSE("Dual BSD/GPL");
static struct class *buttondrv_class;
static struct class_devices *buttondrv_class_dev;
/*
*/
static DECLARE_WAIT_QUEUE_HEAD(button_wait_q);
/*中断事件标志,中断服务程序将他置1,read函数将他置0*/
static volatile int ev_press =0;
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
static unsigned keyval;
static struct fasync_struct *button_async;
struct pin_desc{
unsigned int pin;
unsigned int key_value;
};
/*按键按下时是:0x01 0x02 0x03 0x04*/
/*按键松开时是:0x81 0x82 0x83 0x84*/
struct pin_desc pins_desc[4] =
{
{S3C2410_GPF1,0x01},
{S3C2410_GPF4,0x02},
{S3C2410_GPF2,0x03},
{S3C2410_GPF0,0x04},
};
/*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
struct pin_desc * pindesc = (struct pin_desc *) dev_id;
unsigned int pinval;
pinval = s3c2410_gpio_getpin(pindesc -> pin);
if(pinval)//松开
{
keyval = 0x80|pindesc->key_value;
}
else
{
keyval = pindesc->key_value;
}
ev_press =1;//中断发生
wake_up_interruptible(&button_wait_q);
kill_fasync(&button_async,SIGIO,POLL_IN);
return IRQ_HANDLED;
}
static int button_dev_open(struct inode *inode ,struct file* file)
{
//配置按键的引脚 GPF0,1,2,4为输入引脚
request_irq(IRQ_EINT1,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key1",&pins_desc[0]);
request_irq(IRQ_EINT4,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key2",&pins_desc[1]);
request_irq(IRQ_EINT2,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key3",&pins_desc[2]);
request_irq(IRQ_EINT0,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key4",&pins_desc[3]);
return 0;
}
ssize_t button_dev_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
{
if(size !=1)
{
return -EINVAL;
}
/*如果没有按键动作发生
就休眠*/
wait_event_interruptible(button_wait_q,ev_press);
/*如果有按键动作发生,直接返回*/
copy_to_user(buf,&keyval,1);
ev_press = 0;
return 0;
}
int button_dev_close(struct inode* inode ,struct file *file)
{
free_irq(IRQ_EINT1,&pins_desc[0]);
free_irq(IRQ_EINT4,&pins_desc[1]);
free_irq(IRQ_EINT2,&pins_desc[2]);
free_irq(IRQ_EINT0,&pins_desc[3]);
return 0;
}
static int button_dev_fasync(int fd,struct file *filp,int on)
{
printk("button_dev_fasync
n");
return fasync_helper(fd,filp,on,&button_async);
}
static struct file_operations button_sdv_fops =
{
.owner
= THIS_MODULE,
.open
= button_dev_open,
.read
= button_dev_read,
.release
= button_dev_close,
.fasync
= button_dev_fasync,
};
int major;
static int button_dev_init(void)//入口函数
{
major = register_chrdev(0,"button_drv",&button_sdv_fops);
buttondrv_class = class_create(THIS_MODULE,"button_drv");
if(IS_ERR(buttondrv_class))
return PTR_ERR(buttondrv_class);
buttondrv_class_dev= device_create(buttondrv_class,NULL,MKDEV(major,0),NULL,"wq_button");
if(unlikely(IS_ERR(buttondrv_class_dev)))
return PTR_ERR(buttondrv_class_dev);
/*映射物理地址*/
gpfcon = (volatile unsigned long *) ioremap(0x56000050 ,16);
gpfdat = gpfcon + 1;
return 0;
}
static void button_dev_exit(void)
{
unregister_chrdev(major,"button_drv");
device_unregister(buttondrv_class_dev);
class_destroy(buttondrv_class);
iounmap(gpfcon);
}
module_init(button_dev_init);
module_exit(button_dev_exit);
6、完整测试代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
int fd;
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd,&key_val,1);
printf("key_val: 0x%xn",key_val);
}
int main(int argc, char **argv)
{
int ret=0;
int Oflags;
unsigned char key_val;
signal(SIGIO,my_signal_fun);
fd = open("/dev/wq_button", O_RDWR);
if(fd<0)
{
printf("can't open n");
}
fcntl(fd, F_SETOWN,getpid());//告诉内核发给谁
/*改变FASYNC标志,最终会调用驱动的button_dev_fasync函数*/
Oflags = fcntl(fd,F_GETFL);//
fcntl(fd,F_SETFL,Oflags|FASYNC);//
while(1)
{
sleep(1000);
}
return 0;
}
最后
以上就是勤奋大地为你收集整理的linux驱动程序之增加按键异步通知机制目的:按下按键时驱动程序通知应用程序的全部内容,希望文章能够帮你解决linux驱动程序之增加按键异步通知机制目的:按下按键时驱动程序通知应用程序所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复