单片机
返回首页

Samsung_tiny4412(驱动笔记07)----spinlock,semaphore,atomic,mutex,completion,interrupt

2025-01-15 来源:cnblogs

/***********************************************************************************

 *                    

 *               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)

 *               {   

 *                   ... //省略代码

 *               }  

 *               ... //省略代码

 *


 **********************************************************************************/


                        \\\\--*目录*--////////

                        |  一. 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 = %dn', 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 = %dn', 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.n');

        

            return 0;

        }

        

        static int test_close(struct inode *inode, struct file *file)

        {

            test_t *p = file->private_data;

        

            printk('Close.n');

            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 = %dn', 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 = %dn', 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.n');

        

        

            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.n');

            

            /*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 = %dn', 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('irqn', &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 = %dn', 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

    #include

    #include

    #include

    #include

    #include

    #include

    

    #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.n');

    }

    

    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 = %dn', 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

    #include

    #include

    #include

    #include

    

    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.n', i + 1);

            }

        }

    

        close(fd);

        return 0;

    }


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章