zoukankan      html  css  js  c++  java
  • 阻塞型驱动设计

    一、
      当应用程序要对某个资源进行访问的时候,如果这个资源没有或者说被占用,这个应用程序就要进入阻塞状态,在linux系统中它会进入一个内核等待队列,等到被唤醒之后才能运行。这就是阻塞机制,它对一个驱动程序来说是很重要和必要的。
    二、如何使用等待队列
      1、定义等待队列
        wait_queue_head_t    name;
      2、初始化等待队列
        init_waitqueue_head    (&name); 
      1&2、定义+初始化等待队列
        DECLARE_WAIT_QUEUE_HEAD    (name);
        突然想到立白皂液洗护合一新升级。。什么鬼。。
      3、进入等待队列,睡眠
        wait_event    (queue,condition);
        参数:
          queue,要加入到等待队列的队列名称
          condition,若非0,则跳过这个函数,若为0,则将调用这个函数的应用程序挂在到等待队列queue中
      4、从等待队列中唤醒
        wake_up    (wait_queue_t    *q);
        将等待队列q中的所有进程唤醒,然后经过调度来运行某一进程
    三、在按键驱动程序中的应用

      在读取数据的函数中加入等待的函数,因为读取数据可能会遭遇阻塞,没有按键按下时,key_num为0,进入等待队列,等待唤醒。一次按键过后清除键值。在中断操作函数中加入唤醒函数,因为中断是按键引起的,一旦进入中断则肯定有按键被按下。

      key.h: 

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/miscdevice.h>
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    #include <linux/sched.h>

    #define GPGCON 0x56000060 #define GPGDAT 0x56000064 unsigned int *gpio_config,*gpio_data; /*定义工作项结构体*/ struct work_struct *work1; /*定义定时器变量结构体*/ struct timer_list key_timer; unsigned int key_num = 0; /*定义等待队列*/ wait_queue_head_t key_queue;

    键盘中断驱动程序:

      

    #include "key.h"
    
    /********************
    函数名:work1_func
    参数:无
    返回值:无
    函数功能:实现工作项
    结构体中的func成员
    ********************/
    void work1_func()
    {
        /*启动定时器*/
        mod_timer(&key_timer,jiffies + (HZ/10));
    }
    
    /************************
    函数名:que_init
    参数:无
    返回值:无
    函数功能:创建一个工作项
    *************************/
    int que_init()
    {
        /*创建工作*/
        work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
    
        INIT_WORK(work1, work1_func);
    }
    
    /************************
    函数名:key_int
    参数:无
    返回值:0
    函数功能:按键中断处理函数
    *************************/
    irqreturn_t key_int(int irq, void *dev_id)
    {
        /*1、检测设备是否产生中断*/
    
        /*2、清除中断产生标志*/
    
        /*3、提交下半部分工作*/
        schedule_work(work1);
    
        return 0;
    }
    
    /************************
    函数名:key_hw_init
    参数:无
    返回值:无
    函数功能:初始化与按键相关
    的寄存器
    *************************/
    void key_hw_init()
    {
        unsigned int data; 
        gpio_config = ioremap(GPGCON,4);
        gpio_data = ioremap(GPGDAT,4);
        data = readw(gpio_config);
        data &= ((3)|(3<<6)|(3<<10)|(3<<12)|(3<<14)|(3<<22));//~(0b11);
        data |= (2|(2<<6)|(2<<10)|(2<<12)|(2<<14)|(2<<22));//0b10;
        writew(data,gpio_config);
    }
    
    /************************
    函数名:key_timer_func
    参数:无
    返回值:无
    函数功能:定时器超时处理函
    数,达到规定时间执行此函数
    *************************/
    void key_timer_func()
    {
        unsigned int key_val,i;
    
        for(i = 0;i < 15;i++)
        {
            if((i == 0)||(i == 3)||(i == 5)||(i == 6)||(i == 7)||(i == 11))
            {
                key_val = readw(gpio_data) & (1 << i);
                if(key_val == 0)
                    key_num = i+1;
            }
        }
        wake_up(&key_queue);
    }
    
    int key_open(struct inode *node, struct file *filp)
    {
        return 0; 
    }
    
    ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
    {
        wait_event(key_queue,key_num);
    
        copy_to_user(buf,&key_num,4);
    
        /*清空按键键值*/
        key_num = 0;
    
        return 4;
    }
    
    /* 函数映射关系表*/
    struct file_operations key_fops = 
    {
        .open = key_open,
        .read = key_read,
        //.unlocked_ioctl = key_ioctl,
    };
    
    /*字符设备描述结构*/
    struct miscdevice key_miscdev = 
    {
        .minor = 200,
        .name = "key",
        .fops = &key_fops,
    };
    
    static int button_init()
    {
        /*注册设备*/
        misc_register(&key_miscdev);
    
        /*硬件初始化*/
        key_hw_init();
        
        /*注册中断*/
        request_irq(IRQ_EINT8,key_int,IRQF_TRIGGER_FALLING ,"key",(void *) 0);
        request_irq(IRQ_EINT11,key_int,IRQF_TRIGGER_FALLING ,"key",(void *) 0);
        request_irq(IRQ_EINT13,key_int,IRQF_TRIGGER_FALLING ,"key",(void *) 0);
        request_irq(IRQ_EINT14,key_int,IRQF_TRIGGER_FALLING ,"key",(void *) 0);
        request_irq(IRQ_EINT15,key_int,IRQF_TRIGGER_FALLING ,"key",(void *) 0);
        request_irq(IRQ_EINT19,key_int,IRQF_TRIGGER_FALLING ,"key",(void *) 0);
    
        /*工作队列初始化*/
        que_init();
    
        /*初始化定时器*/
    
        init_timer(&key_timer);
    
        key_timer.function = key_timer_func;
    
        /*注册定时器*/
        add_timer(&key_timer);
    
        /*初始化等待队列*/
        init_waitqueue_head(&key_queue);
    
        printk("key.ko is ready
    ");
        return 0;
    }
    
    static void button_exit()
    {
        /*注销设备*/
        misc_deregister(&key_miscdev);
        /*注销中断*/
        free_irq(IRQ_EINT8, 0);
    }
    
    MODULE_LICENSE("GPL");
    module_init(button_init);
    module_exit(button_exit);

    应用程序:

      

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main()
    {
        int fd = 0,key_num;
    
        fd = open("/dev/mykey", O_RDWR);
    
        if(fd < 0)
            printf("open device fail!
    ");
    
        read(fd, &key_num, 4);
    
        printf("key num is %d
    ", key_num);
    
        close(fd);
      
      return 0;
    }

    此代码适用mini2440开发板,不同型号开发板IO口和中断号不同。如果有疑问或建议,欢迎指出。

  • 相关阅读:
    题解 UVA10213 【How Many Pieces of Land ?】
    NOIP 2018 游记
    POJ 1821 Fence(单调队列优化DP)
    HDU 2196 Computer(经典树形DP)
    POJ 2228 Naptime(DP+环形处理)
    POJ 1742 Coins(多重背包?)
    POJ 2311 Cutting Game(SG函数)
    BZOJ 2560(子集DP+容斥原理)
    HDU2841 Visible Trees(容斥原理)
    HDU 1796 How many integers can you find(容斥原理)
  • 原文地址:https://www.cnblogs.com/51qianrushi/p/4294662.html
Copyright © 2011-2022 走看看