linux 驱动之input子系统(gpio-keys)实现
linux 驱动之input子系统(gpio-keys)实现
野火相关input 子系统说明
中断说明
中断最重要属性就是响应必须及时,而实际实现中中断处理过程往往比较费事,这将会影响后续中断响应。为了解决这个问题,因此提出中断上下部的概念,将中断处理过程分为两部分:
上部分:处理过程比较快。不会占用很长时间的放在上半部。
下半部:处理过程比较耗时操作放在下半部。
1、中断上下部设计思路
2、如果要处理的内容不希望被其他中断打断,那么可以放到上半部。
3、如果要处理的任务对时间敏感,可以放到上半部。
4、如果要处理的任务与硬件有关,可以放到上半部。
5、除了上述三点以外的其他任务,优先考虑放到下半部。
6、中断上下部设计
中断处理函数可以作为中断上半部,而下半部 Liunx 内核提供多种机制:
软中断
tasklet
中断和应用层沟通
内核空间和用户空间数据的交互主要有三种方式
1、copy_to_user()
2、信号
3、netlink
4、Linux内核中断引入用户空间(异步通知机制)
异步通知
驱动处理
fasync函数
1.如果要使用异步通知,需要在设备驱动中实现fops中的fasync函数
2.当设备可以访问的时候,驱动程序需要向应用程序发出信号,相当于产生”中断“。kill_fastync函数负责发送指定的信号,kill_fastync函数。
应用处理
1、注册信号处理函数
2、将本应用程序的进程号告诉内核
3、开启异步通知
flags = fcntl(fd,F_GETEL);//获取当前的进程状态
fcntl(fd,F_SETEL,flags | FASYNC);//开启当前进程异步通知功能
重点就是通过fcntl函数设置进程状态为FASYNC,经过这一步,驱动程序中的fasync函数就会执行
例子
驱动代码
struct irqkey_dev
{
dev_t devid;
...
struct fasync_struct *async_queue;
};
void timer_function(unsigned long arg)
{
unsigned char value;
...
//一次完成的按键过程
if(atomic_read(&dev->releasekey))
{
if(dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
}
}
static int key_fasync(int fd, struct file *filp, int on)
{
printk(KERN_EMERG "key_fasync enter!\n");
struct irqkey_dev *dev = (struct irqkey_dev *)filp->private_data;
return fasync_helper(fd, filp, on, &dev->async_queue);
}
static int key_release(struct inode *inode,struct file *filp)
{
printk(KERN_EMERG "key_release enter!\n");
return key_fasync(-1, filp, 0);
}
————————————————
版权声明:本文为CSDN博主「爱吃肉的大高个」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a568713197/article/details/103145834
应用代码
static void sigio_signal_func(int signum)
{
int err = 0;
unsigned int keyvalue = 0;
err = read(fd, &keyvalue, sizeof(keyvalue));
if(err < 0)
{
}
else
{
printf("SIGIO signal! key value = %d\r\n",keyvalue);
}
}
const char default_path[] = "/dev/input/by-path/platform-gpio-keys-event";
int main(int argc, char *argv[])
{
...
/*open device*/
fd = open(filename, O_RDWR);
if(fd < 0)
{
printf("Can't open file %s\r\n", filename);
return -1;
}
printf("Open file %s OK!\r\n", filename);
signal(SIGIO, sigio_signal_func);
fcntl(fd, F_SETOWN, getpid());
flags = fcntl(fd, F_GETFD);
fcntl(fd, F_SETFL, flags | FASYNC);
while(1)
{
sleep(2);
}
}
————————————————
版权声明:本文为CSDN博主「爱吃肉的大高个」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a568713197/article/details/103145834