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

时间:2023-03-08 18:25:02

之前的按键方式:

查询:  极度占用CPU资源

中断:  在读的时候产生休眠,在没有信号的时候永远不会返回。

poll机制:  在中断的基础上加上超时时间。

异步通知就是通过信号来传送。

首先在应用程序中有一个信号处理函数,在应用程序接收到信号时会自动调用信号处理函数。

驱动程序为应用程序提供设置信号量的接口。fcntl函数,会调用到fasync函数

fcntl(fd,F_SETOWN,getpid());     //F_SETOWN告诉内核自己的pid

oflags = fcntl(fd,F_GETFL);      //改变fasync标记

fcntl(fd,F_SETFL,oflags|FASYNC);

驱动模块文件:

#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/fs.h>
#include <asm/arch/regs-gpio.h>
#include <linux/interrupt.h>
#include <linux/poll.h> static struct class *key_class;       //创建类
static struct class_device *key_class_devs; //创建类对应的设备 struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[] = {
{S3C2410_GPF0,0X01},
{S3C2410_GPF2,0X02},
{S3C2410_GPG3,0X03},
{S3C2410_GPG11,0X04},
};
unsigned char keyvals=; static volatile int ev_press = ;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static struct fasync_struct *key_async_queue; static irqreturn_t keys_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)
{
keyvals = pindesc->key_val|0x80;
}
else
{
keyvals = pindesc->key_val;
}
ev_press = ;
wake_up_interruptible(&button_waitq); kill_fasync (&key_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED;
} int key_open(struct inode *inode, struct file *fp)
{
request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[]);
request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[]);
request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[]);
request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[]);
return ;
} ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){ if(count != )
{
return -EINVAL;
}
wait_event_interruptible(button_waitq,ev_press); copy_to_user(buff,&keyvals,);
ev_press = ;
return ;
} ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){
} int key_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0,&pins_desc[]);
free_irq(IRQ_EINT2,&pins_desc[]);
free_irq(IRQ_EINT11,&pins_desc[]);
free_irq(IRQ_EINT19,&pins_desc[]);
} static unsigned int key_poll(struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = ;
poll_wait(file, &button_waitq,wait);
if(ev_press)
mask |= POLLIN|POLLRDNORM;
return mask;
} static int key_fsync (int fd, struct file *filp, int on)
{return fasync_helper (fd, filp, on, &key_async_queue);    //on则内核自动给key_async_queue分配空间并初始化结构体
} struct file_operations led_fops={
.owner = THIS_MODULE,
.open = key_open,
.write = key_write,
.read = key_read,
.release = key_close,
.poll = key_poll,
.fasync = key_fsync,
}; int major;
static int key_init(void)
{
major = register_chrdev( ,"key_drv", &led_fops );
key_class = class_create(THIS_MODULE,"key_class");
key_class_devs = class_device_create(key_class,NULL,MKDEV(major,),NULL,"my_keys"); printk("key install Module\n");
return ;
} static void key_exit(void)
{
unregister_chrdev( major, "key_drv" );
class_device_unregister(key_class_devs);
class_destroy(key_class);
printk("key Module exit\n");
} module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");

测试程序代码:

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h> int fd; void my_signal( int s )
{
static char key_val;
read(fd,&key_val,);
printf("key_val:%d\n",key_val);
}
int main( int argc, char **argv )
{
int oflags;
signal(SIGIO, my_signal);
fd = open("/dev/my_keys",O_RDWR); fcntl(fd,F_SETOWN,getpid());     //告诉内核自己的pid
oflags = fcntl(fd,F_GETFL);      //改变fasync标记
fcntl(fd,F_SETFL,oflags|FASYNC); if(fd<)
{
printf("open failed\n");
return ;
} while()
{
sleep();
} return ;
}

sd