7. linux 驱动异步编程

TOC

1. 相关接口和结构体

接口

//初始化接口
int fasync _ helper(int fd, struct file *filp, int mode, struct
fasync _ struct **fa);


//释放信号接口
void kill _ fasync(struct fasync _ struct **fa, int sig, int band);

结构体


//文件操作结构体
static const struct file_operations fops = 
{
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_release,
    //.read = hello_read,
    //.write = hello_write,
    .fasync = hello_fasync,
    .release = hello_release,
   // .unlocked_ioctl = hello_ioctl,
};

需要编写接口 int hello_fasync(int fd, struct file *flip, int mode)int hello_release(struct inode *pnode, struct file *pfile) 并注册到上述结构体中。

2. 驱动代码示例

使用定时器定时发送SIGIO信号给应用层

#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 <linux/cdev.h>  
#include <linux/device.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/sched.h> 




#define HELLO_CNT   1  


//主设备号为0,表示动态分配设备号 
dev_t dev = 0;
static int major = 0;   
static int minor = 0;

static struct cdev *hello_cdev[HELLO_CNT];
static struct class *hello_class = NULL;
static struct class_device * hello_class_dev[HELLO_CNT];


static struct timer_list tm;
static struct fasync_struct *async = NULL;


int hello_open(struct inode * pnode, struct file * pfile)
{
    printk("open file..
");
    int num = MINOR(pnode->i_rdev);
    if(num >= HELLO_CNT)
    {
        return -ENODEV;
    }

    pfile->private_data = hello_cdev[num];

    return 0;
}




int hello_fasync(int fd, struct file *flip, int mode)
{
    printk("set fasync..");
    return fasync_helper(fd, flip, mode, &async);
}


int hello_release(struct inode *pnode, struct file *pfile)
{
    printk("release file ..
");


    return hello_fasync(-1, filp, 0);
}




//文件操作结构体
static const struct file_operations fops = 
{
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_release,
    //.read = hello_read,
    //.write = hello_write,
    .fasync = hello_fasync,
    .release = hello_release,
   // .unlocked_ioctl = hello_ioctl,
};


static void setup_cdev(int index)
{
    int err, devno = MKDEV(major, index);

    cdev_init(hello_cdev[index], &fops);
    hello_cdev[index]->owner = THIS_MODULE;
    hello_cdev[index]->ops = &fops;
    err = cdev_add(hello_cdev[index], devno, 1);
    if(err)
    {
        printk(KERN_NOTICE "Error %d adding hello%d", err, index);
    }
}




void call_back(unsigned long val)
{
    printk("timer is out!!
");
    //使用信号通知上层应用
    if (async)
    {
        kill_fasync(&async, SIGIO, POLL_IN);
        printk("send SIGIO to app!!
");
    }


    //重新注册定时器
    tm.expires = jiffies + 2 * HZ;
    add_timer(&tm);
}



static int __init hello_init(void)
{
    //申请设备号,动态or静态
    int ret = 0;
    if(major)
    {
        //为字符设备静态申请第一个设备号
        dev = MKDEV(major, minor);
        ret = register_chrdev_region(dev, HELLO_CNT, "hello");
    }
    else
    {
        //为字符设备动态申请一个设备号
        ret = alloc_chrdev_region(&dev, minor, HELLO_CNT, "hello");
        major = MAJOR(dev);
    }


    //构造cdev设备对象
    int i = 0;
    for(i = 0; i < HELLO_CNT; ++i)
    {
        hello_cdev[i] = cdev_alloc();


    }


    //初始化设备对象    
    for(minor = 0; minor < HELLO_CNT; ++minor)
    {
        setup_cdev(minor);
    }

    hello_class = class_create(THIS_MODULE, "hello");
    for(minor = 0; minor < HELLO_CNT; ++minor)
    {
        hello_class_dev[minor] = device_create(hello_class, NULL, MKDEV(major, minor), NULL, "hello%d",minor);
    }


    //初始化定时器
    init_timer(&tm);
    tm.function = call_back;
    tm.expires = jiffies + 2 * HZ;
    add_timer(&tm);

    return 0;
}




static void __exit hello_exit(void)
{
    for(minor = 0; minor < HELLO_CNT; ++minor)
    {
        device_destroy(hello_class, MKDEV(major, minor));
    }
    class_destroy(hello_class);


    //从内核注销cdev设备对象
    cdev_del(hello_cdev);

    //回收设备号
    unregister_chrdev_region(dev, HELLO_CNT);


    //注销定时器
    del_timer(&tm);
}


module_init(hello_init);  
module_exit(hello_exit);  


MODULE_LICENSE("GPL"); 

3. 应用层测试代码

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>


#define DEV_NAME ("/dev/hello0")


void signal_handle(int num)
{
     printf("Get SIGIO Signal from kernel!
");
     printf("I need to do something!!
");
}


int main(int argc, char **argv)
{
    int fd = -1;
    int flags = -1;


    //注册信号捕获函数
    signal(SIGIO, signal_handle);


    fd = open(DEV_NAME, O_RDWR);
    if(fd < 0)
    {
        printf("can't find dev:%s
", DEV_NAME);
        return -1;
    }

    //将驱动发出的异步信号绑定到本进程
    fcntl(fd, F_SETOWN, getpid());
    flags = fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, flags | FASYNC);


    while(1)
    {
        sleep(1);
    }


    return 0;
}

原文地址:https://www.cnblogs.com/standardzero/p/12551079.html