驱动对应用的异步通知机制
1.应用程序需要完成如下三个步骤:
(1)signal(SIGIO, sig_handler);
调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。
(2)fcntl(fd, F_SET_OWNER, getpid());
指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。
(3)f_flags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, f_flags | FASYNC);
在设备文件中添加FASYNC标志,驱动中就会调用将要实现的test_fasync函数。
三个步骤执行后,一旦有信号产生,相应的进程就会收到。
2.驱动需要完成下面四个步骤:
(1)定义结构体fasync_struct。
struct fasync_struct *async_queue;
(2)实现test_fasync,把函数fasync_helper将fd,filp和定义的结构体传给内核。
int test_fasync (int fd, struct file *filp, int mode)
{
struct _test_t *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
(3)当设备可写时,调用函数kill_fasync发送信号SIGIO给内核。
if (dev->async_queue){
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
}
3.驱动代码
#include <linux/types.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/gpio.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/wait.h> #include <linux/uaccess.h> #include <mach/gpio.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> struct key_desc{ unsigned int pin; unsigned char value; }; static dev_t devno; static struct cdev cdev; static struct class* buttons_class; static struct device* buttons_device; static wait_queue_head_t button_waitq; static struct timer_list buttons_timer; static volatile int pressed = 0; static unsigned int key_val; static struct fasync_struct *button_async; static struct key_desc *irq_pd; static volatile unsigned long *gph3con; static volatile unsigned long *gph3dat; static struct key_desc key_descs[8] = { [0] = { .pin = S5PV210_GPH2(3), .value = 0x00, }, [1] = { .pin = S5PV210_GPH2(4), .value = 0x01, }, [2] = { .pin = S5PV210_GPH2(5), .value = 0x02, }, [3] = { .pin = S5PV210_GPH2(6), .value = 0x03, }, [4] = { .pin = S5PV210_GPH2(7), .value = 0x04, }, }; static void buttons_timer_function(unsigned long data) { struct key_desc * pindesc = irq_pd; unsigned int pinval; if (!pindesc) return; pinval = gpio_get_value(pindesc->pin); if (pinval) { /* 松开 */ key_val = 0x80 | pindesc->value; } else { /* 按下 */ key_val = pindesc->value; } pressed = 1; wake_up_interruptible(&button_waitq); kill_fasync (&button_async, SIGIO, POLL_IN); } static irqreturn_t buttons_irq(int irq, void *dev_id){ printk("buttons_irq happen\n"); /* 10ms后启动定时器 */ irq_pd = (struct key_desc *)dev_id; mod_timer(&buttons_timer, jiffies+HZ/100); return IRQ_RETVAL(IRQ_HANDLED); } static int buttons_open(struct inode *inode, struct file *file){ int ret; ret = request_irq(IRQ_EINT(19), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key1", &key_descs[0]); if(ret) return ret; ret = request_irq(IRQ_EINT(20), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key2", &key_descs[1]); if(ret) return ret; ret = request_irq(IRQ_EINT(21), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", &key_descs[2]); if(ret) return ret; ret = request_irq(IRQ_EINT(22), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key4", &key_descs[3]); if(ret) return ret; ret = request_irq(IRQ_EINT(23), buttons_irq, IRQ_TYPE_EDGE_BOTH, "key5", &key_descs[4]); if(ret) return ret; return 0; } static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){ if (count != 1) return -EINVAL; if (file->f_flags & O_NONBLOCK) { if (!pressed) return -EAGAIN; } wait_event_interruptible(button_waitq, pressed); pressed = 0; if(copy_to_user(data, &key_val, 1)){ printk(KERN_ERR "The driver can not copy the data to user area!\n"); return -ENOMEM; } return 0; } static int buttons_close(struct inode *inode, struct file *file){ free_irq(IRQ_EINT(19), &key_descs[0]); free_irq(IRQ_EINT(20), &key_descs[1]); free_irq(IRQ_EINT(21), &key_descs[2]); free_irq(IRQ_EINT(22), &key_descs[3]); free_irq(IRQ_EINT(23), &key_descs[4]); return 0; } static int buttons_fasync (int fd, struct file *filp, int on) { printk("driver: buttons_fasync\n"); return fasync_helper (fd, filp, on, &button_async); } struct file_operations buttons_ops = { .open = buttons_open, .read = buttons_read, .release = buttons_close, .fasync = buttons_fasync, }; int buttons_init(void){ int ret; init_timer(&buttons_timer); buttons_timer.function = buttons_timer_function; //buttons_timer.expires = 0; add_timer(&buttons_timer); cdev_init(&cdev, &buttons_ops); cdev.owner = THIS_MODULE; ret = alloc_chrdev_region(&devno, 0, 1, "buttons"); if(ret){ printk(KERN_ERR "alloc char device region faild!\n"); return ret; } ret = cdev_add(&cdev, devno, 1); if(ret){ printk(KERN_ERR "add char device faild!\n"); goto add_error; } buttons_class = class_create(THIS_MODULE, "buttonsdrv"); if(IS_ERR(buttons_class)){ printk(KERN_ERR "create class error!\n"); goto class_error; } buttons_device = device_create(buttons_class, NULL, devno, NULL, "buttons"); if(IS_ERR(buttons_device)){ printk(KERN_ERR "create buttons device error!\n"); goto device_error; } init_waitqueue_head(&button_waitq); gph3con = (volatile unsigned long *)ioremap(0xE0200C60, 16); gph3dat = gph3con + 1; *gph3con &= (~0x000000ff); *gph3con |=0x11; *gph3dat &= ~0x03; printk("buttons init\n"); return 0; device_error: class_destroy(buttons_class); class_error: cdev_del(&cdev); add_error: unregister_chrdev_region(devno,1); return -ENODEV; } void buttons_exit(void){ printk("buttons exit\n"); device_destroy(buttons_class, devno); class_destroy(buttons_class); cdev_del(&cdev); unregister_chrdev_region(devno, 1); } module_init(buttons_init); module_exit(buttons_exit); MODULE_LICENSE("GPL");
4.用户空间代码:
#include <fcntl.h> #include <stdio.h> #include <poll.h> #include <signal.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fd; void sig_handler(int signum) { unsigned char key_val; read(fd, &key_val, 1); printf("key_val: 0x%x\n", key_val); } int main(int argc, char **argv) { unsigned char key_val; int ret; int Oflags; signal(SIGIO, sig_handler); fd = open("/dev/buttons", O_RDWR | O_NONBLOCK); if (fd < 0){ printf("can't open!\n"); return -1; } fcntl(fd, F_SETOWN, getpid()); Oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, Oflags | FASYNC); while(1); return 0; }
5.测试结果:
[210_Liujia]#insmod buttons.ko [210_Liujia]#./buttons_test key_val: 0x1 key_val: 0x81 key_val: 0x0 key_val: 0x80 key_val: 0x2 key_val: 0x82 key_val: 0x3 key_val: 0x83 key_val: 0x4 key_val: 0x84 key_val: 0x1 key_val: 0x81 key_val: 0x2 key_val: 0x82 key_val: 0x4 key_val: 0x84 key_val: 0x3 key_val: 0x83
转载:
本文参考链接:https://www.cnblogs.com/hellokitty2/p/9074631.html