linux中断和异步通知 基于QT210

linux异步通知:

应用程序需要完成如下三个步骤:

1signal(SIGIO, sig_handler);

调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。

2fcntl(fd, F_SET_OWNER, getpid());

指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。

3f_flags = fcntl(fd, F_GETFL);

fcntl(fd, F_SETFL, f_flags | FASYNC);

在设备文件中添加FASYNC标志,驱动中就会调用将要实现的test_fasync函数。

三个步骤执行后,一旦有信号产生,相应的进程就会收到。


内核需要完成下面四个步骤:

1)定义结构体fasync_struct

struct fasync_struct *async_queue;

2)实现test_fasync,把函数fasync_helperfd,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);

 }

4)完成ops

 struct file_operations test_fops = {

 .open = test_open,

 .release = test_close,

 .write = test_write,

 .read = test_read,

 .poll = test_poll,

 .fasync = test_fasync


补充:

在文件关闭时,即在设备驱动的release()函数中,应调用设备驱动的fasync()函数将文件从异步通知的列表

中删除

int xxx_release (struct inode *inode, struct file *filp)

{

struct xxx_dev *dev = filp->private_data;

xxx_fasync(-1, filp, 0);

...

return 0;

}



基于QT210和linux3.4.2设置如下:

配置内核:



参考原理图:


编译内核代码:


  1. #include <linux/types.h>   
  2. #include <linux/module.h>   
  3. #include <linux/cdev.h>   
  4. #include <linux/fs.h>   
  5. #include <linux/device.h>   
  6. #include <linux/gpio.h>   
  7. #include <linux/irq.h>   
  8. #include <linux/interrupt.h>   
  9. #include <linux/sched.h>    
  10. #include <linux/wait.h>   
  11. #include <linux/uaccess.h>   
  12. #include <mach/gpio.h>   
  13. #include <asm/uaccess.h>   
  14. #include <asm/irq.h>   
  15. #include <asm/io.h>   
  16. static dev_t devno;  
  17. static struct cdev cdev;  
  18. static struct class* buttons_class;  
  19. static struct device* buttons_device;  
  20.   
  21. static wait_queue_head_t button_waitq;  
  22. static struct timer_list buttons_timer;  
  23.   
  24. static volatile int pressed = 0;  
  25. static unsigned int key_val;  
  26.   
  27. static struct fasync_struct *button_async;  
  28.   
  29. struct key_desc{  
  30.     unsigned int  pin;  
  31.     unsigned char value;  
  32. };  
  33. static struct key_desc *irq_pd;  
  34.   
  35. static volatile unsigned long *gph3con;  
  36. static volatile unsigned long *gph3dat;  
  37. static struct key_desc key_descs[8] = {  
  38.     [0] = {  
  39.         .pin = S5PV210_GPH2(3),  
  40.         .value = 0x00,  
  41.     },  
  42.   
  43.     [1] = {  
  44.         .pin = S5PV210_GPH2(4),  
  45.         .value = 0x01,  
  46.     },  
  47.   
  48.     [2] = {  
  49.         .pin = S5PV210_GPH2(5),  
  50.         .value = 0x02,  
  51.     },  
  52.   
  53.     [3] = {  
  54.         .pin = S5PV210_GPH2(6),  
  55.         .value = 0x03,  
  56.     },  
  57.   
  58.     [4] = {  
  59.         .pin = S5PV210_GPH2(7),  
  60.         .value = 0x04,  
  61.     },  
  62. };  
  63. static void buttons_timer_function(unsigned long data)  
  64. {  
  65.     struct key_desc * pindesc = irq_pd;  
  66.     unsigned int pinval;  
  67.     if (!pindesc)  
  68.         return;  
  69.     pinval = gpio_get_value(pindesc->pin);  
  70.   
  71.     if (pinval)  
  72.     {  
  73.         /* 松开 */  
  74.         key_val = 0x80 | pindesc->value;  
  75.     }  
  76.     else  
  77.     {  
  78.         /* 按下 */  
  79.         key_val = pindesc->value;  
  80.     }  
  81.     pressed = 1;  
  82.     wake_up_interruptible(&button_waitq);  
  83.       
  84.     kill_fasync (&button_async, SIGIO, POLL_IN);  
  85. }  
  86.   
  87. static irqreturn_t buttons_irq(int irq, void *dev_id){  
  88.     printk("buttons_irq happen\n");  
  89.     /* 10ms后启动定时器 */  
  90.     irq_pd = (struct key_desc *)dev_id;  
  91.     mod_timer(&buttons_timer, jiffies+HZ/100);  
  92.     return IRQ_RETVAL(IRQ_HANDLED);  
  93. }  
  94.   
  95. static int buttons_open(struct inode *inode, struct file *file){  
  96.     int ret;  
  97.   
  98.       
  99.     ret = request_irq(IRQ_EINT(19),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key1", &key_descs[0]);  
  100.     if(ret)  
  101.         return ret;  
  102.     ret = request_irq(IRQ_EINT(20),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key2", &key_descs[1]);  
  103.     if(ret)  
  104.         return ret;  
  105.     ret = request_irq(IRQ_EINT(21),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", &key_descs[2]);  
  106.     if(ret)  
  107.         return ret;  
  108.     ret = request_irq(IRQ_EINT(22),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key4", &key_descs[3]);  
  109.     if(ret)  
  110.         return ret;  
  111.     ret = request_irq(IRQ_EINT(23),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key5", &key_descs[4]);  
  112.     if(ret)  
  113.         return ret;  
  114.     return 0;  
  115. }  
  116.   
  117. static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){  
  118.       
  119.     if (count != 1)  
  120.         return -EINVAL;  
  121.   
  122.     if (file->f_flags & O_NONBLOCK)  
  123.     {  
  124.         if (!pressed)  
  125.             return -EAGAIN;  
  126.     }  
  127.   
  128.     wait_event_interruptible(button_waitq, pressed);  
  129.     pressed = 0;  
  130.   
  131.     if(copy_to_user(data, &key_val, 1)){  
  132.         printk(KERN_ERR "The driver can not copy the data to user area!\n");  
  133.         return -ENOMEM;  
  134.     }  
  135.       
  136.     return 0;  
  137. }  
  138.   
  139. static int buttons_close(struct inode *inode, struct file *file){  
  140.     free_irq(IRQ_EINT(19),  &key_descs[0]);  
  141.     free_irq(IRQ_EINT(20),  &key_descs[1]);   
  142.     free_irq(IRQ_EINT(21),  &key_descs[2]);  
  143.     free_irq(IRQ_EINT(22),  &key_descs[3]);  
  144.     free_irq(IRQ_EINT(23),  &key_descs[4]);  
  145.     return 0;  
  146. }  
  147. static int buttons_fasync (int fd, struct file *filp, int on)  
  148. {  
  149.     printk("driver: buttons_fasync\n");  
  150.     return fasync_helper (fd, filp, on, &button_async);  
  151. }  
  152. struct file_operations buttons_ops = {  
  153.     .open    = buttons_open,  
  154.     .read    = buttons_read,  
  155.     .release = buttons_close,  
  156.     .fasync  = buttons_fasync,  
  157. };  
  158.   
  159. int buttons_init(void){  
  160.     int ret;  
  161.   
  162.     init_timer(&buttons_timer);  
  163.     buttons_timer.function = buttons_timer_function;  
  164.     //buttons_timer.expires  = 0;   
  165.     add_timer(&buttons_timer);   
  166.       
  167.     cdev_init(&cdev, &buttons_ops);  
  168.     cdev.owner = THIS_MODULE;  
  169.   
  170.     ret = alloc_chrdev_region(&devno, 0, 1, "buttons");  
  171.     if(ret){  
  172.         printk(KERN_ERR "alloc char device region faild!\n");  
  173.         return ret;  
  174.     }  
  175.   
  176.     ret = cdev_add(&cdev, devno, 1);  
  177.     if(ret){  
  178.         printk(KERN_ERR "add char device faild!\n");  
  179.         goto add_error;  
  180.     }  
  181.   
  182.     buttons_class = class_create(THIS_MODULE, "buttonsdrv");  
  183.     if(IS_ERR(buttons_class)){  
  184.         printk(KERN_ERR "create class error!\n");  
  185.         goto class_error;  
  186.     }  
  187.   
  188.     buttons_device = device_create(buttons_class, NULL, devno, NULL, "buttons");  
  189.     if(IS_ERR(buttons_device)){  
  190.         printk(KERN_ERR "create buttons device error!\n");  
  191.         goto device_error;  
  192.     }  
  193.   
  194.     init_waitqueue_head(&button_waitq);  
  195.     gph3con = (volatile unsigned long *)ioremap(0xE0200C60, 16);  
  196.     gph3dat = gph3con + 1;  
  197.   
  198.     *gph3con &= (~0x000000ff);  
  199.     *gph3con |=0x11;  
  200.     *gph3dat &= ~0x03;    
  201.   
  202.       
  203.     printk("buttons init\n");  
  204.     return 0;  
  205.   
  206. device_error:  
  207.     class_destroy(buttons_class);  
  208. class_error:  
  209.     cdev_del(&cdev);  
  210. add_error:  
  211.     unregister_chrdev_region(devno,1);  
  212.   
  213.     return -ENODEV;  
  214. }  
  215.   
  216. void buttons_exit(void){  
  217.     printk("buttons exit\n");  
  218.     device_destroy(buttons_class, devno);  
  219.     class_destroy(buttons_class);  
  220.     cdev_del(&cdev);  
  221.     unregister_chrdev_region(devno, 1);  
  222. }  
  223.   
  224. module_init(buttons_init);  
  225. module_exit(buttons_exit);  
  226. MODULE_LICENSE("GPL");  
#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>
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;

struct key_desc{
	unsigned int  pin;
	unsigned char value;
};
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");

编译用户测试代码:

  1. #include <fcntl.h>   
  2. #include <stdio.h>   
  3. #include <poll.h>   
  4. #include <signal.h>   
  5. #include <sys/types.h>   
  6. #include <unistd.h>   
  7. #include <fcntl.h>   
  8.   
  9.   
  10. int fd;   
  11.   
  12. void sig_handler(int signum)  
  13. {  
  14.     unsigned char key_val;  
  15.     read(fd, &key_val, 1);   
  16.     printf("key_val: 0x%x\n", key_val);  
  17. }  
  18.   
  19. int main(int argc, char **argv)  
  20. {  
  21.     unsigned char key_val;  
  22.     int ret;  
  23.     int Oflags;  
  24.   
  25.     signal(SIGIO, sig_handler);  
  26.   
  27.     fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);  
  28.     if (fd < 0){   
  29.         printf("can't open!\n");  
  30.         return -1;   
  31.     }     
  32.   
  33.     fcntl(fd, F_SETOWN, getpid());  
  34.     Oflags = fcntl(fd, F_GETFL);  
  35.     fcntl(fd, F_SETFL, Oflags | FASYNC);  
  36.   
  37.     while(1);  
  38.   
  39.     return 0;  
  40. }  
#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;
}

测试结果如下:

  1. [210_Liujia]#insmod buttons.ko  
  2. [210_Liujia]#./buttons_test  
  3. key_val: 0x1  
  4. key_val: 0x81  
  5. key_val: 0x0  
  6. key_val: 0x80  
  7. key_val: 0x2  
  8. key_val: 0x82  
  9. key_val: 0x3  
  10. key_val: 0x83  
  11. key_val: 0x4  
  12. key_val: 0x84  
  13. key_val: 0x1  
  14. key_val: 0x81  
  15. key_val: 0x2  
  16. key_val: 0x82  
  17. key_val: 0x4  
  18. key_val: 0x84  
  19. key_val: 0x3  
  20. key_val: 0x83  
[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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值