• 嵌入式Linux驱动学习之路(十四)按键驱动-同步、互斥、阻塞


    目的:同一个时刻,只能有一个应用程序打开我们的驱动程序。

    ①原子操作:

    v = ATOMIC_INIT( i )   定义原子变量v并初始化为i

    atomic_read(v)        返回原子变量的值
    atomic_set(v,i)        设置原子变量的值      

    atomic_inc_and_test(v)     自加后和测试是否为0  为0则返回true

    atomic_dec_and_test(v)     自减后和测试是否为0  为0则返回true

    atomic_inc(v)      自加
    #atomic_dec(v)     自减

    驱动代码:

    #include <linux/sched.h>
    #include <linux/signal.h>
    #include <linux/spinlock.h>
    #include <linux/errno.h>
    #include <linux/random.h>
    #include <linux/poll.h>
    #include <linux/init.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/wait.h>
    #include <linux/mutex.h>
    #include <linux/io.h>
    #include <asm/irq.h>
    #include <linux/irq.h>
    #include <linux/fs.h>
    #include <asm/arch/regs-gpio.h>
    #include <linux/interrupt.h>
    #include <linux/poll.h>
    
    
    static struct class *key_class;     //创建类
    static struct class_device *key_class_devs;   //创建类对应的设备
    
    
    struct pin_desc{
        unsigned int pin;
        unsigned int key_val;
    };
    struct pin_desc pins_desc[4] = {
        {S3C2410_GPF0,0X01},
        {S3C2410_GPF2,0X02},
        {S3C2410_GPG3,0X03},
        {S3C2410_GPG11,0X04},
    };
    unsigned char keyvals=0;
    
    static volatile int ev_press = 0;
    static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
    
    static struct fasync_struct *key_async_queue;
    
    atomic_t canopen = ATOMIC_INIT(1); 
    
    static irqreturn_t keys_irq(int irq, void *dev_id)
    {
        struct pin_desc *pindesc = (struct pin_desc *)dev_id;
        unsigned int pinval;
        pinval = s3c2410_gpio_getpin(pindesc->pin);
        if(pinval)
        {
            keyvals = pindesc->key_val|0x80;
        }
        else
        {
            keyvals = pindesc->key_val;
        }
        ev_press = 1;
        wake_up_interruptible(&button_waitq);
    
        kill_fasync (&key_async_queue, SIGIO, POLL_IN);
    
        return IRQ_HANDLED;
    }
    
    
    int key_open(struct inode *inode, struct file *fp)
    {
        if(!atomic_dec_and_test(&canopen))  //if --canopen==0 return ture  /*自减后和0相比 如果等于0 则返回true*/
        {
            atomic_inc(&canopen);
            return -EBUSY;
        }
    
        request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]);
        request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]);
        request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]);
        request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]);
        return 0;
    }
    
    ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){
    
        if(count != 1)
        {
            return -EINVAL;
        }
        wait_event_interruptible(button_waitq,ev_press);
        
        copy_to_user(buff,&keyvals,1);
        ev_press = 0;
        return 0;
    }
    
    ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){
    }
    
    int key_close(struct inode *inode, struct file *file)
    {
        atomic_inc(&canopen);
        free_irq(IRQ_EINT0,&pins_desc[0]);
        free_irq(IRQ_EINT2,&pins_desc[1]);
        free_irq(IRQ_EINT11,&pins_desc[2]);
        free_irq(IRQ_EINT19,&pins_desc[3]);
    }
    
    static unsigned int key_poll(struct file *file, struct poll_table_struct *wait)
    {
        unsigned int mask = 0;
        poll_wait(file, &button_waitq,wait);
        if(ev_press)
            mask |= POLLIN|POLLRDNORM;
        return mask;
    }
    
    static int key_fsync (int fd, struct file *filp, int on)
    {
        printk("ok
    ");
        return fasync_helper (fd, filp, on, &key_async_queue);
    }
    
    struct file_operations led_fops={
        .owner = THIS_MODULE,
        .open = key_open,
        .write  = key_write,
        .read   = key_read,
        .release = key_close,
        .poll = key_poll,
        .fasync = key_fsync,
    };
    
    int major;
    static int key_init(void)
    {
        major = register_chrdev( 0,"key_drv", &led_fops );
        key_class = class_create(THIS_MODULE,"key_class");
        key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys");
        
        printk("key install Module
    ");
        return 0;
    }
    
    static void key_exit(void)
    {
        unregister_chrdev( major, "key_drv" );
        class_device_unregister(key_class_devs);
        class_destroy(key_class);
        printk("key Module exit
    ");
    }
    
    module_init(key_init);
    module_exit(key_exit);
    MODULE_LICENSE("GPL");

    信号量:

    #include <linux/sched.h>
    #include <linux/signal.h>
    #include <linux/spinlock.h>
    #include <linux/errno.h>
    #include <linux/random.h>
    #include <linux/poll.h>
    #include <linux/init.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/wait.h>
    #include <linux/mutex.h>
    #include <linux/io.h>
    #include <asm/irq.h>
    #include <linux/irq.h>
    #include <linux/fs.h>
    #include <asm/arch/regs-gpio.h>
    #include <linux/interrupt.h>
    #include <linux/poll.h>
    
    
    static struct class *key_class;     //创建类
    static struct class_device *key_class_devs;   //创建类对应的设备
    
    
    struct pin_desc{
        unsigned int pin;
        unsigned int key_val;
    };
    struct pin_desc pins_desc[4] = {
        {S3C2410_GPF0,0X01},
        {S3C2410_GPF2,0X02},
        {S3C2410_GPG3,0X03},
        {S3C2410_GPG11,0X04},
    };
    unsigned char keyvals=0;
    
    static volatile int ev_press = 0;
    static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
    
    static struct fasync_struct *key_async_queue;
    
    static DECLARE_MUTEX(canopen); //定义互斥锁
    
    static irqreturn_t keys_irq(int irq, void *dev_id)
    {
        struct pin_desc *pindesc = (struct pin_desc *)dev_id;
        unsigned int pinval;
        pinval = s3c2410_gpio_getpin(pindesc->pin);
        if(pinval)
        {
            keyvals = pindesc->key_val|0x80;
        }
        else
        {
            keyvals = pindesc->key_val;
        }
        ev_press = 1;
        wake_up_interruptible(&button_waitq);
    
        kill_fasync (&key_async_queue, SIGIO, POLL_IN);
    
        return IRQ_HANDLED;
    }
    
    
    int key_open(struct inode *inode, struct file *fp)
    {
        /*获取信号量*/
        down(&canopen);      //如果设备已经被打开,那么程序将会一直停在这里知道信号量被释放。
    
        request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]);
        request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]);
        request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]);
        request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]);
        return 0;
    }
    
    ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){
    
        if(count != 1)
        {
            return -EINVAL;
        }
        wait_event_interruptible(button_waitq,ev_press);
        
        copy_to_user(buff,&keyvals,1);
        ev_press = 0;
        return 0;
    }
    
    ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){
    }
    
    int key_close(struct inode *inode, struct file *file)
    {
        free_irq(IRQ_EINT0,&pins_desc[0]);
        free_irq(IRQ_EINT2,&pins_desc[1]);
        free_irq(IRQ_EINT11,&pins_desc[2]);
        free_irq(IRQ_EINT19,&pins_desc[3]);
        up(&canopen);
    }
    
    static unsigned int key_poll(struct file *file, struct poll_table_struct *wait)
    {
        unsigned int mask = 0;
        poll_wait(file, &button_waitq,wait);
        if(ev_press)
            mask |= POLLIN|POLLRDNORM;
        return mask;
    }
    
    static int key_fsync (int fd, struct file *filp, int on)
    {
        printk("ok
    ");
        return fasync_helper (fd, filp, on, &key_async_queue);
    }
    
    struct file_operations led_fops={
        .owner = THIS_MODULE,
        .open = key_open,
        .write  = key_write,
        .read   = key_read,
        .release = key_close,
        .poll = key_poll,
        .fasync = key_fsync,
    };
    
    int major;
    static int key_init(void)
    {
        major = register_chrdev( 0,"key_drv", &led_fops );
        key_class = class_create(THIS_MODULE,"key_class");
        key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys");
        
        printk("key install Module
    ");
        return 0;
    }
    
    static void key_exit(void)
    {
        unregister_chrdev( major, "key_drv" );
        class_device_unregister(key_class_devs);
        class_destroy(key_class);
        printk("key Module exit
    ");
    }
    
    
    
    module_init(key_init);
    module_exit(key_exit);
    MODULE_LICENSE("GPL");

    阻塞:分为阻塞和非阻塞

      如何分辨阻塞和非阻塞呢?则需要在打开设备文件的时候传入一个参数

    #include <linux/sched.h>
    #include <linux/signal.h>
    #include <linux/spinlock.h>
    #include <linux/errno.h>
    #include <linux/random.h>
    #include <linux/poll.h>
    #include <linux/init.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/wait.h>
    #include <linux/mutex.h>
    #include <linux/io.h>
    #include <asm/irq.h>
    #include <linux/irq.h>
    #include <linux/fs.h>
    #include <asm/arch/regs-gpio.h>
    #include <linux/interrupt.h>
    #include <linux/poll.h>
    
    
    static struct class *key_class;     //创建类
    static struct class_device *key_class_devs;   //创建类对应的设备
    
    
    struct pin_desc{
        unsigned int pin;
        unsigned int key_val;
    };
    struct pin_desc pins_desc[4] = {
        {S3C2410_GPF0,0X01},
        {S3C2410_GPF2,0X02},
        {S3C2410_GPG3,0X03},
        {S3C2410_GPG11,0X04},
    };
    unsigned char keyvals=0;
    
    static volatile int ev_press = 0;
    static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
    
    static struct fasync_struct *key_async_queue;
    
    static DECLARE_MUTEX(canopen); //定义互斥锁
    
    static irqreturn_t keys_irq(int irq, void *dev_id)
    {
        struct pin_desc *pindesc = (struct pin_desc *)dev_id;
        unsigned int pinval;
        pinval = s3c2410_gpio_getpin(pindesc->pin);
        if(pinval)
        {
            keyvals = pindesc->key_val|0x80;
        }
        else
        {
            keyvals = pindesc->key_val;
        }
        ev_press = 1;
        wake_up_interruptible(&button_waitq);
    
        kill_fasync (&key_async_queue, SIGIO, POLL_IN);
    
        return IRQ_HANDLED;
    }
    
    
    int key_open(struct inode *inode, struct file *fp)
    {
        /*获取信号量*/
        if( fp->f_flags & O_NONBLOCK )
        {
            if(down_trylock(&canopen))
                return -EBUSY;
        }
        else
        {
            down(&canopen);
        }
        request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]);
        request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]);
        request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]);
        request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]);
        return 0;
    }
    
    ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){
    
        if(fp->f_flags & O_NONBLOCK )
        {
            if(!ev_press)
                return -EAGAIN;
        }
        else
        {
            wait_event_interruptible(button_waitq,ev_press);
        }
        if(count != 1)
        {
            return -EINVAL;
        }
        
        copy_to_user(buff,&keyvals,1);
        ev_press = 0;
        return 0;
    }
    
    ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){
    }
    
    int key_close(struct inode *inode, struct file *file)
    {
        free_irq(IRQ_EINT0,&pins_desc[0]);
        free_irq(IRQ_EINT2,&pins_desc[1]);
        free_irq(IRQ_EINT11,&pins_desc[2]);
        free_irq(IRQ_EINT19,&pins_desc[3]);
        up(&canopen);
    }
    
    static unsigned int key_poll(struct file *file, struct poll_table_struct *wait)
    {
        unsigned int mask = 0;
        poll_wait(file, &button_waitq,wait);
        if(ev_press)
            mask |= POLLIN|POLLRDNORM;
        return mask;
    }
    
    static int key_fsync (int fd, struct file *filp, int on)
    {
        printk("ok
    ");
        return fasync_helper (fd, filp, on, &key_async_queue);
    }
    
    struct file_operations led_fops={
        .owner = THIS_MODULE,
        .open = key_open,
        .write  = key_write,
        .read   = key_read,
        .release = key_close,
        .poll = key_poll,
        .fasync = key_fsync,
    };
    
    int major;
    static int key_init(void)
    {
        major = register_chrdev( 0,"key_drv", &led_fops );
        key_class = class_create(THIS_MODULE,"key_class");
        key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys");
        
        printk("key install Module
    ");
        return 0;
    }
    
    static void key_exit(void)
    {
        unregister_chrdev( major, "key_drv" );
        class_device_unregister(key_class_devs);
        class_destroy(key_class);
        printk("key Module exit
    ");
    }
    
    
    
    module_init(key_init);
    module_exit(key_exit);
    MODULE_LICENSE("GPL");

    阻塞测试文件:

    #include <stdio.h>
    #include <signal.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int fd;
    
    static char key_val;
    int main( int argc, char **argv )
    {
        int oflags;
        fd = open("/dev/my_keys",O_RDWR|O_NONBLOCK);  /* O_NONBLOCK为非阻塞*/
       
        if(fd<0)
        {
            printf("open failed
    ");
            return 0;
        }
    
        while(1)
        {
            read(fd,&key_val,1);
            printf("key_val:%d
    ",key_val);
            sleep(1);
        }
    
    
        return 0;
    }

  • 相关阅读:
    Ant构建原理及build.xml文档描述
    Selenium WebDriver的工作原理
    appium工作原理
    jmeter获取mysql数据并作为请求参数使用
    linux sar的使用
    hdu 1520 Anniversary party
    hdu 1331 Function Run Fun
    hdu 1208 Pascal's Travels
    hdu 1159 Common Subsequence
    poj 1129 Channel Allocation
  • 原文地址:https://www.cnblogs.com/ynxf/p/6000644.html
Copyright © 2020-2023  润新知