zoukankan      html  css  js  c++  java
  • Samsung_tiny4412(驱动笔记07)----spinlock,semaphore,atomic,mutex,completion,interrupt

    /***********************************************************************************
     *                    
     *               spinlock,semaphore,atomic,mutex,completion,interrupt
     *
     *   声明:
     *       1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会
     *         不对齐,从而影响阅读.
     *       2. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因;
     *       3. 基于2中的原因,本文借鉴了python中的缩进代码风格进行代码的体现:
     *           1. 有些代码中的"..."代表省略了不影响阅读的代码;
     *           2. 如下代码缩进代表在一个函数内部的代码,至于在什么函数里,不影响阅读:
     *               ... //省略代码
     *               struct test_s {
     *               };
     *               ... //省略代码
     *
     *                   //进入临界区之前加锁     }
     *                   spin_lock(&p->lock);     | 
     *                                            |   |
     *                   /* 有效代码 */           |-->|采用缩进,代表在一个函数内
     *                                            |   |的代码
     *                   //出临界区之后解锁       |
     *                   spin_unlock(&p->lock);   }
     *
     *               ... //省略代码                                
     *               int __init test_init(void)
     *               {   
     *                   ... //省略代码
     *               }  
     *               ... //省略代码
     *
     *
     *                                          2015-3-13 阴 深圳 尚观 Var 曾剑锋
     **********************************************************************************/
    
                            \\\\--*目录*--////////
                            |  一. spinlock接口;     
                            |  二. semaphore接口;    
                            |  三. atomic接口;       
                            |  四. mutex接口;        
                            |  五. completion接口;   
                            |  六. interrupt接口;    
                            |  七. 按键驱动大致写法;
                            |  八. 测试按键驱动;     
                            \\\\\\//////////////
    
    
    一. spinlock接口:
        1. 声明:       spinlock_t lock;
        2. 初始化:     spin_lock_init(&test.lock);
        3. 获取自旋锁: spin_lock(&p->lock);
        4. 释放自旋锁: spin_unlock(&p->lock);
        5. spin_lock接口使用Demo:
            ...
            struct test_s {
                struct file_operations fops;
                spinlock_t lock;
                int major;
            };
            ...
                //进入临界区之前加锁
                spin_lock(&p->lock);
                for(i = 0; i < 3; i++)
                {
                    printk("count = %d, %s", cnt++, kbuf);
                    /*msleep(10);*/
                    mdelay(10);
                }
                //出临界区之后解锁
                spin_unlock(&p->lock);
            ...
            int __init test_init(void)
            {   
                int ret;
                // 初始化spin_lock   
                spin_lock_init(&test.lock);
            
                ret = register_chrdev(test.major,
                        DEV_NAME, &test.fops);
                if(ret > 0)
                {
                    test.major = ret;
                    printk("major = %d
    ", test.major);
                    ret = 0;
                }
            
                return ret;
            }  
            ...
    
    二. semaphore接口:
        1. 定义: struct semaphore sem;
        2. 定义一个信号量,并初始化: DEFINE_SEMAPHORE(name);
        3. 初始化: sema_init(&test.sem, 1);
        4. 3种获取信号量: 
            1. down(&p->sem);
            2. down_interruptible(&p->sem);
            3. down_trylock(&p->sem);
        5. 释放信号量: up(&p->sem);
        6. semaphore接口使用Demo:
            ...
            struct test_s {
                struct file_operations fops;
                /**
                 * spinlock_t lock;
                 * volatile int count;
                 */
                struct semaphore sem;
                int major;
            };
            ...
                /**
                 * spin_lock(&p->lock);
                 * if(p->count <= 0)
                 * {
                 *     spin_unlock(&p->lock);
                 *     return -EAGAIN;
                 * }
                 * p->count--;
                 * spin_unlock(&p->lock);
                 */
            
                //加不了锁,睡眠等待
                /*down(&p->sem);*/
            
                if(down_trylock(&p->sem))
                    return -EAGAIN;
            
                for(i = 0; i < 3; i++)
                {
                    printk("count = %d, %s", cnt++, kbuf);
                    msleep(10);
                }
            
                up(&p->sem);
            
                /**
                 * spin_lock(&p->lock);
                 * p->count++;
                 * spin_unlock(&p->lock);
                 */
            ...
            int __init test_init(void)
            {
                int ret;
            
                /**
                 * spin_lock_init(&test.lock);
                 * test.count = 1;
                 */
            
                sema_init(&test.sem, 1);
            
                ret = register_chrdev(test.major,
                        DEV_NAME, &test.fops);
                if(ret > 0)
                {
                    test.major = ret;
                    printk("major = %d
    ", test.major);
                    ret = 0;
                }
            
                return ret;
            }
            ...
    
    三. atomic接口:
        1. 头文件:   linux-3.5/include/linux/atomic.h
        2. 声明定义: atomic_t val; atomic_t *v = &val;
        3. 读取原子变量的值:   atomic_read(v);
        4. 修改原子变量的值:   atomic_set(v, i);
        5. 原子变量自加1:      atomic_inc(v); --> v += 1;
        6. 原子变量自减1:      atomic_dec(v); --> v -= 1;
        7. 原子变量自加1并检测是否为0:       atomic_inc_and_test(v); v += 1,判断结果是否为0
        8. 原子变量自减1并检测是否为0:       atomic_dec_and_test(v); v -= 1,判断结果是否为0
        9. 原子变量自加1并返回原子变量的值:  atomic_inc_return(v)
        10. 原子变量自减1并返回原子变量的值: atomic_dec_return(v)
        11. 比较变量i和原子变量的值是否相等: atomic_sub_and_test(i, v)
        12. atomic接口使用Demo:
            ...
            struct test_s {
                struct file_operations fops;
                atomic_t v;
                int major;
            };
            typedef struct test_s test_t;
            
            static int test_open(struct inode *inode, struct file *file)
            {
                test_t *p;
                p = container_of(file->f_op, test_t, fops);
            
                file->private_data = p;
            
                if(!atomic_dec_and_test(&p->v))
                {
                    atomic_inc(&p->v);
                    return -EAGAIN;
                }
            
                printk("Open.
    ");
            
                return 0;
            }
            
            static int test_close(struct inode *inode, struct file *file)
            {
                test_t *p = file->private_data;
            
                printk("Close.
    ");
                atomic_inc(&p->v);
            
                return 0;
            }
            ...
            int __init test_init(void)
            {
                int ret;
            
                atomic_set(&test.v, 1);
            
                ret = register_chrdev(test.major,
                        DEV_NAME, &test.fops);
                if(ret > 0)
                {
                    test.major = ret;
                    printk("major = %d
    ", test.major);
                    ret = 0;
                }
            
                return ret;
            }
            ...
    
    四. mutex接口:
        1. 定义: struct mutex lock;
        2. 定义一个互斥锁,并初始化: DEFINE_MUTEX(mutexname);
        3. 初始化: mutex_init(&lock);
        4. 3种加锁方式:
            1. mutex_lock(&lock);
            2. mutex_lock_interruptible(&lock);
            3. mutex_trylock(&lock);
        5. 解锁: mutex_unlock(&lock);
        6. mutex接口使用Demo:
            ...
            struct test_s {
                struct file_operations fops;
                /*struct semaphore sem;*/
                struct mutex lock;
                int major;
            };
            typedef struct test_s test_t;
            ...
                /*mutex_lock(&p->lock);*/
            
                /*
                 *if(mutex_lock_interruptible(&p->lock))
                 *    return -EINTR;
                 */
            
                if(!mutex_trylock(&p->lock))
                    return -EAGAIN;
            
                for(i = 0; i < 3; i++)
                {
                    printk("count = %d, %s", cnt++, kbuf);
                    msleep(10);
                }
            
                mutex_unlock(&p->lock);
            ...
            int __init test_init(void)
            {
                int ret;
            
                mutex_init(&test.lock);
            
                ret = register_chrdev(test.major, DEV_NAME, &test.fops);
                if(ret > 0)
                {
                    test.major = ret;
                    printk("major = %d
    ", test.major);
                    ret = 0;
                }
            
                return ret;
            }
    
    五. completion接口:
        1. 定义: struct completion com;
        2. 定义一个完成量,并初始化: DECLARE_COMPLETION(work)
        3. 初始化: init_completion(&com);
        4. 2种等待完成: 
            1. wait_for_completion(&com);
            2. wait_for_completion_interruptible(&com);
        5. 2种通知完成量:
            1. complete(&com);
            2. complete_all(&com);
        6. mutex接口使用Demo:
            ...
            struct test_s {
                struct file_operations fops;
                struct completion com;
                int major;
            };
            typedef struct test_s test_t;
            ...
            static ssize_t test_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
            {
                test_t *p = file->private_data;
                
                //在完成量com上阻塞
                /*wait_for_completion(&p->com);*/
            
                if(wait_for_completion_interruptible(&p->com))
                    return -ERESTARTSYS;
                    
                printk("Read data.
    ");
            
            
                return count;
            }
            
            static ssize_t test_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
            {
                test_t *p = file->private_data;
                
                printk("Write data.
    ");
                
                /*complete(&p->com);*/
                
                //通知所有阻塞的进程
                complete_all(&p->com);
                
                return count;
            }  
            ...
            int __init test_init(void)
            {
                int ret;
            
                init_completion(&test.com);
                ret = register_chrdev(test.major,
                                      DEV_NAME, &test.fops);
                if(ret > 0)
                {
                    test.major = ret;
                    printk("major = %d
    ", test.major);
                    ret = 0;
                }
            
                return ret;
            }
            ...
    六. interrupt接口:
        1. 查看系统中断处理信息: cat /proc/interrupts
        2. 申请并注册中断处理函数:
            static inline int __must_check request_irq( unsigned int irq, irq_handler_t handler,
                                          unsigned long flags, const char *name, void *dev_data);
        3. 释放中断,并取消中断处理函数:
            void free_irq(unsigned int irq, void *dev_data);
        4. 代码执行环境:
            1. 中断上下文:         in_interrupt(); ---> 判断执行环境是否是中断上下文
                1. 软中断上下文:   in_softirq();   ---> 判断执行环境是否是soft irq
                2. 外部中断上下文: in_irq();       ---> 判断执行环境是否是硬件中断处理环境
            2. 进程上下文.
        5. 共享中断方法:
            1. request_irq()指定共享标志 IRQF_SHARED;
            2. request_irq()最后一个参数不能传递NULL,传递当前驱动全局变量地址;
        6. 将系统gpio编号转换成对应的外部中断: gpio_to_irq();
        7. spinlock中断中使用Demo:
            ...
            struct test_s {
                struct file_operations fops;
                spinlock_t lock;
                int major;
            };
            typedef struct test_s test_t;
            ...
            int critical(const char *s, spinlock_t *lock)
            {
                int i;
                unsigned long flag;
                static int cnt = 0;
            
                /*spin_lock(lock);*/
                /*local_irq_disable();*/
                /*local_irq_save(flag);*/
                /*spin_lock_irq(lock);*/
                spin_lock_irqsave(lock, flag);
            
                for(i = 0; i < 3; i++)
                {
                    printk("count = %d, %s", cnt++, s);
                    mdelay(1000);
                }
            
                spin_unlock_irqrestore(lock, flag);
                /*spin_unlock_irq(lock);*/
                /*local_irq_restore(flag);*/
                /*local_irq_enable();*/
                /*spin_unlock(lock);*/
            
                return 0;
            }
            
            static irqreturn_t irq_handler(int irq, void *arg)
            {
                test_t *p = arg;
            
                critical("irq
    ", &p->lock);
            
                return IRQ_HANDLED;
            }
            
            static ssize_t test_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
            {
                int ret;
                char kbuf[count + 1];
                test_t *p = file->private_data;
            
                ret = copy_from_user(kbuf, buf, count);
                if(ret)
                    return -EFAULT;
                kbuf[count] = '';
            
                if(critical(kbuf, &p->lock))
                    return -EAGAIN;
            
                return count;
            }
            ...
            int __init test_init(void)
            {
                int ret;
            
                spin_lock_init(&test.lock);
            
                ret = register_chrdev(test.major,
                        DEV_NAME, &test.fops);
                if(ret > 0)
                {
                    test.major = ret;
                    printk("major = %d
    ", test.major);
                    ret = 0;
                }
            
                ret = request_irq(IRQ_EINT(26), irq_handler,
                                  IRQF_TRIGGER_FALLING,
                                  "key1", &test);
                if(ret)
                    unregister_chrdev(test.major, DEV_NAME);
            
                return ret;
            }
            ...
    
    七. 按键驱动大致写法:
        #include <linux/module.h>
        #include <linux/fs.h>
        #include <linux/gpio.h>
        #include <linux/delay.h>
        #include <linux/interrupt.h>
        #include <linux/uaccess.h>
        #include <linux/sched.h>
        
        #define DEV_NAME    "test"
        
        struct timer_list timer;
        struct btn_desc {
            int gpio;
            int num;
            char *name;
        };
        
        int ev_key = 0;
        char key_state[] = {0, 0, 0, 0};
        DECLARE_WAIT_QUEUE_HEAD(wq);
        
        struct btn_desc btn[] = {
            { EXYNOS4_GPX3(2), 0, "key1" },
            { EXYNOS4_GPX3(3), 1, "key2" },
            { EXYNOS4_GPX3(4), 2, "key3" },
            { EXYNOS4_GPX3(5), 3, "key4" }
        };
        
        void timer_main(unsigned long data)
        {
            ev_key = 1;
            wake_up_interruptible(&wq);
            printk("timer_main.
    ");
        }
        
        static irqreturn_t irq_handler(int irq, void *arg)
        {
            struct btn_desc *key = arg;
        
            key_state[key->num] = 1;
        
            mod_timer(&timer, jiffies + 20);
        
            return IRQ_HANDLED;
        }
        
        static int test_open(struct inode *inode, struct file *file)
        {
            int i, irq, ret;
        
            for(i = 0; i < ARRAY_SIZE(btn); i++)
            {
                //irq = IRQ_EINT(26+i); //irq可以通过这种方法获得
                irq = gpio_to_irq(btn[i].gpio);
                ret = request_irq(irq, irq_handler, IRQF_TRIGGER_FALLING | IRQF_SHARED,
                            btn[i].name, &btn[i]);
                if(ret)
                    break;
            }
        
            if(ret)
            {
                for(--i; i >= 0; i--)
                {
                    irq = gpio_to_irq(btn[i].gpio);
                    free_irq(irq, &btn[i]);
                }
                return ret;
            }
        
            return 0;
        }
        
        static int test_close(struct inode *inode, struct file *file)
        {
            int i, irq;
        
            for(i = 0; i < ARRAY_SIZE(btn); i++)
            {
                irq = gpio_to_irq(btn[i].gpio);
                free_irq(irq, &btn[i]);
            }
        
            return 0;
        }
        
        static ssize_t test_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
        {
            int ret;
        
            if(count > ARRAY_SIZE(key_state))
                count = ARRAY_SIZE(key_state);
        
            while(!ev_key)
            {
                if(file->f_flags & O_NONBLOCK)
                    return -EAGAIN;
        
                if(wait_event_interruptible(wq, ev_key))
                    return -ERESTARTSYS;
            }
        
            ret = copy_to_user(buf, key_state, count);
            if(ret)
                return -EFAULT;
        
            memset(key_state, 0, sizeof(key_state));
            ev_key = 0;
        
            return count;
        }
        
        static struct file_operations fops = {
            .owner      = THIS_MODULE,
            .open       = test_open,
            .release    = test_close,
            .read       = test_read,
        };
        
        int major;
        int __init test_init(void)
        {
            int ret;
        
            setup_timer(&timer, timer_main, 11223344);
            ret = register_chrdev(major,
                                  DEV_NAME, &fops);
            if(ret > 0)
            {
                major = ret;
                printk("major = %d
    ", major);
                ret = 0;
            }
        
            return ret;
        }
        
        void __exit test_exit(void)
        {
            del_timer_sync(&timer);
            unregister_chrdev(major, DEV_NAME);
        }
        
        module_init(test_init);
        module_exit(test_exit);
        
        MODULE_LICENSE("GPL");
    
    八. 测试按键驱动:
        #include <stdio.h>
        #include <string.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <fcntl.h>
        
        int main(int argc, char **argv)
        {
            int fd, i, ret;
            char buf[4];
        
            fd = open(argv[1], O_RDWR);
            if(-1 == fd)
            {
                perror("open");
                exit(1);
            }
        
            while(1)
            {
                ret = read(fd, buf, sizeof(buf));
                if(4 != ret)
                    continue;
        
                for(i = 0; i < sizeof(buf); i++)
                {
                    if(buf[i] == 1)
                        printf("key%d down.
    ", i + 1);
                }
            }
        
            close(fd);
            return 0;
        }
  • 相关阅读:
    2020 7 13 每日随笔
    2020 7 10 每日总结
    2020 7 14 每日总结
    2020 7 16 每日总结
    2020 7 15 每日总结
    2020 7 19 每日总结
    2020 7 18 每日总结
    2020 7 17 每日总结
    2020 7 11
    2020 7 12
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4336005.html
Copyright © 2011-2022 走看看