驱动对应用的异步通知机制

发布者:ArtisticSoul最新更新时间:2025-02-08 来源: cnblogs关键字:驱动  S5PV210 手机看文章 扫描二维码
随时随地手机看文章

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

#include

#include

#include

#include gpio.h>

#include

#include

#include  

#include

#include

#include

#include

#include

#include


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 happenn');

    /* 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_fasyncn');

    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 initn');

    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 exitn');

    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

#include

#include

#include

#include

#include

#include



int fd; 


void sig_handler(int signum)

{

    unsigned char key_val;

    read(fd, &key_val, 1); 

    printf('key_val: 0x%xn', 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


关键字:驱动  S5PV210 引用地址:驱动对应用的异步通知机制

上一篇:【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
下一篇:代码示例_中断

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved