美文网首页
异步信号 kill

异步信号 kill

作者: 大神华仔 | 来源:发表于2016-06-24 11:41 被阅读0次
    • 客户端

      • 要点三( 设置信号SIGIO的处理)
        1. 设置信号处理方法(当中断型号来之后自动跳到catch_signal( ) 函数执行
          signal(SIGIO, catch_signal);
        2. 设置信号的属主进程
          fcntl(fd, F_SETOWN, getpid());
        3. 将读写模式设置成异步模式
          unsigned int flag = fcntl(fd, F_GETFL, 0);
          fcntl(fd, F_SETFL, flag | FASYNC);

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <linux/input.h>
    #include <poll.h>
    #include <signal.h>
    
    
    struct key_event{
        int  code ; // 按键的键值, 比如KEY_DOWN,  KEY_POWER
        int value; // 按键的状态,按下为1, 抬起为0
    };
    
    static int fd;
    
    void catch_signal(int signo)
    {
        int ret;
    
        struct key_event event;
        if(signo == SIGIO)
        {
            printf("we got a SIGIO\n");
            ret = read(fd, &event, sizeof(struct key_event));
            if(ret < 0)
            {
                perror("read");
                exit(1);
            }
    
            if(event.code == KEY_POWER)
            {
                if(event.value)
                {
                    printf(" key power pressed\n");
                }else
                {
                    printf(" key power up\n");
                }
            }
            if(event.code == KEY_ENTER)
            {
                if(event.value)
                {
                    printf(" key enter pressed\n");
                }else
                {
                    printf(" key enter up\n");
                }
            }
        }   
    
        printf("-----------------signal handled end\n");
    }
    
    
    int main(int argc, char *argv[])
    {
    
       // int fd;
    
        int ret;
        char kbbuf[128];
    
        fd = open("/dev/key1", O_RDWR);
        if(fd < 0)
        {
            perror("open");
            exit(1);
        }
    
        //  需要设置信号SIGIO的处理
        // 1,设置信号处理方法
        signal(SIGIO, catch_signal);
        // 2,设置信号的属主进程
        fcntl(fd, F_SETOWN, getpid());
        //3, 将读写模式设置成异步模式
        unsigned int flag = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, flag | FASYNC);
    
    
        //做其他的事情
        while(1){
            sleep(1);
            printf("I am very bored\n");
        }
    
        
        close(fd);
    
        return 0;
    }
    


    • 驱动端

      • 要的四
        1. 初始化等待队列头 (在初始化的时候)
          wait_queue_head_t wq_head; //定义变量
          init_waitqueue_head(&key_dev->wq_head);
        2. 发送信号 (在中断函数中后部)
          wake_up_interruptible(&key_dev->wq_head);//先唤醒
          2.1 发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用 程序的SIGIO信号处理函数
          kill_fasync(&key_dev->key_fasync, SIGIO, POLLIN);//再发送数据
        3. 区分阻塞还是非阻塞 (在 .read( ) 中前部)(key_dev->have_data在中断函数中,为假是执行返回 -EAGAIN)
          if((filp->f_flags & O_NONBLOCK ) && !key_dev->have_data)
          return -EAGAIN;
        4. 没有数据就休眠--have_data如果0表示没有数据,就需要等(在 .read( ) 中前部,key_dev->have_data为真是执行)
          wait_event_interruptible(key_dev->wq_head, key_dev->have_data);
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/slab.h>
    #include <linux/cdev.h>
    #include <linux/device.h>
    #include <linux/gpio.h>
    #include <linux/interrupt.h>
    #include <linux/input.h>
    #include <linux/wait.h>
    #include <linux/sched.h>
    #include <linux/poll.h>
    
    #include <asm/uaccess.h>
    #include <asm/io.h>
    
    
    // 设计一个表示按键数据的对象
    struct key_event{
        int  code ; // 按键的键值, 比如KEY_DOWN,  KEY_POWER
        int value; // 按键的状态,按下为1, 抬起为0
    };
    
    // 面向对象---将任何都看成对象, struct 就是对象
    //设计一个对象类型,描述当前的设备信息,同时是一个全局的设备对象
    struct s5pv210_key{
        int dev_major; //用老的注册设备号的方式
        struct class *cls;
        struct device *dev;
        int irqno; //表示设备的中断号码
        int testdata;
        struct key_event event;//存放按键的数据
        wait_queue_head_t wq_head;
        int have_data; //表示标志位,表示是否有数据
        struct fasync_struct  *key_fasync; //指向一个被分配之后的struct fasync_struct空间
        struct tasklet_struct mytasklet;
    };
    
    
    
    
    
    //设计一个对象,描述是按键的信息
    /*
    1, 中断号
        2, gpio号码
        3, 名字
        4, 按键的类型
    */
    struct key_info{
        char *name;
        int irqno;
        int gpionum;
        int code;
        int flags;  //触发方式
    };
    //设置所有按键的信息
    struct key_info  allkeys[] = {
        [0] = {
            .name = "key1_eint0",
            .irqno = IRQ_EINT(0),
            .gpionum = S5PV210_GPH0(0),
            .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
            .code = KEY_UP,
        },
    
        [1] = {
            .name = "key2_eint1",
            .irqno = IRQ_EINT(1),
            .gpionum = S5PV210_GPH0(1),
            .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
            .code = KEY_DOWN,
        },
        [2] = {
            .name = "key3_eint2",
            .irqno = IRQ_EINT(2),
            .gpionum = S5PV210_GPH0(2),
            .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
            .code = KEY_LEFT,
                    },
        [6] = {
            .name = "key7_eint22",
            .irqno = IRQ_EINT16_31,
            .gpionum = S5PV210_GPH2(6),
            .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
            .code = KEY_HOME,
        },
        [7] = {
            .name = "key8_eint23",
            .irqno = IRQ_EINT16_31,
            .gpionum = S5PV210_GPH2(7),
            .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
            .code = KEY_POWER,
        },
    };
    
    
    //设置对象
    struct  s5pv210_key  *key_dev;
    
    int key_drv_open(struct inode *inode, struct file *filp)
    {
        //一般也是做初始化动作
        printk("-------^_^   %s-----------\n", __FUNCTION__);
    
        memset(&key_dev->event,0, sizeof(struct key_event));
        key_dev->have_data = 0;
    
        return 0;
    
    }
    
    // write(fd, buf, size);
    ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
    {
    
    
        return 0;
    
    }
    int key_drv_close(struct inode *inode, struct file *filp)
    {
        printk("-------^_^   %s-----------\n", __FUNCTION__);
    
        fasync_helper(-1, filp, 0, &key_dev->key_fasync);//释放key_dev->key_fasync
    
        return 0;
    
    }
    
    
    long key_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
    {
    
        
        return 0;
    
    }
    
    
    ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos)
    {
        printk("-------^_^   %s------have= %d-----\n", __FUNCTION__, key_dev->have_data);
        int ret;
        
        //区分阻塞还是非阻塞
        if((filp->f_flags & O_NONBLOCK ) &&  !key_dev->have_data)
            return -EAGAIN;
        
        // 没有数据就休眠--have_data如果0表示没有数据,就需要等
        wait_event_interruptible(key_dev->wq_head, key_dev->have_data);
    
        ret = copy_to_user(buf, &key_dev->event, count);
        if(ret > 0)
        {
            printk("copy_to_user error\n");
            return -EFAULT;
        }
    
        // 清空后,接着去收其他的数据
        memset(&key_dev->event,0, sizeof(struct key_event));
        key_dev->have_data = 0; // 重新设置成没有数据
    
        
        return count;
    
    }
    
    
    unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
    {
        printk("-------^_^   %s-----------\n", __FUNCTION__);
        unsigned int  mask = 0;
        
        // 将当前的等待队列注册到vfs中
        poll_wait(filp, &key_dev->wq_head, pts);
    
    
        //如果有数据的时候,返回一个POLLIN
        if(key_dev->have_data)
                mask |= POLLIN;
    
        return mask;
    }
    
    int key_drv_fasync (int fd, struct file *filp, int on)
    {
        //调用一个fasync_helper,  构建struct fasync_struct,描述信号的信息(信号是给谁的)
    
        return fasync_helper(fd, filp,  on, &key_dev->key_fasync);
    
    }
    
    
    const struct file_operations  key_fops = {
        .open = key_drv_open,
        .write = key_drv_write,
        .read = key_drv_read,
        .release = key_drv_close,
        .unlocked_ioctl = key_drv_ioctl,
        .poll = key_drv_poll,
        .fasync = key_drv_fasync,
    };
    
    
    void tasklet_half_irq_handle(unsigned long data)
    {
        printk("-------^_^   %s-----------\n", __FUNCTION__);
        wake_up_interruptible(&key_dev->wq_head);//会唤醒
        key_dev->have_data = 1; //表示有数据
    
        ///发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用程序的SIGIO信号处理函数
        kill_fasync(&key_dev->key_fasync, SIGIO, POLLIN);
        
    }
    
    
    
    irqreturn_t key_irq_handler(int irqno, void *dev_id)
    {
    
        printk("-------^_^   %s-----------\n", __FUNCTION__);
    
        //区分不同的中断
        struct key_info  *p = (struct key_info  *)dev_id;
    
        //区分是按下还是抬起
        int value;
    
    
        value = gpio_get_value(p->gpionum);
        
        if(value){
            //抬起
            printk("%s  up \n", p->name);
            key_dev->event.code = p->code;
            key_dev->event.value = 0;
    
        }else{
            //按下    
            printk("%s  pressed \n", p->name);
            key_dev->event.code =  p->code;
            key_dev->event.value = 1;
        }
    
        //启动下半部
        tasklet_schedule(&key_dev->mytasklet);
        
        return IRQ_HANDLED;
    }
    
    
    
    static  int __init key_drv_init(void)
    {
        int ret;
        //申请资源
        // 实例化该对象
        //  GFP_KERNEL如果当前没有内存可分配,该函数会一直等
        key_dev = kzalloc(sizeof(struct s5pv210_key), GFP_KERNEL);
        if(key_dev == NULL)
        {
            printk(KERN_ERR "kzalloc error\n");
            return -ENOMEM;
        }
        // 1,  申请设备号
        key_dev->dev_major = register_chrdev(0, "s5pv210_key_drv", &key_fops);
        if(key_dev->dev_major < 0)
        {
            printk(KERN_ERR "kzalloc error\n");
            ret = -ENODEV;
            goto err_0;
        }
    
        
        // 2, 自动创建文件
        //  /sys/class/key_cls 文件夹
        key_dev->cls = class_create(THIS_MODULE, "key_cls");
        if(IS_ERR(key_dev->cls))
        {
            printk(KERN_ERR "class_create error\n");
            ret = PTR_ERR(key_dev->cls);
            goto err_1;
        }
    
        //  /sys/class/key_cls/key/
        //  /dev/key1
        key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,1),NULL, "key1");
        if(IS_ERR(key_dev->dev))
        {
            printk(KERN_ERR "device_create error\n");
            ret = PTR_ERR(key_dev->dev);
            goto err_2;
        }
    
    
        // 4, 硬件的初始化---中断
        //
        //key_dev->irqno = IRQ_EINT(1);
    
        int i;
        int irqno;
        int flags;
        char *name;
        for(i=0; i<ARRAY_SIZE(allkeys); i++)
        {
            irqno = allkeys[i].irqno;
            if(irqno == IRQ_EINT16_31)
                    irqno = gpio_to_irq(allkeys[i].gpionum);
    
            flags = allkeys[i].flags;
            name = allkeys[i].name;
            ret = request_irq(irqno, key_irq_handler, flags,name, &allkeys[i]);
            if(ret != 0)
            {
                printk(KERN_ERR "request_irq error  : i=%d\n", i);
                ret = -EBUSY;
                goto err_4;
            }
            
        }
        
        //初始化等待队列头
        init_waitqueue_head(&key_dev->wq_head);
    
        // 初始化tasklet,为下半部做准备
        tasklet_init(&key_dev->mytasklet,tasklet_half_irq_handle, 34);
        
        return 0;
    
    err_4:
        i--;
        for(; i>0; i--)
        {
            irqno = gpio_to_irq(allkeys[i].gpionum);
            free_irq(irqno, &allkeys[i]);
        }
        
    err_3:
        device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));
    err_2:
        class_destroy(key_dev->cls);
    
    err_1:
        unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");
        
    err_0:
        kfree(key_dev);
        return ret;
    
    }
    
    
    static void __exit  key_drv_exit(void)
    {
        //释放资源
        int i;
        int irqno;
        for(i=0; i<ARRAY_SIZE(allkeys); i++)
        {   
            irqno = gpio_to_irq(allkeys[i].gpionum);
            free_irq(irqno, &allkeys[i]);
        }
        device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));
        class_destroy(key_dev->cls);
        unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");
        
        kfree(key_dev);
    }
    
    
    
    module_init(key_drv_init);
    module_exit(key_drv_exit);
    MODULE_LICENSE("GPL");
    
    

    相关文章

      网友评论

          本文标题:异步信号 kill

          本文链接:https://www.haomeiwen.com/subject/dquodttx.html