• 阻塞型驱动设计


    一、
      当应用程序要对某个资源进行访问的时候,如果这个资源没有或者说被占用,这个应用程序就要进入阻塞状态,在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口和中断号不同。如果有疑问或建议,欢迎指出。

  • 相关阅读:
    js string format All In One
    CSS water wave effect All In One
    Github PR 时合并多次提交的 git commits All In One
    js auto selector dom by providing id All In One
    JSS All In One
    python 中将fastq文件保存为字典
    python 中统计fasta文件中每条序列的长度
    c语言中利用do while循环语句限制用户的输入范围
    python中记录程序运行时间
    c语言中的do while循环语句
  • 原文地址:https://www.cnblogs.com/51qianrushi/p/4294662.html
Copyright © 2020-2023  润新知