Linux 嵌入式驱动开发异步通知

文章目录

        • 1. 概念
        • 2. 通知流程
        • 3. 驱动
        • 4. APP

1. 概念

信号类似于硬件层面的中断,相当于软件层次上的中断

不同的信号相当于中断号,分别需要实现一个 信号处理函数

不可被忽略信号:SIGKILL(9)SIGSTOP(19)

2. 通知流程
  1. 应用程序实现并注册一个信号处理函数
  2. 应用程序将 current 进程号告知内核
  3. 应用程序获取当前进程状态并开启当前进程异步通知
  4. 驱动程序初始化 fasync 结构体
  5. 满足通知条件,如:中断发生,按键触发有效
  6. 手动向应用程序发出信号,如:SIGIO、POLLIN
  7. 触发应用程序信号处理函数
3. 驱动
  1. 定义 fasync_struct 结构体指针变量

    /* 可在设备结构体里定义 */
    struct fasync_struct xxx_fasync_struct;
    
  2. 使用异步通知,需要在设备驱动中实现 file_operations 操作集中的 fasync 函数

    /* fasync 函数原型 */
    int (*fasync) (int fd, struct file *filp, int on)
    
    /* file operations */
    static struct file_operations key_fops = {
    	...
        .fasync         = xxx_fasync,	/* 异步通知操作函数 */
    	...
    };
    
  3. fasync 函数里面一般通过调用 fasync_helper 函数来初始化前面定义的 fasync_struct 结构体指针

    /* fasync_helper 函数原型 */
    int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp);
    
    /* 异步通知操作函数 */
    static int xxx_fasync(int fd, struct file *filp, int on)
    {
        int ret = 0;
        struct xxx_dev *dev = filp->private_data;
    
        /* 初始化 fasync 结构体 */
        ret = fasync_helper(fd, filp, on, &dev->xxx_fasync_struct);
        if(ret < 0) {
            printk("Init fasync_struct failed!\r\n");
            return -EIO;
        }
        return 0;
    }
    
  4. 在关闭驱动文件的时候需要在 file_operations 操作集中的 release 函数中释放 fasync_struct

    /* 同样使用异步通知操作函数 xxx_fasync 释放异步通知 */
    static int xxx_release(struct inode *inode, struct file *filp)
    {
        return xxx_fasync(-1, filp, 0); /* 删除异步通知 */
        								/* 注意参数 */
    }
    
  5. 当设备可以访问的时候,驱动程序使用 kill_fasync 函数负责发送指定的信号

    /* 函数原型 */
    /*
     * fp:		要操作的 fasync_struct
     * sig:		要发送的信号,如 SIGIO
     * band:	可读时设置为 POLL_IN,可写时设置为 POLL_OUT
     */
    void kill_fasync(struct fasync_struct **fp, int sig, int band);
    
4. APP
  1. signal 注册信号处理函数

    /* 函数原型 */
    /*
     * signum:	要处理的信号,如 SIGIO
     * handler:	信号处理函数
     */
    sighandler_t signal(int signum, sighandler_t handler);
    
  2. 实现一个信号处理函数

    /* 示例 */
    static void xxx_signal_handler(int signum)
    {...}
    
  3. fcntl 将本应用程序的进程号告诉给内核

    /*
     * fd:			文件描述符
     * F_SETOWN:	文件设置本身
     * getpid():	获取本进程 pid
     */
    fcntl(fd, F_SETOWN, getpid());
    
  4. 开启异步通知

    /*
     * F_GETFL:	获取文件标志
     * F_SETFL:	设置文件标志
     * FASYNC:	异步通知标志
     */
    /* 获取当前的进程状态 */
    flags = fcntl(fd, F_GETFL);	
    /* 开启当前进程异步通知功能 */
    fcntl(fd, F_SETFL, flags | FASYNC);		
    

你可能感兴趣的:(arm,嵌入式硬件,stm32,c语言)