linux内核err实现,Linux内核中断引入用户空间(异步通知机制)【转】

当Linux内核空间发生中断后怎么使用户空间的应用程序运行相应的函数呢,当芯片有数据到来时内核会产生一个中断,但是怎样通知应用程序来取数据,以前这个问题一直困扰我很长时间,后来发现linux中有异步通知机制,在用户程序中用signal注册一个响应SIGIO信号的回调函数,然后在驱动程序中向该进程发出SIGIO信号便完成该功能,下面是该功能具体实施方法:

1.在驱动中定义一个static struct fasync_struct *async;

2.在fasync系统调用中注册fasync_helper(fd, filp, mode, &async);

3.在中断服务程序(顶半部、底半部都可以)发出信号kill_fasync(&async, SIGIO, POLL_IN);

4.在用户应用程序中用signal注册一个响应SIGIO的回调函数signal(SIGIO, sig_handler);

5.通过fcntl(fd, F_SETOWN, getpid())将将进程pid传入内核

6.通过fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC)设置异步通知

驱动部分代码:

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define DEVICE_NAME "mybeep"

volatile unsigned long *GPBCON;

volatile unsigned long *GPBDAT;

volatile unsigned long *GPBUP;

void beep_start(void);

void beep_stop(void);

int  beep_irq_register(void);

unsigned int flag=1;

static struct fasync_struct *async; //声明fasync_struct

struct key_irq_desc {

unsigned int irq;

int pin;

int pin_setting;

int number;

char *name;

};

static int beep_fasync(int fd, struct file *filp, int mode)

{

printk("application  fasync!

");

return fasync_helper(fd, filp, mode, &async);         //注册上层调用进程的信息,上层调用fcntl设置FASYNC会调用这个系统调用

}

static struct key_irq_desc key_irqs [] = {

{IRQ_EINT8, S3C2410_GPG(0), S3C2410_GPG0_EINT8, 0, "KEY1"},

};

static irqreturn_t key_interrupt(int irq, void *dev_id)

{

kill_fasync(&async, SIGIO, POLL_IN);  //向打开设备文件的进程发出SIGIO信号

return (IRQ_HANDLED);

}

void beep_gpiob_init(void)

{

*GPBCON&=~((1<<0)|(1<<1));

*GPBCON|=(1<<0);

*GPBUP&=~(1<<0);

}

void beep_start(void)

{

*GPBDAT|=(1<<0);

}

void beep_stop(void)

{

*GPBDAT&=~(1<<0);

}

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

{

if(beep_irq_register() != 0)

{

printk("Request irq error!

");

}

printk(KERN_ALERT "application  open!

");

return 0;

}

ssize_t beep_read(struct file *file, char __user *buff, size_t count, loff_t *offp)

{

printk("application  read!

");

return 0;

}

ssize_t beep_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)

{

printk("application  write!

");

return 0;

}

static int beep_release(struct inode *inode, struct file *file)

{

disable_irq(key_irqs[0].irq);

free_irq(key_irqs[0].irq, (void *)&key_irqs[0]);

printk("application  close!

");

return beep_fasync(-1, file, 0);

}

static int beep_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

switch(cmd)

{

case 0:

beep_start();

break;

case 1:

beep_stop();

break;

default:

break;

}

return 0;

}

static struct file_operations beep_ops = {

.owner = THIS_MODULE,

.open = beep_open,

.release = beep_release,

.ioctl = beep_ioctl,

.read = beep_read,

.write = beep_write,

.fasync = beep_fasync,

};

static struct miscdevice beep_misc = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &beep_ops,

};

int beep_irq_register(void)

{

int err;

err = request_irq(key_irqs[0].irq, key_interrupt, 0, key_irqs[0].name, (void *)&key_irqs[0]);

set_irq_type(key_irqs[0].irq, IRQ_TYPE_EDGE_RISING);

if(err)

{

disable_irq(key_irqs[0].irq);

free_irq(key_irqs[0].irq, (void *)&key_irqs[0]);

return -EBUSY;

}

return 0;

}

static int __init beep_init(void)

{

int ret;

ret=misc_register(&beep_misc);

if(ret <0)

{

printk("register miscdevice error code:%d

",ret);

return ret;

}

printk("beep device create!

");

GPBCON=(volatile unsigned long *)ioremap(0x56000010,12);

GPBDAT=GPBCON+1;

GPBUP=GPBCON+2;

beep_gpiob_init();

return 0;

}

static void __exit beep_exit(void)

{

iounmap(GPBCON);

misc_deregister(&beep_misc);

printk("beep device delete!

");

}

MODULE_LICENSE("GPL");

MODULE_AUTHOR("kingdragonfly");

module_init(beep_init);

module_exit(beep_exit);

用户应用程序代码:

#include 

#include 

#include 

#include 

void sig_handler(int sig)

{

if(sig == SIGIO)

{

printf("Receive io signal from kernel!

");

}

}

int main(void)

{

int fd;

signal(SIGIO, sig_handler);

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

fcntl(fd, F_SETOWN, getpid());

fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);

printf("waiting key interrupt:

");

while(1)

{

}

}

当内核里发生中断时在中断服务程序中发出SIGIO信号从而自动调用相应的回调函数,在回调函数中可以进行相应处理。

上面程序在mini2440开发板实现了按K1键,用户程序自动调用void sig_handler(int sig)功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值