zoukankan      html  css  js  c++  java
  • Linux设备驱动开发基础--阻塞型设备驱动

    1. 当一个设备无法立刻满足用户的读写请求时(例如调用read时,设备没有数据提供),驱动程序应当(缺省的)阻塞进程,使它进入等待(睡眠)状态,知道请求可以得到满足。

    2. Linux内核等待队列:在实现阻塞驱动的过程中,需要有一个“候车室”来安排被阻塞的进程“休息”,当唤醒它们的条件成熟时,则可以从“候车室”中将这些进程唤醒。而这个“候车室”就是等待队列。

    3. Linux内核等待队列的使用

    (1)定义等待队列

    wait_queue_head_t my_queue;

    (2)初始化等待队列

    init_waitqueue_head(&my_queue);

    (3)定义+初始化等待队列

    DECLARE_WAIT_QUEUE_HEAD(my_queue)

    (4)使进程进入等待队列

    ① wait_event

    wait_event(queue, condition)

      当condition(布尔表达式)为真时,立即返回;否则让进程进入TASK_UNINTERRUPTIBLE模式的睡眠,并挂在queue参数所指定的等待队列上。

    ② wait_event_interruptible

    wait_event_interruptible(queue, condition)

      当condition(布尔表达式)为真时,立即返回;否则让进程进入TASK_INTERRUPTIBLE的睡眠,并挂在queue参数所指定的等待队列上。

    ③ wait_event_killable

    wait_event_killable(queue, condition)

      当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_KILLABLE的睡眠,并挂在queue参数所指定的等待队列上。

    (5)从等待队列中唤醒进程

     ① wake_up:

    wake_up(wait_queue_t *q)

      从等待队列q中唤醒状态为TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,TASK_KILLABLE 的所有进程。

     ② wake_up_interruptible

    wake_up_interruptible(wait_queue_t *q)

      从等待队列q中唤醒状态为TASK_INTERRUPTIBLE 的进程

    4. 简单示例

    #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>
    
    #define GPGCON 0x56000060
    #define GPGDAT 0x56000064
    
    unsigned int *gpio_config;
    
    struct timer_list buttons_timer;
    
    unsigned int key_num = 0;
    
    wait_queue_head_t  key_wait_queue;
    
    void keys_timer_function(unsigned long data)  
    {
        printk("keys_timer_function
    ");
        
        key_num = 0;
    
        printk("data = %lx
    ", data);
        
        switch(data)
        {
            case IRQ_EINT8:
                key_num = 1;
                break;
                
            case IRQ_EINT11:
                key_num = 2;
                break;
                
            case IRQ_EINT13:
                key_num = 3;
                break;    
            case IRQ_EINT14:
                key_num = 4;
                break;
            
            case IRQ_EINT15:
                key_num = 5;
                break;
            
            case IRQ_EINT19:
                key_num = 6;
                break;            
            
            default:
                break;
        }
    
        printk("key_num = %d
    ", key_num);
        
        wake_up(&key_wait_queue);
    } 
    
    irqreturn_t key_int(int irq, void *dev_id)
    {
        //1. 检测是否发生了按键中断
        
        //2. 清除已经发生的按键中断
        
        //3. 提交下半部
        buttons_timer.data = (unsigned long)irq;
        mod_timer(&buttons_timer, jiffies + (HZ / 10)); 
        
        //return 0;
        return IRQ_HANDLED;
    }
    
    void key_hw_init(void)
    { 
        unsigned int config_data;
        
        config_data = readl(gpio_config);
        config_data &= 0b00111100;
        config_data |= 0b10000010;
    
        printk("config_data = %x
    ", config_data);
        
        writel(config_data, gpio_config);
    }
    
    
    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_wait_queue, key_num);
        
        printk("in kernel: key num is %d
    ",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,    
    };
    
    struct miscdevice key_miscdev = {
        .minor = 200,
        .name = "key",
        .fops = &key_fops,    
    };
    
    static int button_init(void)
    {
        int ret;
        
        gpio_config = ioremap(GPGCON, 4);
        
        ret = misc_register(&key_miscdev);
        
        printk("ret = %d
    ", ret);
        
        if (ret == 0)
        {
            //按键初始化
            key_hw_init();
            
            //注册中断处理程序
            request_irq(IRQ_EINT8, key_int, IRQF_TRIGGER_LOW, "key1", 0);
            request_irq(IRQ_EINT11, key_int, IRQF_TRIGGER_LOW, "key2", 0);
            request_irq(IRQ_EINT13, key_int, IRQF_TRIGGER_LOW, "key3", 0);
            request_irq(IRQ_EINT14, key_int, IRQF_TRIGGER_LOW, "key4", 0);
            request_irq(IRQ_EINT15, key_int, IRQF_TRIGGER_LOW, "key5", 0);
            request_irq(IRQ_EINT19, key_int, IRQF_TRIGGER_LOW, "key6", 0);
            
            /* 初始化定时器 */  
            init_timer(&buttons_timer);   
            buttons_timer.function = keys_timer_function;  
            
            /* 向内核注册一个定时器 */  
            add_timer(&buttons_timer);  
            
            /* 初始化等待队列 */
            init_waitqueue_head(&key_wait_queue);
        }
        else
        {
            printk("register fail!
    ");
        }
        
        return ret;
    }
    
    static void button_exit(void)
    {    
        iounmap(gpio_config);
        
        free_irq(IRQ_EINT8, 0);
        free_irq(IRQ_EINT11, 0);
        free_irq(IRQ_EINT13, 0);
        free_irq(IRQ_EINT14, 0);
        free_irq(IRQ_EINT15, 0);
        free_irq(IRQ_EINT19, 0);
        
        misc_deregister(&key_miscdev);    
    }
    
    module_init(button_init);
    module_exit(button_exit);
  • 相关阅读:
    稳扎稳打Silverlight(47) 4.0UI之操作剪切板, 隐式样式, CompositeTransform, 拖放外部文件到程序中
    返璞归真 asp.net mvc (9) asp.net mvc 3.0 新特性之 View(Razor)
    返璞归真 asp.net mvc (6) asp.net mvc 2.0 新特性
    稳扎稳打Silverlight(48) 4.0其它之打印, 动态绑定, 增强的导航系统, 杂七杂八
    精进不休 .NET 4.0 (9) ADO.NET Entity Framework 4.1 之 Code First
    稳扎稳打Silverlight(42) 4.0控件之Viewbox, RichTextBox
    稳扎稳打Silverlight(53) 4.0通信之对WCF NetTcpBinding的支持, 在Socket通信中通过HTTP检索策略文件, HTTP请求中的ClientHttp和BrowserHttp
    稳扎稳打 Silverlight 4.0 系列文章索引
    稳扎稳打Silverlight(54) 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”
    返璞归真 asp.net mvc (8) asp.net mvc 3.0 新特性之 Model
  • 原文地址:https://www.cnblogs.com/wulei0630/p/9524633.html
Copyright © 2011-2022 走看看