Linux中断异步通知笔记

来源:互联网 发布:mysql 统计字符串长度 编辑:程序博客网 时间:2024/05/01 22:18

异步通知笔记

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

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。

static struct fasync_struct *button_async;

2)实现t fifth_drv_fasync,把函数fasync_helper将fd,filp和定义的结构体传给内核。

static int fifth_drv_fasync (int fd, struct file *filp, int on)

{

         printk("driver:fifth_drv_fasync\n");

         return fasync_helper (fd,filp, on, &button_async);

}

3)当设备可写时,调用函数kill_fasync发送信号SIGIO给内核。

kill_fasync(&button_async, SIGIO, POLL_IN);

4)完成ops

 structfile_operations test_fops = {

 .open =test_open,

 .release =test_close,

 .write =test_write,

 .read =test_read,

 .poll =test_poll,

 .fasync =test_fasync

 

以下是部分代码

内核驱动代码

#include<linux/module.h>

#include<linux/kernel.h>

#include<linux/fs.h>

#include<linux/init.h>

#include<linux/delay.h>

#include<linux/irq.h>

#include<asm/uaccess.h>

#include<asm/irq.h>

#include<asm/io.h>

#include<asm/arch/regs-gpio.h>

#include<asm/hardware.h>

#include<linux/poll.h>

 

 

staticstruct class *fifthdrv_class;

staticstruct class_device        *fifthdrv_class_dev;

 

volatileunsigned long *gpfcon;

volatileunsigned long *gpfdat;

 

volatileunsigned long *gpgcon;

volatileunsigned long *gpgdat;

 

 

staticDECLARE_WAIT_QUEUE_HEAD(button_waitq);

 

/*中断事件标志, 中断服务程序将它置1,fifth_drv_read将它清0 */

staticvolatile int ev_press = 0;

 

staticstruct fasync_struct *button_async;

 

 

structpin_desc{

         unsigned int pin;

         unsigned int key_val;

};

 

 

/*键值: 按下时, 0x01, 0x02, 0x03, 0x04 */

/*键值: 松开时, 0x81, 0x82, 0x83, 0x84 */

staticunsigned char key_val;

 

structpin_desc pins_desc[4] = {

         {S3C2410_GPF0, 0x01},

         {S3C2410_GPF2, 0x02},

         {S3C2410_GPG3, 0x03},

         {S3C2410_GPG11, 0x04},

};

 

 

/*

  * 确定按键值

  */

staticirqreturn_t buttons_irq(int irq, void *dev_id)

{

         struct pin_desc * pindesc = (structpin_desc *)dev_id;

         unsigned int pinval;

        

         pinval =s3c2410_gpio_getpin(pindesc->pin);

 

         if (pinval)

         {

                   /* 松开 */

                   key_val = 0x80 |pindesc->key_val;

         }

         else

         {

                   /* 按下 */

                   key_val =pindesc->key_val;

         }

 

    ev_press = 1;                  /* 表示中断发生了 */

    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

        

         kill_fasync (&button_async, SIGIO,POLL_IN);

        

         return IRQ_RETVAL(IRQ_HANDLED);

}

 

staticint fifth_drv_open(struct inode *inode, struct file *file)

{

         /* 配置GPF0,2为输入引脚 */

         /* 配置GPG3,11为输入引脚 */

         request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2",&pins_desc[0]);

         request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3",&pins_desc[1]);

         request_irq(IRQ_EINT11, buttons_irq,IRQT_BOTHEDGE, "S4", &pins_desc[2]);

         request_irq(IRQ_EINT19, buttons_irq,IRQT_BOTHEDGE, "S5", &pins_desc[3]);         

 

         return 0;

}

 

ssize_tfifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)

{

         if (size != 1)

                   return -EINVAL;

 

         /* 如果没有按键动作, 休眠 */

         wait_event_interruptible(button_waitq,ev_press);

 

         /* 如果有按键动作, 返回键值 */

         copy_to_user(buf, &key_val, 1);

         ev_press = 0;

        

         return 1;

}

 

 

intfifth_drv_close(struct inode *inode, struct file *file)

{

         free_irq(IRQ_EINT0, &pins_desc[0]);

         free_irq(IRQ_EINT2, &pins_desc[1]);

         free_irq(IRQ_EINT11,&pins_desc[2]);

         free_irq(IRQ_EINT19,&pins_desc[3]);

         return 0;

}

 

staticunsigned fifth_drv_poll(struct file *file, poll_table *wait)

{

         unsigned int mask = 0;

         poll_wait(file, &button_waitq,wait); // 不会立即休眠

 

         if (ev_press)

                   mask |= POLLIN | POLLRDNORM;

 

         return mask;

}

 

staticint fifth_drv_fasync (int fd, struct file *filp, int on)

{

         printk("driver:fifth_drv_fasync\n");

         return fasync_helper (fd, filp, on,&button_async);

}

 

 

staticstruct file_operations sencod_drv_fops = {

    .owner  =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

    .open   =  fifth_drv_open,    

         .read         =     fifth_drv_read,           

         .release =  fifth_drv_close,

         .poll   =  fifth_drv_poll,

         .fasync     =  fifth_drv_fasync,

};

 

 

intmajor;

staticint fifth_drv_init(void)

{

         major = register_chrdev(0,"fifth_drv", &sencod_drv_fops);

 

         fifthdrv_class =class_create(THIS_MODULE, "fifth_drv");

 

         fifthdrv_class_dev =class_device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL,"buttons"); /* /dev/buttons */

 

         gpfcon = (volatile unsigned long*)ioremap(0x56000050, 16);

         gpfdat = gpfcon + 1;

 

         gpgcon = (volatile unsigned long*)ioremap(0x56000060, 16);

         gpgdat = gpgcon + 1;

 

         return 0;

}

 

staticvoid fifth_drv_exit(void)

{

         unregister_chrdev(major,"fifth_drv");

         class_device_unregister(fifthdrv_class_dev);

         class_destroy(fifthdrv_class);

         iounmap(gpfcon);

         iounmap(gpgcon);

         return 0;

}

 

 

module_init(fifth_drv_init);

 

module_exit(fifth_drv_exit);

 

MODULE_LICENSE("GPL");

 

 

测试应用程序

 

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

#include<poll.h>

#include<signal.h>

#include<sys/types.h>

#include<unistd.h>

#include<fcntl.h>

 

 

/*fifthdrvtest

  */

intfd;

 

voidmy_signal_fun(int signum)

{

         unsigned char key_val;

         read(fd, &key_val, 1);

         printf("key_val: 0x%x\n",key_val);

}

 

intmain(int argc, char **argv)

{

         unsigned char key_val;

         int ret;

         int Oflags;

 

         signal(SIGIO, my_signal_fun);

        

         fd = open("/dev/buttons",O_RDWR);

         if (fd < 0)

         {

                   printf("can'topen!\n");

         }

 

         fcntl(fd, F_SETOWN, getpid());

        

         Oflags = fcntl(fd, F_GETFL);

        

         fcntl(fd, F_SETFL, Oflags | FASYNC);

 

 

         while (1)

         {

                   sleep(1000);

         }

        

         return 0;

}

 

 

 

0 0